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 - 用鼠标旋转相机的视图矩阵使其旋转的主要内容,如果未能解决你的问题,请参考以下文章

glRotatef 旋转相机而不是物体

Unity:使用鼠标位置为我的相机制作角度以围绕对象旋转

使用鼠标围绕中心旋转 Three.js 相机

3D MAX常用快捷键

怎样用鼠标控制摄像机的移动旋转

Cesium.js禁止三维球鼠标旋转、缩放、鼠标中键拖动