Search code examples
c++matrixopengl3dprojection-matrix

Perspective projection turns cube into weird tv shaped cuboid


This is my perspective projection matrix code

inline m4
Projection(float WidthOverHeight, float FOV)
{
    float Near = 1.0f;
    float Far = 100.0f;

    float f = 1.0f/(float)tan(DegToRad(FOV / 2.0f));
    float fn = 1.0f / (Near - Far);


    float a = f / WidthOverHeight;
    float b = f;
    float c = Far * fn;
    float d = Near * Far * fn;

    m4 Result = 
    {
        {{a, 0, 0, 0},
         {0, b, 0, 0},
         {0, 0, c, -1},
         {0, 0, d, 0}}
    };
    return Result;
}

And here is the main code

    m4 Project = Projection(ar, 90);
    m4 Move = {};
    CreateMat4(&Move,
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, -2,
        0, 0, 0, 1);
    m4 Rotate = Rotation(Scale);
    Scale += 0.01f;

    m4 FinalTransformation = Project * Move * Rotate;
    SetShaderUniformMat4("Project", FinalTransformation, ShaderProgram);

Here are some pictures of the cube rotating. In the shader code I just multiply the transformation by the position (with the transformation being on the left).

I am not sure if it's helpful but here is the rotation code:

float c = cos(Angle);
float s = sin(Angle);
m4 R =
{
    {{ c, 0, s, 0},
     { 0, 1, 0, 0},
     {-s, 0, c, 0},
     { 0, 0, 0, 1}}
};
return R;

I tried multiplying the matricies in the shader code instead of on the c++ side but then everything disappeared.


Solution

  • OpenGL matrixes are stored with column major order. You have to read the columns from left to right. For example the 1st column of the matrix R is { c, 0, s, 0}, the 2nd one is { 0, 1, 0, 0} the 3rd is {-s, 0, c, 0} and the 4th is { 0, 0, 0, 1}. The lines in your code are actually columns (not rows).
    Therefore you need to to transpose you projection matrix (Project) and translation matrix (Move).