GLFW - 用鼠标旋转相机的视图矩阵使其旋转
Posted
技术标签:
【中文标题】GLFW - 用鼠标旋转相机的视图矩阵使其旋转【英文标题】:GLFW - Rotating camera's view matrix with mouse makes it spin 【发布时间】:2016-03-08 10:43:05 【问题描述】:我使用 glfw 来获取鼠标位置,然后计算偏移量(或我在代码中标记的增量),并使用它来围绕 x 轴和 y 轴旋转相机。这一切都很好,但是,当我用鼠标做圆圈时,由于某种原因,它会使相机沿 z 轴旋转。
这是我计算鼠标 x 和 y 增量位置的代码:
void input(Window* window, float deltaTime)
rotationMatY = Matrix44::CreateIdentity();
rotationMatX = Matrix44::CreateIdentity();
translationMat = Matrix44::CreateIdentity();
float oldXPos = (float)mouseX, oldYPos = (float)mouseY;
glfwGetCursorPos(window->getGLFWWindow(), &mouseX, &mouseY);
float xDelta, yDelta;
xDelta = (float)mouseX - oldXPos;
yDelta = (float)mouseY - oldYPos;
const float R_SPEED = 10.f;
// Rotate the camera around with the mouse according to how much it's moved
// since the last frame
if (getMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT))
rotationMatY =
Matrix44::CreateRotateY(DegToRad(R_SPEED * xDelta * deltaTime));
rotationMatX =
Matrix44::CreateRotateX(DegToRad(R_SPEED * yDelta * deltaTime));
然后我将相机的视图矩阵乘以生成的旋转矩阵:
void Crate_full_framework::onRender()
view *= rotationMatY;
view *= rotationMatX;
... // Other rendering code here
这是我计算 x 轴和 y 轴旋转的方法:
Matrix44 Matrix44::CreateRotateX(float angle)
return Matrix44(1.f, 0.f, 0.f, 0.f,
0.f, cosf(angle), sinf(angle), 0.f,
0.f, -sinf(angle), cosf(angle), 0.f,
0.f, 0.f, 0.f, 1.f);
Matrix44 Matrix44::CreateRotateY(float angle)
return Matrix44(cosf(angle), 0.f, -sinf(angle), 0.f,
0.f, 1.f, 0.f, 0.f,
sinf(angle), 0.f, cosf(angle), 0.f,
0.f, 0.f, 0.f, 1.f);
我只是想弄清楚我的数学哪里出了问题。我很确定我必须重置相机的 y 轴方向,以便它始终在正 y 方向上,只是不知道如何到达那里。
编辑:我在这里向 YouTube 上传了一个视频:https://youtu.be/2QXKvOGHXgM,它只是展示了在旋转相机的同时盘旋鼠标会发生什么。
【问题讨论】:
无需在您的矩阵代码中寻找实际错误,只是一个小注释。我通常不会滚动我自己的矩阵/向量代码。有些库可以更好更快地做到这一点(使用 sse/neon 内在函数)。例如,只有标头 GLM library 非常流行,大多数 opengl 教程实际上都使用它作为首选实现,因为它试图与 glsl 着色器的语法紧密匹配。 感谢您的评论,我真的很想使用 glm,但不幸的是这是为了学校,所以我必须自己编写代码。 【参考方案1】:看视频,我看到了问题。您正在寻找的是一个虚拟轨迹球。 *** 提供:
https://computergraphics.stackexchange.com/questions/151/how-to-implement-a-trackball-in-opengl
您当前使用的看起来像欧拉角,其中(除其他外)存在您刚刚遇到的问题。
来自:http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/
在 2 个方向之间进行平滑插值很难。简单地插值 X、Y 和 Z 角度会很丑。 应用多次旋转既复杂又不精确:您必须计算最终的旋转矩阵,并从该矩阵中猜测欧拉角 一个众所周知的问题,“万向节锁定”,有时会阻止您的旋转,以及其他会翻转您的模型的奇点 倒置。 不同的角度进行相同的旋转(例如 -180° 和 180°) 一团糟 - 如上所述,通常正确的顺序是 YZX,但如果您还使用不同顺序的库,就会有麻烦。 有些操作很复杂:例如,围绕特定轴旋转 N 度。您可以使用四元数来简单地实现它,上面的源代码中提供了它的解释
【讨论】:
我在想这可能与欧拉角有关。我会查看您提供的链接。感谢您的回答。【参考方案2】:我在这里猜测,但可能你应该将整个代码置于getMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT)
条件下。
void input(Window* window, float deltaTime)
// Rotate the camera around with the mouse according to how much it's moved
// since the last frame
if (getMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT))
rotationMatY = Matrix44::CreateIdentity();
rotationMatX = Matrix44::CreateIdentity();
translationMat = Matrix44::CreateIdentity();
float oldXPos = (float)mouseX, oldYPos = (float)mouseY;
glfwGetCursorPos(window->getGLFWWindow(), &mouseX, &mouseY);
float xDelta, yDelta;
xDelta = (float)mouseX - oldXPos;
yDelta = (float)mouseY - oldYPos;
const float R_SPEED = 10.f;
rotationMatY =
Matrix44::CreateRotateY(DegToRad(R_SPEED * xDelta * deltaTime));
rotationMatX =
Matrix44::CreateRotateX(DegToRad(R_SPEED * yDelta * deltaTime));
【讨论】:
对它没有太大的期望,但这是我没想到的新东西。试过了,还是不行。不过还是谢谢。【参考方案3】:只是用我的解决方案更新这个帖子,以便将来帮助人们。
问题是我没有在每一帧都创建一个全新的变换矩阵。我试图添加到旧的视图矩阵中,这就是相机会旋转的原因。它将采用旧的向上向量并将新向量添加到其中,这将产生旋转。所以现在的代码是这样的:
view = rotationMatTotal * translationMat;
而不是这个:
view *= rotationMatTotal * translationMat;
感谢所有回复,他们提供了丰富的信息,我学到了很多东西!
【讨论】:
以上是关于GLFW - 用鼠标旋转相机的视图矩阵使其旋转的主要内容,如果未能解决你的问题,请参考以下文章