现代 OpenGL 多维数据集旋转未按预期工作

Modern OpenGL cube rotation not working as expected

本文关键字:工作 旋转 OpenGL 数据集 现代      更新时间:2023-10-16

我正在尝试围绕轴旋转立方体,但它的行为肯定不正确。我假设问题出在我的矩阵旋转代码上,因为其他一切似乎都在工作。我可以沿 x、y 或 z 轴以及比例正确平移模型。我的相机视图矩阵也按预期工作,我的投影矩阵也是如此。如果我删除视图矩阵和/或投影矩阵实现,问题仍然存在。

如果你想看看我得到的结果,它与这个堆栈溢出帖子中显示的 gif 完全相同的输出:在现代 opengl 中旋转立方体......看起来很奇怪 立方体在旋转时似乎自行折叠,然后在完全旋转后恢复正常,并且似乎可以正常旋转约 20 度,直到再次折叠并重复。我的问题与链接到文章中的问题相同,但是我的矩阵类不同,所以我的问题虽然相同,但似乎有不同的解决方案。

这是我与可能相关的运算符的剥离矩阵声明

数学.h

typedef struct matrix4x4
{
//Elements stored in ROW MAJOR ORDER
GLfloat matrix[16];
void translate(Vector3f translation);
void rotateX(GLfloat angle);
void rotateY(GLfloat angle);
void rotateZ(GLfloat angle);
void rotate(Vector3f angles);
void scale(Vector3f scales);
void scale(GLfloat scale);
inline matrix4x4& operator*=(const matrix4x4& rhs)
{
this->matrix[0] = this->matrix[0] * rhs.matrix[0] + this->matrix[1] * rhs.matrix[4] + this->matrix[2] * rhs.matrix[8] + this->matrix[3] * rhs.matrix[12];
this->matrix[1] = this->matrix[0] * rhs.matrix[1] + this->matrix[1] * rhs.matrix[5] + this->matrix[2] * rhs.matrix[9] + this->matrix[3] * rhs.matrix[13];
this->matrix[2] = this->matrix[0] * rhs.matrix[2] + this->matrix[1] * rhs.matrix[6] + this->matrix[2] * rhs.matrix[10] + this->matrix[3] * rhs.matrix[14];
this->matrix[3] = this->matrix[0] * rhs.matrix[3] + this->matrix[1] * rhs.matrix[7] + this->matrix[2] * rhs.matrix[11] + this->matrix[3] * rhs.matrix[15];
this->matrix[4] = this->matrix[4] * rhs.matrix[0] + this->matrix[5] * rhs.matrix[4] + this->matrix[6] * rhs.matrix[8] + this->matrix[7] * rhs.matrix[12];
this->matrix[5] = this->matrix[4] * rhs.matrix[1] + this->matrix[5] * rhs.matrix[5] + this->matrix[6] * rhs.matrix[9] + this->matrix[7] * rhs.matrix[13];
this->matrix[6] = this->matrix[4] * rhs.matrix[2] + this->matrix[5] * rhs.matrix[6] + this->matrix[6] * rhs.matrix[10] + this->matrix[7] * rhs.matrix[14];
this->matrix[7] = this->matrix[4] * rhs.matrix[3] + this->matrix[5] * rhs.matrix[7] + this->matrix[6] * rhs.matrix[11] + this->matrix[7] * rhs.matrix[15];
this->matrix[8] = this->matrix[8] * rhs.matrix[0] + this->matrix[9] * rhs.matrix[4] + this->matrix[10] * rhs.matrix[8] + this->matrix[11] * rhs.matrix[12];
this->matrix[9] = this->matrix[8] * rhs.matrix[1] + this->matrix[9] * rhs.matrix[5] + this->matrix[10] * rhs.matrix[9] + this->matrix[11] * rhs.matrix[13];
this->matrix[10] = this->matrix[8] * rhs.matrix[2] + this->matrix[9] * rhs.matrix[6] + this->matrix[10] * rhs.matrix[10] + this->matrix[11] * rhs.matrix[14];
this->matrix[11] = this->matrix[8] * rhs.matrix[3] + this->matrix[9] * rhs.matrix[7] + this->matrix[10] * rhs.matrix[11] + this->matrix[11] * rhs.matrix[15];
this->matrix[12] = this->matrix[12] * rhs.matrix[0] + this->matrix[13] * rhs.matrix[4] + this->matrix[14] * rhs.matrix[8] + this->matrix[15] * rhs.matrix[12];
this->matrix[13] = this->matrix[12] * rhs.matrix[1] + this->matrix[13] * rhs.matrix[5] + this->matrix[14] * rhs.matrix[9] + this->matrix[15] * rhs.matrix[13];
this->matrix[14] = this->matrix[12] * rhs.matrix[2] + this->matrix[13] * rhs.matrix[6] + this->matrix[14] * rhs.matrix[10] + this->matrix[15] * rhs.matrix[14];
this->matrix[15] = this->matrix[12] * rhs.matrix[3] + this->matrix[13] * rhs.matrix[7] + this->matrix[14] * rhs.matrix[11] + this->matrix[15] * rhs.matrix[15];
return *this;
}
}matrix4x4;
matrix4x4 createTransformationMatrix(Vector3f translation, Vector3f rotation, Vector3f scale);
matrix4x4 createPerspectiveProjectionMatrix(GLfloat width, GLfloat height, GLfloat fov, GLfloat nearPlane, GLfloat farPlane);
matrix4x4 createViewMatrix(Vector3f cameraPosition, GLfloat cameraPitch, GLfloat cameraYaw, GLfloat cameraRoll);

