GLFW - 用鼠标旋转相机的视图矩阵使其旋转

GLFW - Rotating camera's view matrix with mouse makes it spin

我使用 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 显示了在旋转相机的同时盘旋鼠标时发生的情况。

我在这里猜测,但也许您应该将整个代码置于条件 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));
        }
    }

看着视频,我明白了问题所在。您正在寻找的是一个虚拟轨迹球。 Whosebug 提供:

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度。

您可以使用四元数简单地实现它,上面的源代码中提供了对它的解释

只是用我的解决方案更新此线程以帮助将来的人。

问题是我没有在每一帧都创建一个全新的变换矩阵。我试图添加到旧的视图矩阵,这就是相机旋转的原因。它将采用旧的向上矢量并向其添加新矢量,这将产生旋转。所以代码现在就是这样:

view = rotationMatTotal * translationMat;

而不是这个:

view *= rotationMatTotal * translationMat;

感谢所有回复,他们提供了很多信息,我学到了很多东西!