OpenGL:从原点平移时模型拉伸

Posted

技术标签:

【中文标题】OpenGL:从原点平移时模型拉伸【英文标题】:OpenGL: Model stretched when translated from origin 【发布时间】:2015-01-14 16:34:41 【问题描述】:

我正在开发一个太空飞行模拟器,作为我的第一个真正的 OpenGL 项目。当立方体不在原点时,我无法正确渲染它。发生的情况是立方体从原点伸出,拉伸的程度取决于从原点平移的量。

我相信它与着色器无关,因为我尝试了两个不同的顶点着色器,结果相同。其中一个着色器是一个非常简单的着色器:

#version 330 core

// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;

// Output data ; will be interpolated for each fragment.
out vec3 fragmentColor;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;

void main()    

    // Output position of the vertex, in clip space : MVP * position
    gl_Position =  MVP * vec4(vertexPosition_modelspace,1);

    // The color of each vertex will be interpolated
    // to produce the color of each fragment
    fragmentColor = vec3(255,255,255);

我似乎很清楚问题不在于着色器。

当立方体在每个方向平移 1 个单位时,它看起来像这样:

在正 Z 方向平移相机时,立方体将拉伸更多以跟随相机。

翻译前(相机位于(0,0,25),模型位于(5,5,5))

MVP 矩阵:

(10.942525, 0.000000, 12.402489, 12.500000)   
(0.000000, 14.590034, 12.402489, 12.500000)   
(0.000000, 0.000000, 12.302468, 12.400000)   
(0.000000, 0.000000, 24.804977, 25.000000) 

变换矩阵:

(0.100000, 0.000000, 0.000000, 0.500000)   
(0.000000, 0.100000, 0.000000, 0.500000)   
(0.000000, 0.000000, 0.100000, 0.500000)   
(0.000000, 0.000000, 0.000000, 1.000000)   

平移后(相机正z方向平移)

变换矩阵:

(0.100000, 0.000000, 0.000000, 0.500000)
(0.000000, 0.100000, 0.000000, 0.500000)
(0.000000, 0.000000, 0.100000, 0.500000)
(0.000000, 0.000000, 0.000000, 1.000000)

MVP 矩阵:

(10.942525, 0.000000, 46.159237, 46.250000)
(0.000000, 14.590034, 46.159237, 46.250000)
(0.000000, 0.000000, 46.059216, 46.150002)
(0.000000, 0.000000, 92.318474, 92.500000)

这是我从模型中获取转换矩阵的代码:

glm::mat4 MovableObject::getTransformationMatrix() const

    return getTranslationMatrix() * getRotationMatrix() * getScaleMatrix();


glm::mat4 MovableObject::getScaleMatrix() const

    glm::mat4 scaleMatrix = glm::mat4(1.0);
    scaleMatrix[0][0] = scaleFactors[0];
    scaleMatrix[1][1] = scaleFactors[1];
    scaleMatrix[2][2] = scaleFactors[2];
    return scaleMatrix;


glm::mat4 MovableObject::getRotationMatrix() const

    return glm::toMat4(rotation);


glm::mat4 MovableObject::getTranslationMatrix() const

    glm::mat4 translationMatrix = glm::mat4(1.);
    translationMatrix[0][3] = center[0];
    translationMatrix[1][3] = center[1];
    translationMatrix[2][3] = center[2];
    return translationMatrix;

这是绘制网格的渲染代码:

