【问题标题】:Modern OpenGL cube rotation not working as expected现代 OpenGL 立方体旋转未按预期工作
【发布时间】:2018-09-28 02:50:00
【问题描述】:

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

如果你想看看我得到了什么结果,它的输出与此 stackoverflow 帖子中显示的 gif 完全相同:Rotating a cube in modern opengl... looks strange 立方体在旋转时似乎会自行折叠,然后在完全旋转后恢复正常,并且似乎可以正常旋转约 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。

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

【问题讨论】:

  • 将其编辑为minimal reproducible example。推荐使用已知良好的库,如 GLM 进行矩阵吊索。
  • 已编辑,我觉得我应该留在投影矩阵构造中,以防问题与此有关,以及我的翻译和缩放方法以表明我正在尝试做的事情确实有效
  • 我不想使用 GLM 或其他库,因为我希望能够跨多个平台移植此代码,包括一些使用自己的图形系统的平台。如果不移植所有 OpenGL,GLM 就不能在这些情况下使用。我更喜欢“滚动你自己的”矩阵处理类,以防止跨平台为同一个项目使用几个截然不同的代码库。到目前为止,我已经能够避免使用大多数外部库,并希望将数量保持在绝对最小值

标签: c++ opengl math matrix rotation


【解决方案1】:

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

例如在第一行 this-&gt;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-&gt;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, ... );

【讨论】:

  • 我不敢相信我忽略了这一点。我想这就是你匆忙做事时会发生的事情。谢谢你。正如我的帖子底部所指出的,我已经将 GL_TRUE 传递给 glUniformMatrix4fv。再次感谢您的快速回复,这确实是我的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-11
  • 1970-01-01
  • 2021-06-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多