OpenGL MVP 矩阵计算错误

OpenGL MVP matrix miscalculation

我一直在学习一些 OpenGL 教程,但我的 MVP 矩阵计算似乎没有按预期进行。我怀疑我在某个函数的某个地方犯了错误,但我似乎无法查明它。帮助将不胜感激,因为我仍然是 3D 矩阵转换领域的初学者。

我在 MVP 计算中使用的函数:

float ToRadians(float Degrees)
{
    float Result = Degrees * (PI32 / 180.0f);

    return (Result);
}

mat4 Rotate(float Angle, vec3 Axis)
{
    // Creates an identity matrix
    mat4 Result = Mat4d(1.0f);

    float SinTheta = sinf(ToRadians(Angle));
    float CosTheta = cosf(ToRadians(Angle));

    Result.Elements[0][0] = (Axis.X * Axis.X * (1.0f - CosTheta)) + CosTheta;
    Result.Elements[0][1] = (Axis.X * Axis.Y * (1.0f - CosTheta)) - (Axis.Z * SinTheta);
    Result.Elements[0][2] = (Axis.X * Axis.Z * (1.0f - CosTheta)) + (Axis.Y * SinTheta);

    Result.Elements[1][0] = (Axis.Y * Axis.X * (1.0f - CosTheta)) + (Axis.Z * SinTheta);
    Result.Elements[1][1] = (Axis.Y * Axis.Y * (1.0f - CosTheta)) + CosTheta;
    Result.Elements[1][2] = (Axis.Y * Axis.Z * (1.0f - CosTheta)) - (Axis.X * SinTheta);

    Result.Elements[2][0] = (Axis.Z * Axis.X * (1.0f - CosTheta)) - (Axis.Y * SinTheta);
    Result.Elements[2][1] = (Axis.Z * Axis.Y * (1.0f - CosTheta)) + (Axis.X * SinTheta);
    Result.Elements[2][2] = (Axis.Z * Axis.Z * (1.0f - CosTheta)) + CosTheta;

    return (Result);
}

mat4 Translate(vec3 Translation)
{
    mat4 Result = Mat4d(1.0f);

    Result.Elements[3][0] = Translation.X;
    Result.Elements[3][1] = Translation.Y;
    Result.Elements[3][2] = Translation.Z;

    return (Result);
}

mat4 Perspective(float FOV, float AspectRatio, float Near, float Far)
{
    mat4 Result = Mat4d(1.0f);

    float TanThetaOver2 = tanf(FOV * (PI32 / 360.0f));

    Result.Elements[0][0] = 1.0f / TanThetaOver2;
    Result.Elements[1][1] = AspectRatio / TanThetaOver2;
    Result.Elements[2][3] = -1.0f;
    Result.Elements[2][2] = (Near + Far) / (Near - Far);
    Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far);
    Result.Elements[3][3] = 0.0f;

    return (Result);
}

我正文的相关栏目:

//  Model matrix
mat4 MatModel = Rotate(-45.0f, Vec3(1.0f, 0.0f, 0.0f));
//  View matrix
mat4 MatView = Translate(Vec3(0.0f, 0.0f, -3.0f));
//  Projection matrix
mat4 MatProjection = Perspective(45.0f,
                                 (GLfloat) 1024 / (GLfloat) 768,
                                 0.1f, 100.0f);

GLuint LocModel = glGetUniformLocation(ShaderProgramID, "Model");
GLuint LocView = glGetUniformLocation(ShaderProgramID, "View");
GLuint LocProjection = glGetUniformLocation(ShaderProgramID, "Projection");

glUniformMatrix4fv(LocModel, 1, GL_TRUE, (GLfloat*) MatModel.Elements);
glUniformMatrix4fv(LocView, 1, GL_TRUE, (GLfloat*) MatView.Elements);
glUniformMatrix4fv(LocProjection, 1, GL_TRUE, (GLfloat*) MatProjection.Elements);

//  Bind VAO and draw from EBO
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);

这是我的顶点着色器:

#version 330 core

layout (location = 0) in vec3 Position;
layout (location = 1) in vec2 CTexCoord;

out vec2 STexCoord;

uniform mat4 Model;
uniform mat4 View;
uniform mat4 Projection;

void main()
{
    gl_Position = Projection * View * Model * vec4(Position, 1.0f);
    STexCoord = CTexCoord;
}

在着色器中,没有 Projection 和 View 矩阵,旋转似乎很顺利,但是当添加 View 矩阵时,情况看起来很奇怪。添加投影矩阵后,不会渲染任何内容。

对比图片:

Model / rotation matrix only applied

Model / rotation and View / translation matrices applied (does this look normal?)

应用了完整的 MVP 矩阵后,除了背景之外什么都没有显示。 (抱歉,现在不能 post 超过 2 个链接...)

提前致谢! :)

您对 glUniformMatrix 的调用集转置为 GL_TRUE,这意味着矩阵是行优先的。这意味着 OpenGL 期望矩阵每一行中的元素在内存中相邻。您正在像这样在视图矩阵中设置翻译元素:

Result.Elements[3][0] = Translation.X;
Result.Elements[3][1] = Translation.Y;
Result.Elements[3][2] = Translation.Z;

由于您告诉 OpenGL 您的矩阵是行优先的,这意味着 Elements 中的第一个下标是行,而 Elements 中的最后一个下标是列。这意味着您将第 4 列中的第 1 列到第 3 列设置为翻译。这将影响 gl_Position 的 w 分量,你会感到奇怪。我可以看到您对投影矩阵犯了同样的错误。基于此,我假设您将 mat4 设为列优先。如果是这种情况,我建议将 glUniformMatrix 中的转置参数更改为 GL_FALSE。如果不是,你应该在翻译和投影建筑中交换 row/column:

mat4 Translate(vec3 Translation)
{
   mat4 Result = Mat4d(1.0f);

   Result.Elements[0][3] = Translation.X;
   Result.Elements[1][3] = Translation.Y;
   Result.Elements[2][3] = Translation.Z;

   return (Result);
}