Handmade Network»Forums
Roman
25 posts
ups
basis vectors (rotation)
Edited by Roman on Reason: Initial post
Hello. I want to my character object facing where I am looking in 3D space.(character is just a box). So I am using basis vectors(right, up, forward) to construct matrix and then multiply that with the model matrix. But everything works except when the character rotates it also stretches(like a water). What I did wrong?
Code for rotation object
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
   model = scale(model, hero->size);
    
    v3 up = v3(0.0f,1.0f,0.0f);
    v3 right = normalize(cross(gameState->cameraFront,up));
    
    mat4 M = 
    {
        {
            {right.x,up.x,gameState->cameraFront.x,0.0f},
            {right.y,up.y,gameState->cameraFront.y,0.0f},
            {right.z,up.z,gameState->cameraFront.z,0.0f},
            {0.0f,0.0f,0.0f,1.0f}
        }
    };
    model = M * model;
    
    
    model = translate(model, hero->p);
    
    passUniformMatrix(opengl.shaderProgram,model,false,"model");
    glDrawArrays(GL_TRIANGLES, 0, 36);

Code for camera transforming
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void 
cameraTransform(Camera *camera, Input *input, Game_state *gameState)
{
    beginUseProgram(opengl.shaderProgram);
    if(camera->firstMouseMove)
    {
        camera->lastMouseX = input->mouseX;
        camera->lastMouseY = input->mouseY;
        
        camera->firstMouseMove = false;
    }
    
    s32 dtMouseX = input->mouseX - camera->lastMouseX;
    s32 dtMouseY = camera->lastMouseY - input->mouseY;
    
    dtMouseX *= camera->mouseSensitivity;
    dtMouseY *= camera->mouseSensitivity;
    
    camera->yaw += dtMouseX;
    camera->pitch += dtMouseY;
    
    if(camera->pitch > 89.0f)
    {
        camera->pitch  = 89.0f;
    }
    if(camera->pitch < -89.0f)
    {
        camera->pitch = -89.0f;
    }
    
    gameState->cameraFront.x = cos(ToRadians(camera->yaw)) * cos(ToRadians(camera->pitch));
    gameState->cameraFront.y = sin(ToRadians(camera->pitch));
    gameState->cameraFront.z = sin(ToRadians(camera->yaw)) * cos(ToRadians(camera->pitch));
    
    gameState->cameraFront = normalize(gameState->cameraFront);
    
    mat4 viewMatrix = indentity();
    viewMatrix = lookAt(gameState->cameraP,
                        gameState->cameraP + gameState->cameraFront,
                        v3(0.0f,1.0f,0.0f));
    
    
    passUniformMatrix(opengl.shaderProgram,viewMatrix,false,"view");
    
    camera->lastMouseX = WINDOW_WIDTH / 2;
    camera->lastMouseY = WINDOW_HEIGHT/ 2;
    
    endUseProgram(opengl.shaderProgram);
}

Thanks in advance.
Simon Anciaux
1337 posts
basis vectors (rotation)
Are cameraFront and up guaranteed to be perpendicular (in other words, is cameraFront parallel to the ground since up is strait up) ?

If not, you need to recompute up after computing right by doing another cross product between cameraFront and right (the 3 axis of the matrix need to be perpendicular otherwise the object will be deformed).

But I'm not "fluent" with matrix transformations so maybe it's not that.
Oliver Marsh
193 posts / 1 project
Olster1.github.io
basis vectors (rotation)
Just wondering what the matrix multiplication function looks like?
Roman
25 posts
ups
basis vectors (rotation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
mat4 
operator*(mat4 a, mat4 b)
{
    mat4 result = {};
    
    for(s32 r = 0; r < 4; r++)
    {
        for(s32 c = 0; c < 4; c++)
        {
            for(s32 i = 0; i < 4; i++)
            {
                result.e[r][c] += a.e[r][i] * b.e[i][c];
            }
        }
    }
    return result;
}

Oliver Marsh
193 posts / 1 project
Olster1.github.io
basis vectors (rotation)
Edited by Oliver Marsh on
Hi Roman,

I'm a bit rusty on matrix's, but one thing I did notice is the layout of the matrix - the basis vectors are laid out in column-major order that is

1
2
3
4
5
6
Matrix4 result = {{
            xAxis.x, yAxis.x, zAxis.x, 0,
            xAxis.y, yAxis.y, zAxis.y, 0,
            xAxis.z, yAxis.z, zAxis.z, 0,
            0, 0, 0, 1
        }};


instead of

1
2
3
4
5
6
Matrix4 result = {{
            xAxis.x, xAxis.y, xAxis.z, 0,
            yAxis.x, yAxis.y, yAxis.z, 0,
            zAxis.x, zAxis.y, zAxis.z, 0,
            0, 0, 0, 1
        }};


Not that that's a problem as your matrix multiplication function takes this into account, but OpenGL expects matrixes to be in the second format I believe. Not sure if this is the problem, but you could try transposing the final matrix before you send it to OpenGL.
Mārtiņš Možeiko
2559 posts / 2 projects
basis vectors (rotation)
Edited by Mārtiņš Možeiko on
Unless you are talking about ancient fixed-functionality-pipeline in OpenGL 1.x, then OpenGL (same as D3D) does not care about which layout your matrix uses. You can use either layout, all you need is just correctly write out math in your shader (m * v) vs (v * m) or use GLSL layout qualifiers - like layout(row_major) vs layout(column_major).
Oliver Marsh
193 posts / 1 project
Olster1.github.io
basis vectors (rotation)
Oh yea, was thinking if you use the matrices as the same way as math P * V * M instead of the other way.
Mārtiņš Možeiko
2559 posts / 2 projects
basis vectors (rotation)
Edited by Mārtiņš Možeiko on
With matrices it works the same way (vector is just the 1x4 matrix). You do either P*V*M or you do M*V*P - result will be the same for both storage formats. It works because of following basic property of matrix multiplication: https://en.wikipedia.org/wiki/Matrix_multiplication#Transpose

Oliver Marsh
193 posts / 1 project
Olster1.github.io
basis vectors (rotation)
Edited by Oliver Marsh on
Does that mean you don't have to worry about the ordering in the shader or
1
P*V*M*Vertex
will work with the row-major layout (M, then V, then P) & column-major will work with
1
M*V*P*Vertex
(P first, then V, then M)? That is a neat way of doing things.
Mārtiņš Možeiko
2559 posts / 2 projects
basis vectors (rotation)
Edited by Mārtiņš Možeiko on
Almost correct. Vertex also needs to be on correct side, just like other matrices.

You do "P * V * M * vertex" for column major.
Or "vertex * M * V * P" for row major.

But order of multiplication you do first does not really matter. As "((vertex * M) * V) * P" is same as "vertex * ((M * V) * P)" or even as "(vertex * M) * (V * P)".
https://en.wikipedia.org/wiki/Matrix_multiplication#Associativity
Oliver Marsh
193 posts / 1 project
Olster1.github.io
basis vectors (rotation)
Thanks Martin 😊