嗨,我正在尝试一些c ++ opengl代码并制作了一个相机。我想给场景一个鼠标输入以便四处查看,所以我像这里的教程一样添加了此代码。 https://learnopengl.com/Getting-started/Camera
但是,关于偏航和俯仰值,有些数学概念我不了解。这是鼠标移动的回调函数。
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值的原因。
任何帮助将不胜感激。告诉我是否误解了任何数学概念或其他东西。预先感谢!
答案 0 :(得分:1)
由于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
这只是一个整数旋转,首先以正缠绕顺序围绕z轴旋转角度pitch
(1,0,0),然后将y轴绕结果y角度yaw
旋转负序。
我还认为您在这里引用的源代码的作者要么是a)着急,要么b)有点困惑这里的数学计算方式。我说这有两个原因:
默认方向为(0,0,-1),但欧拉角设置为使得pitch=0
,yaw=0
产生(1,0,0)观看方向,默认为yaw=-90
。可以用一种更简洁,更直观的方式来制定它,以便零角度产生默认的前视方向。
此处完全不需要使用lookAt
。它在内部执行的正交归一化只是浪费处理能力(尽管对于今天的标准来说这不是很大的能力,但是仍然如此)。将(0,1,0)
用作向上向量将在极点附近变得非常不稳定,将pitch
限制为[-89,89]
只是防止这种情况发生的一种手段。实际上,在此导航模型中使摄像机直视上或下是没有错的(由于您仅沿2D平面移动,因此,即使{@ 1}下)。这种情况引起的万向节锁定也无关紧要,因为根本没有跟随第三次旋转。
直接从两个旋转角度和相机位置创建视图矩阵确实很容易,并且完全避免了在90度或全90度附近的任何问题。