及其相关实现 数学.cpp

matrix4x4::matrix4x4(GLfloat elements[])
{
//Elements stored in ROW MAJOR ORDER
for (unsigned int i = 0; i <= elementCount; i++)
{
matrix[i] = elements[i];
}
}
void matrix4x4::setIdentity()
{
std::fill(matrix, matrix + sizeof(matrix) / sizeof(GLfloat), 0.0f);
matrix[0] = 1;
matrix[5] = 1;
matrix[10] = 1;
matrix[15] = 1;
}
/*/////////////////////////////////////////////////////
math
/////////////////////////////////////////////////////*/
void matrix4x4::translate(Vector3f translation)
{
GLfloat transformElements[16] =
{
1.0f, 0.0f, 0.0f, translation.x,
0.0f, 1.0f, 0.0f, translation.y,
0.0f, 0.0f, 1.0f, translation.z,
0.0f, 0.0f, 0.0f, 1.0f
};
matrix4x4 transform = matrix4x4(transformElements);
*this *= transform;
}
void matrix4x4::rotateX(GLfloat angle)
{
angle = degreesToRadians(angle);
GLfloat transformElements[16] =
{
1.0f,       0.0f,               0.0f,           0.0f,
0.0f,   std::cos(-angle),   -std::sin(-angle),  0.0f,
0.0f,   std::sin(-angle),   std::cos(-angle),   0.0f,
0.0f,       0.0f,               0.0f,           1.0f
};
matrix4x4 transform = matrix4x4(transformElements);
*this *= transform;
}
void matrix4x4::rotateY(GLfloat angle)
{
angle = degreesToRadians(angle);
GLfloat transformElements[16] =
{
std::cos(-angle),   0.0f,   std::sin(-angle),   0.0f,
0.0f,               1.0f,       0.0f,           0.0f,
-std::sin(-angle),  0.0f,   std::cos(-angle),   0.0f,
0.0f,               0.0f,       0.0f,           1.0f
};
matrix4x4 transform = matrix4x4(transformElements);
*this *= transform;
}
void matrix4x4::rotateZ(GLfloat angle)
{
angle = degreesToRadians(angle);
GLfloat transformElements[16] =
{
std::cos(-angle),   -std::sin(-angle),  0.0f,   0.0f,
std::sin(-angle),   std::cos(-angle),   0.0f,   0.0f,
0.0f,                   0.0f,           1.0f,   0.0f,
0.0f,                   0.0f,           0.0f,   1.0f
};
matrix4x4 transform = matrix4x4(transformElements);
*this *= transform;
}
void matrix4x4::rotate(Vector3f angles)
{
matrix4x4 transform = matrix4x4();
transform.setIdentity();
transform.rotateX(angles.x);
transform.rotateY(angles.y);
transform.rotateZ(angles.z);
*this *= transform;
}
void matrix4x4::scale(Vector3f scales)
{
GLfloat transformElements[16] =
{
scales.x,   0.0f,       0.0f,       0.0f,
0.0f,       scales.y,   0.0f,       0.0f,
0.0f,       0.0f,       scales.z,   0.0f,
0.0f,       0.0f,       0.0f,       1.0f
};
matrix4x4 transform = matrix4x4(transformElements);
*this *= transform;
}
matrix4x4 createTransformationMatrix(Vector3f translation, Vector3f rotation, Vector3f scale)
{
matrix4x4 transformationMatrix;
transformationMatrix.setIdentity();
//I've tried changing the order of these around, as well as only
//doing one operation (skipping translate and scale, or everything but a single axis rotation
transformationMatrix.translate(translation);
transformationMatrix.rotate(rotation);
transformationMatrix.scale(scale);
return transformationMatrix;
}
matrix4x4 createPerspectiveProjectionMatrix(GLfloat width, GLfloat height, GLfloat fov, GLfloat nearPlane, GLfloat farPlane)
{
matrix4x4 projectionMatrix;
projectionMatrix.setIdentity();
GLfloat aspectRatio = width / height;
projectionMatrix.matrix[0] = (1.0f / std::tan((degreesToRadians(fov)) / 2.0f) / aspectRatio);
projectionMatrix.matrix[5] = 1.0f / std::tan((degreesToRadians(fov)) / 2.0f);
projectionMatrix.matrix[10] = (farPlane + nearPlane) / (nearPlane - farPlane);
projectionMatrix.matrix[11] = (2.0f * farPlane * nearPlane) / (nearPlane - farPlane);
projectionMatrix.matrix[14] = -1.0f;
return projectionMatrix;
}