void Mesh::render(glm::mat4 modelMatrix, const Camera& camera)

    glUseProgram(programID);

    glm::mat4 view = camera.getViewMatrix();
    glm::mat4 pvm = camera.getProjectionMatrix() * view * modelMatrix;

    std::cout << "MVP Matrix: " << glm::to_string(pvm) << std::endl << std::endl;

    // Send our transformation to the currently bound shader,
    // in the "MVP" uniform
    glUniformMatrix4fv(matrixID, 1, GL_FALSE, &pvm[0][0]);
    glUniformMatrix4fv(modelMatrixID, 1, GL_FALSE, &modelMatrix[0][0]);
    glUniformMatrix4fv(viewMatrixID, 1, GL_FALSE, &view[0][0]);

    glUniform3f(lightID, 0.f, 0.f, 0.f); // TODO: hardwiring at 0 for now

    // Bind our texture in Texture Unit 0
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    // Set "myTextureSampler" sampler to user Texture Unit 0
    glUniform1i(textureID, 0);

    // 1st attribute buffer : vertices
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexAttribPointer(
                          0,                  // attribute
                          3,                  // size
                          GL_FLOAT,           // type
                          GL_FALSE,           // normalized?
                          0,                  // stride
                          (void*)0            // array buffer offset
                          );

    // 2nd attribute buffer : UVs
    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
    glVertexAttribPointer(
                          1,                                // attribute
                          2,                                // size
                          GL_FLOAT,                         // type
                          GL_FALSE,                         // normalized?
                          0,                                // stride
                          (void*)0                          // array buffer offset
                          );

    // 3rd attribute buffer : normals
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
    glVertexAttribPointer(
                          2,                                // attribute
                          3,                                // size
                          GL_FLOAT,                         // type
                          GL_FALSE,                         // normalized?
                          0,                                // stride
                          (void*)0                          // array buffer offset
                          );

    // Draw the triangles !
    glDrawArrays(GL_TRIANGLES, 0, vertices.size() );

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);

这是获取相机矩阵的代码:

glm::mat4 Camera::getProjectionMatrix() const

    return glm::perspective(FoV, 4.0f / 3.0f, 0.1f, 1000.0f);


glm::mat4 Camera::getViewMatrix() const

    glm::mat4 matrix = glm::toMat4(rotation);
    glm::vec3 up = glm::vec3(matrix[0][1], matrix[1][1], matrix[2][1]);
    glm::vec3 forward = -glm::vec3(matrix[0][2], matrix[1][2], matrix[2][2]);


    return glm::lookAt(center, center + forward, up);

【问题讨论】:

抱歉,我没有正确理解这一点,并且有几个问题 - 当您沿 z 轴仅平移时,为什么您的 MVP 在这两种情况下看起来如此不同?还要将此翻译添加到哪个矩阵?您的模型矩阵在两种情况下似乎都保持不变,并且“Camera::getViewMatrix()”似乎根本没有使用翻译?? 翻译被添加到代表相机的矩阵中,所以相机在移动,而不是模型。我认为这可能是 MVP 看起来如此不同的原因,但老实说我不确定。 另外,center 表示相机或模型中心的向量,因此 getViewMatrix() 使用该平移。 【参考方案1】:

glm 使用以列为主的存储顺序,因此您必须以 m[col][row] 的形式访问元素。您的 getTranslationMatrix() 函数未遵循该约定,因为翻译向量应位于最后一列。您打印矩阵数字的代码似乎也可以解释转置的内容。

请注意,glm 已经具备通过GLM_GTX_transform module 创建转换矩阵(如旋转、缩放和平移)的功能。

【讨论】:

看,当我在代码中寻找其他潜在问题时会发生这种情况。我被打败了。【参考方案2】:

我不得不假设直接访问矩阵成员的函数存在问题

glm::mat4 MovableObject::getScaleMatrix() const 
  glm::mat4 scaleMatrix = glm::mat4(1.0);
  scaleMatrix[0][0] = scaleFactors[0];
  scaleMatrix[1][1] = scaleFactors[1];
  scaleMatrix[2][2] = scaleFactors[2];
  return scaleMatrix;


glm::mat4 MovableObject::getTranslationMatrix() const

  glm::mat4 translationMatrix = glm::mat4(1.);
  translationMatrix[0][3] = center[0];
  translationMatrix[1][3] = center[1];
  translationMatrix[2][3] = center[2];
  return translationMatrix;

你为什么要这样做而不是更安全

glm::mat4 MovableObject::getScaleMatrix() const 
  return glm::scale(glm::mat4(), scaleFactors);


glm::mat4 MovableObject::getTranslationMatrix() const 
  return glm::translate(glm::mat4(), center);

【讨论】:

以上是关于OpenGL:从原点平移时模型拉伸的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 平移和旋转同时进行

OpenGL中旋转平移缩放等变换的顺序对模型的影响

OpenGL:组合平移/旋转/缩放矩阵或将它们分开?

OpenGL 链式平移/旋转

OpenGL围绕自身而不是原点(0,0,0)旋转对象(一组立方体)

Opengl模型矩阵在旋转一圈后不绕原点旋转