OpenGL中鼠标输入背后的数学运算和偏航/俯仰值

彼得

嗨,我正在尝试一些c ++ opengl代码并制作了一个相机。我想给场景一个鼠标输入以便四处查看,所以我像这里的教程一样添加了此代码。https://learnopengl.com/使用入门/相机

但是,对于偏航和俯仰值,有些数学概念我不了解。这是鼠标移动的回调函数。

void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
    if (firstMouse) //preventing large jumps
    {
        lastX = xpos;
        lastY = ypos;
        firstMouse = false;
    }

    float xoffset = xpos - lastX;
    float yoffset = lastY - ypos;
    lastX = xpos;
    lastY = ypos;

    float sensitivity = 0.1f;
    xoffset *= sensitivity;
    yoffset *= sensitivity;

    yaw += xoffset;
    pitch += yoffset;

    if (pitch > 89.0f)
        pitch = 89.0f;
    if (pitch < -89.0f)
        pitch = -89.0f;

    glm::vec3 front;
    front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
    front.y = sin(glm::radians(pitch));
    front.z = cos(glm::radians(pitch)) * sin(glm::radians(yaw));

    //cameraFront is the direction vector of the camera. Where the camera is looking at
    cameraFront = glm::normalize(front);
}

为了以防万一,下面是在mouse_callback函数中使用的全局变量及其初始值。

glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
//lookAt function requires position, target's position, up vector respectively.

我不明白两件事。据我了解,偏航和俯仰是分别从y轴和x轴计算的。通过使用我们的右手并将拇指指向轴的+方向,其他手指弯曲的方向就是该角度的正方向。

现在,假设我将鼠标移至右侧,而未更改yoffset。然后根据mouse_callback函数,因为xoffset为正,所以偏航值会增加。由于y轴的正方向指向我们正在观看的窗口的顶部,所以偏航的增加意味着相机的方向向量应该向左旋转,对不对?但是在程序中,相机转动并显示场景的右侧部分。我不明白发生了什么。

如果我知道这里发生了什么,我想我可以理解为什么获取yoffset的计算顺序也不同于获取xoffset值的原因。

任何帮助将不胜感激。告诉我是否误解了任何数学概念或其他东西。提前致谢!

由于y轴的正方向指向我们正在观看的窗口的顶部,所以偏航的增加意味着相机的方向向量应该向左旋转,对不对?

否。y的方向与此处无关。保留pitch为0时,给出的公式等于:

front.x = cos(glm::radians(yaw))
front.y = 0
front.z = sin(glm::radians(yaw));

因此,如果yaw为0,则结果为(1,0,0)(右)。如果将其增加到90度,则最终得到(0,0,1),它在右手坐标系中直接指向后方,因此您只是向右转。

您似乎以某种方式将其与正旋转方向相关联,当绕y旋转时,正旋转方向始终从z到x。但是这些公式并未实现绕y轴正角度yaw旋转角度,但实际上旋转了-yaw:由于系统设置为在角度0处屈服+ x,因此我们可以将其视为正向矢量v= (1,0,0)围绕轴y,因此经典旋转矩阵将产生:

      (  cos(yaw)      0     sin(yaw) )           ( cos(yaw) )
v' =  (     0          1        0     ) * v   =   (     0    )
      (  -sin(yaw)     0     cos(yaw) )           (-sin(yaw) )

但是,当您沿负旋转方向旋转时,最终会得到转置矩阵,只需将负号翻转sin

      (  cos(yaw)      0    -sin(yaw) )           ( cos(yaw) )
v' =  (     0          1        0     ) * v   =   (     0    )
      (  sin(yaw)      0     cos(yaw) )           ( sin(yaw) )

就是这样

front = R_y ( -yaw) * (1,0,0)^T

如果您查看带有pitch和偏航的完整公式,您会发现它等于:

front = R_y(-yaw) * R_z(pitch) * (1,0,0)^T

这只是一个完整的旋转,首先pitch以正缠绕顺序围绕z轴旋转(1,0,0),然后yaw以负顺序围绕y轴旋转结果

我还认为您在此处引用的源代码的作者要么是a)着急,要么b)有点困惑这里的数学计算方式。我说这有两个原因:

  1. 默认方向为(0,0,-1),但欧拉角设置为pitch=0yaw=0导致(1,0,0)可视方向,默认为yaw=-90可以用一种更简洁,更直观的方式来制定它,以便零角度产生默认的前视方向。

  2. lookAt这里完全不需要使用它在内部执行的正交归一化只是浪费处理能力(尽管对于当今的标准来说这不是很大的能力,但是仍然如此)。(0,1,0)作为向上向量的用法将在两极附近变得非常不稳定,并且限制pitch[-89,89]hack只是为了防止这种情况的发生。实际上,在此导航模型中让摄像机直视向上或向下并没有什么错误(由于您仅沿2D平面移动yaw,因此即使单独向上或向下直视,也仍然可以很好地定义前进方向)。这种情况引起的万向节锁定也​​不重要,因为根本就没有第三次旋转。

    实际上,直接从两个旋转角度和相机位置创建视图矩阵要容易得多,并且完全避免了在90度或全90度附近的任何问题。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

TOP 榜单

热门标签

归档