现代OpenGL立方体旋转无法按预期工作

时间:2018-04-18 01:49:23

标签: c++ opengl math matrix rotation

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

如果您希望查看我获得的结果,它与此stackoverflow帖子中显示的gif完全相同:Rotating a cube in modern opengl... looks strange 旋转时立方体似乎会自行折叠,然后在完全旋转后恢复正常,并且似乎旋转精细约20度,直到再次折叠并重复。我的问题与链接到文章的问题相同,但是我的矩阵类不一样,所以我的问题虽然相同,但似乎有不同的解决方案。

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

math.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);

及其相关实施 math.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();
    }

所以,回顾一下;我在翻译,缩放和相机移动方面没有任何问题&#34;并且投影矩阵似乎也起作用。但是,无论何时我尝试旋转,我都会获得与上面链接文章完全相同的行为。

最后的注意事项:我已启用深度测试并清除每帧的深度缓冲区。我还传递GL_TRUE来转置我给glUniformMatrix4fv的任何矩阵数据。我检查了每件制服的位置,并且正确地通过了;分别为0,1和2。不是-1。

我很难过,任何帮助都会受到赞赏。如果需要,我可以发布更多代码,但我非常确定这涵盖了问题最有可能存在的全部内容。再次感谢

1 个答案:

答案 0 :(得分:2)

主要问题是矩阵多色化操作。 由于你操纵矩阵(你从矩阵读取并写入它),在你阅读它之前,一些元素是否已被操纵过。

e.g。在第一行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, ... );