C++ 现代OpenGL立方体旋转未按预期工作

C++ 现代OpenGL立方体旋转未按预期工作,c++,opengl,math,matrix,rotation,C++,Opengl,Math,Matrix,Rotation,我试图绕一个轴旋转一个立方体,但它的行为肯定不正确。我假设问题在于我的矩阵旋转代码,因为其他一切似乎都在工作。我可以沿x、y或z轴以及比例正确平移模型。我的相机视图矩阵和投影矩阵也按预期工作。如果删除视图矩阵和/或投影矩阵实现,问题仍然存在 如果您想查看我得到的结果,它的输出与此stackoverflow帖子上显示的gif完全相同: 立方体在旋转时似乎在自身上折叠,然后在完全旋转后恢复正常,并且似乎在大约20度的时间内旋转良好,直到再次在自身上折叠并重复。我的问题与链接到文章中的问题相同,但我的

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

如果您想查看我得到的结果,它的输出与此stackoverflow帖子上显示的gif完全相同: 立方体在旋转时似乎在自身上折叠,然后在完全旋转后恢复正常,并且似乎在大约20度的时间内旋转良好,直到再次在自身上折叠并重复。我的问题与链接到文章中的问题相同,但我的矩阵类不同,因此我的问题虽然相同,但似乎有不同的解决方案

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

数学

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);
它是相关的实现 math.cpp

我的渲染方法

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();
    }
//这是一个简单的多维数据集
标准::向量顶点=
{
-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
};
向量纹理词=
{
...
};
标准::向量索引=
{
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
};
//参数包括(型号、位置、旋转、比例)
实体实体=实体(&TextureModel,Vector3f(0.0f,0.0f,-2.0f),Vector3f(0.0f,0.0f,0.0f),1.0f);
//着色材料
着色器textureShader=着色器(“uniformVarTextureShader”);
loadProjectionMatrix(display.getProjectionMatrix());
摄像机;
//以线框模式绘制
glPolygonMode(GLU前、后、GLU线);
//glPolygonMode(GLU前、后、GLU填充);
while(display.checkForClose()==0)
{
glfwPollEvents();
//要做的事情:在这里更新逻辑
//entity.varyPosition(+0.005f,0.0f,-0.002f);//这与缩放和相机移动一样有效
//实体变量(0.25f、0.18f、0.0f);
entity.setyrotion(entity.getyrotion()+0.25f);//任何类型的旋转操作都会以奇怪的行为结束
//此处呈现命令
display.prepare();
textureShader.bind();
textureShader.loadViewMatrix(cam);
display.render(实体和纹理标头);
textureShader.stop();
display.swapBuffers();
}
因此,回顾一下;我在平移、缩放、“相机移动”和投影矩阵方面没有任何问题。然而,每当我尝试旋转时,我都会得到与上面链接的文章完全相同的行为

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


我被难倒了,任何帮助都将不胜感激。如果需要的话,我可以发布更多的代码,但我很确定这涵盖了问题最可能存在的全部内容。再次感谢

主要问题是矩阵多应用操作。 因为你操纵了矩阵(你从矩阵中读取并写入矩阵),所以在你阅读它之前,有些元素已经被操纵了

e、 g.在第一行
中,该->矩阵[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];
在第二行
中,再次读取该->矩阵[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
};
因此,当您将矩阵设置为统一矩阵时,必须对其进行转置:


把它编辑成一个字母。建议使用一个已知的好库,如matrix-slinging。向下编辑,我觉得我应该留在投影矩阵构造中,以防问题与此有关,以及我的translate和scale方法,以表明我在那里尝试的工作确实有效。我不想使用GLM或其他库,因为我希望能够跨多个平台移植此代码,包括一些使用自己的图形系统的平台。如果不移植所有OpenGL,GLM就不能在这些情况下使用。我更喜欢使用“滚动自己的”矩阵处理类,以防止跨平台为同一项目使用多个截然不同的代码库。到目前为止,我能够避开大多数外部库,并希望将数量保持在绝对最小。我不敢相信我忽略了这一点。我想,当你匆忙行事时就会发生这种情况。非常感谢。我确实已经通过了glUniformMatrix4fv的GL_TRUE,正如我在文章底部所指出的那样。再次感谢您的快速回复,这确实是我的问题
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) );
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( ..., ..., GL_TRUE, ... );