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

时间:2016-03-08 10:43:06

标签: c++ opengl matrix rotation glfw

我正在使用glfw来获取鼠标位置,然后我计算偏移量(或我在代码中标记它的增量),然后我使用它来围绕x轴和y轴旋转相机。这一切都很好,但是,当我用鼠标做圆圈时,由于某种原因,相机会沿着z轴旋转。

这是我的代码,我计算鼠标的x和y-delta位置:

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,其中只显示了在旋转相机时旋转鼠标时会发生什么。

3 个答案:

答案 0 :(得分:1)

观看视频,我看到了这个问题。您正在寻找的是虚拟轨迹球。 Stackoverflow提供:

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

您可以使用四元数来简单地实现它,其解释在上面的源

中提供

答案 1 :(得分:0)

我在这里猜测,但可能你应该把整个代码放在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));
        }
    }

答案 2 :(得分:0)

只需使用我的解决方案更新此主题,以便将来帮助人们。

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

view = rotationMatTotal * translationMat;

而不是:

view *= rotationMatTotal * translationMat;

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