我的3D OpenGL对象围绕世界原点旋转,而不是局部空间原点。我做错了什么或误解了什么?

时间:2016-12-14 04:24:21

标签: c++ opengl 3d rotation glm-math

我已经被困在这两天了,我不确定在哪里可以看。我使用OpenGL渲染两个3d立方体,并尝试将局部旋转应用于这些场景中的每个立方体,以响应我按下按钮。

我已经达到了我的立方体在3d空间中旋转的程度,但它们都围绕着世界空间的原点而不是它们自己的本地原点旋转。

(第二视频) https://www.youtube.com/watch?v=3mrK4_cCvUw

在搜索互联网后,计算MVP的适当公式如下:

auto const model = TranslationMatrix * RotationMatrix * ScaleMatrix;
auto const modelview = projection * view * model;

我的每个立方体都拥有自己的"型号",其定义如下:

struct model
{
    glm::vec3 translation;
    glm::quat rotation;
    glm::vec3 scale = glm::vec3{1.0f};
};

当我按下键盘上的按钮时,我创建一个表示新角度的四元数,并将其与前一个旋转四元数相乘,并将其更新到位。

该功能如下所示:

template<typename TData>
void rotate_entity(TData &data, ecst::entity_id const eid, float const angle,
  glm::vec3 const& axis) const
{
    auto &m = data.get(ct::model, eid);
    auto const q = glm::angleAxis(glm::degrees(angle), axis);
    m.rotation = q * m.rotation;

    // I'm a bit unsure on this last line above, I've also tried the following without fully understanding the difference
    // m.rotation = m.rotation * q;
}

轴由用户提供,如下所示:

// inside user-input handling function
float constexpr ANGLE = 0.2f;

...

// y-rotation
case SDLK_u: {
    auto constexpr ROTATION_VECTOR = glm::vec3{0.0f, 1.0f, 0.0f};
    rotate_entities(data, ANGLE, ROTATION_VECTOR);
    break;
}
case SDLK_i: {
    auto constexpr ROTATION_VECTOR = glm::vec3{0.0f, -1.0f, 0.0f};
    rotate_entities(data, ANGLE, ROTATION_VECTOR);
    break;
}

我的GLSL顶点着色器非常简单,我在示例代码中找到了它:

// attributes input to the vertex shader
in vec4 a_position; // position value

// output of the vertex shader - input to fragment
// shader
out vec3 v_uv;

uniform mat4 u_mvmatrix;

void main()
{
  gl_Position = u_mvmatrix * a_position;
  v_uv = vec3(a_position.x, a_position.y, a_position.z);
}

在我的绘图代码中,我用来计算每个多维数据集的MVP的确切代码是:

...
auto const& model = shape.model();

auto const tmatrix = glm::translate(glm::mat4{}, model.translation);
auto const rmatrix = glm::toMat4(model.rotation);
auto const smatrix = glm::scale(glm::mat4{}, model.scale);
auto const mmatrix = tmatrix * rmatrix * smatrix;
auto const mvmatrix = projection * view * mmatrix;

// simple wrapper that does logging and forwards to glUniformMatrix4fv()
p.set_uniform_matrix_4fv(logger, "u_mvmatrix", mvmatrix);

在我的程序的早期,我计算我的视图/投影矩阵如下:

auto const windowheight = static_cast<GLfloat>(hw.h);
auto const windowwidth = static_cast<GLfloat>(hw.w);
auto projection = glm::perspective(60.0f, (windowwidth / windowheight), 0.1f, 100.0f);
auto view = glm::lookAt(
  glm::vec3(0.0f, 0.0f, 1.0f), // camera position
  glm::vec3(0.0f, 0.0f, -1.0f),  // look at origin
  glm::vec3(0.0f, 1.0f, 0.0f)); // "up" vector

我的立方体在世界空间中的位置在Z轴上,所以它们应该是可见的:

cube0.set_world_position(0.0f, 0.0f, 0.0f, 1.0f);
cube1.set_world_position(-0.7f, 0.7f, 0.0f, 1.0f);

// I call set_world_position() exactly once before my game enter's it's main loop.
// I never call this again, it just modifies the vertex used as the center of the shape.
// It doesn't modify the model matrix at all.
// I call it once before my game enter's it's game loop, and I never modify it after that.

所以,我的问题是,更新对象的旋转是否合适?

我应该将四元数直接存储在我的对象&#34;模型&#34;?

我应该将翻译和缩放存储为单独的vec3吗?

有更简单的方法吗?我一直在阅读和重新阅读我能找到的任何内容,但我没有看到有人这样做。

本教程有点细节,特别是如何将旋转应用于现有旋转(我相信这只是将四元数相乘,这就是我在上面的rotate_entity(...)中所做的事情。 )。 http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/ https://github.com/opengl-tutorials/ogl/blob/master/tutorial17_rotations/tutorial17.cpp#L306-L311

存储结果&#34; MVP&#34;更有意义吗?矩阵我自己作为我的&#34;模型&#34; 并直接在MVP矩阵上应用glm :: transform / glm :: scale / glm :: rotate操作? (我之前尝试过最后一个选项,但我也无法弄清楚如何让它工作)。

谢谢!

编辑:更好的链接

1 个答案:

答案 0 :(得分:4)

通常,您不希望修改模型在CPU上的各个顶点的位置。这是顶点程序的全部目的。模型矩阵的目的是将模型定位在顶点程序中的世界中。

要围绕中心旋转模型,您需要先将中心移动到原点,然后旋转它,然后将中心移动到最终位置。所以,让我们说你有一个从(0,0,0)延伸到(1,1,1)的立方体。你需要:

  1. 将多维数据集翻译为(-0.5,-0.5,-0.5)
  2. 按角度旋转
  3. 将立方体翻译为(0.5,0.5,0.5)
  4. 将多维数据集翻译到场景中的任何位置
  5. 您可以将最后两个翻译合并为一个,当然,您可以将所有这些转换合并为一个矩阵,即模型矩阵。