我知道我的矩阵/矢量实现既快速又脏,但我只是想设置一些东西。我计划使数学方法(缩放、翻译等)成为不影响矩阵内容的静态方法,而是接受矩阵作为输入并返回一个新矩阵......但这不是现在的问题。

这是我的顶点着色器

#version 330 core
//declare inputs
in vec3 position;
in vec2 textureCoords;
//declare output
out vec2 pass_textureCoords;
//uniforms
uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
void main(void)
{
//tell OpenGL where to render the vertex on screen
gl_Position = projectionMatrix * viewMatrix * transformationMatrix * vec4(position.x, position.y, position.z, 1.0);
pass_textureCoords = textureCoords;
}

我的渲染方法...

void Renderer::render(Entity entity, Shader* shader)
{
...
RawModel* rawModel = texturedModel->getRawModel();
glBindVertexArray(rawModel->getVaoID());
...
matrix4x4 transformationMatrix = createTransformationMatrix(entity.getPosition(), entity.getRotation(), entity.getScale());
shader->loadTransformationMatrix(transformationMatrix);
...
glDrawElements(GL_TRIANGLES, rawModel->getVertexCount(), GL_UNSIGNED_INT, 0);
...
}

最后是我的主要相关作品。多维数据集定义等

//This is a simple cube
std::vector<GLfloat> vertices = 
{
-0.5f,0.5f,-0.5f,
-0.5f,-0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,0.5f,-0.5f,
-0.5f,0.5f,0.5f,
-0.5f,-0.5f,0.5f,
0.5f,-0.5f,0.5f,
0.5f,0.5f,0.5f,
0.5f,0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,-0.5f,0.5f,
0.5f,0.5f,0.5f,
-0.5f,0.5f,-0.5f,
-0.5f,-0.5f,-0.5f,
-0.5f,-0.5f,0.5f,
-0.5f,0.5f,0.5f,
-0.5f,0.5f,0.5f,
-0.5f,0.5f,-0.5f,
0.5f,0.5f,-0.5f,
0.5f,0.5f,0.5f,
-0.5f,-0.5f,0.5f,
-0.5f,-0.5f,-0.5f,
0.5f,-0.5f,-0.5f,
0.5f,-0.5f,0.5f
};
std::vector<GLfloat> textureCoords =
{
...
};
std::vector<GLuint> indices = 
{
0,1,3,
3,1,2,
4,5,7,
7,5,6,
8,9,11,
11,9,10,
12,13,15,
15,13,14,
16,17,19,
19,17,18,
20,21,23,
23,21,22
};
//parameters are (model, pos, rotation, scale)
Entity entity = Entity(&texturedModel, Vector3f(0.0f, 0.0f, -2.0f), Vector3f(0.0f, 0.0f, 0.0f), 1.0f);
//SHADER STUFF
Shader textureShader = Shader("uniformVarTextureShader");
textureShader.loadProjectionMatrix(display.getProjectionMatrix());
Camera cam;
//draw in wireframe mode
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
while (display.checkForClose() == 0)
{
glfwPollEvents();
//TO DO: update logic here
//entity.varyPosition(+0.005f, 0.0f, -0.002f); //this works, as does scaling and camera movement
//entity.varyRotation(0.25f, 0.18f, 0.0f);
entity.setYRotation(entity.getYRotation() + 0.25f); //any sort of rotation operation ends up with the strange behaivor
//rendering commands here
display.prepare();
textureShader.bind();
textureShader.loadViewMatrix(cam);
display.render(entity, &textureShader);
textureShader.stop();
display.swapBuffers();
}

