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);
}
我一直在学习一些 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);
}