所以,回顾一下;我在平移、缩放、"相机移动"方面没有任何问题,投影矩阵似乎也可以工作。但是,每当我尝试旋转时,我都会得到与上面文章链接完全相同的行为。

最后说明:我启用了深度测试并清除了每一帧的深度缓冲区。我还传递GL_TRUE来转置我提供给glUniformMatrix4fv的任何矩阵数据。我已经检查了每件制服的位置,它们正确通过;分别为 0、1 和 2。否 -1。

我很困惑,任何帮助将不胜感激。 如果需要,我可以发布更多代码,但我很确定这涵盖了问题最有可能出在哪里。再次感谢

主要问题是矩阵多重警务操作。 由于您操作矩阵(您从矩阵中读取并写入它),因此在读取它之前,是否已经操作了一些元素。

例如,在第一行中this->matrix[0]写到

this->matrix[0] = this->matrix[0] * rhs.matrix[0] + this->matrix[1] * rhs.matrix[4] + this->matrix[2] * rhs.matrix[8] + this->matrix[3] * rhs.matrix[12];

在第二行中,this->matrix[0]再次阅读:

this->matrix[1] = this->matrix[0] * rhs.matrix[1] + this->matrix[1] * rhs.matrix[5] + this->matrix[2] * rhs.matrix[9] + this->matrix[3] * rhs.matrix[13];

将矩阵数组复制到局部变量,以解决此问题:

matrix4x4& operator*=(const matrix4x4& rhs)
{
matrix4x4 act( this->matrix );
this->matrix[0] = act.matrix[0] * rhs.matrix[0] + act.matrix[1] * rhs.matrix[4] + act.matrix[2] * rhs.matrix[8] + act.matrix[3] * rhs.matrix[12];
this->matrix[1] = act.matrix[0] * rhs.matrix[1] + act.matrix[1] * rhs.matrix[5] + act.matrix[2] * rhs.matrix[9] + act.matrix[3] * rhs.matrix[13];
....
return *this;
}



顺便说一下,由于您在着色器中将向量从右侧乘以矩阵

gl_Position = projectionMatrix * viewMatrix * transformationMatrix * vec4(position.x, position.y, position.z, 1.0);

矩阵必须按列主顺序启动:

mat4 m44 = mat4(
vec4( Xx, Xy, Xz, 0.0),
vec4( Yx, Xy, Yz, 0.0),
vec4( Zx  Zy  Zz, 0.0),
vec4( Tx, Ty, Tz, 1.0) );

请注意,您的矩阵是按行主要顺序初始化的,例如matrix4x4::translate

GLfloat transformElements[16] =
{
1.0f, 0.0f, 0.0f, translation.x,
0.0f, 1.0f, 0.0f, translation.y,
0.0f, 0.0f, 1.0f, translation.z,
0.0f, 0.0f, 0.0f, 1.0f
};

因此,当您将矩阵设置为统一glUniformMatrix4fv时,您必须转置矩阵:

glUniformMatrix4fv( ..., ..., GL_TRUE, ... );