OpenGL:当我移动相机时,它会向侧面倾斜

OpenGL: Camera tilts sideways when I move it

本文关键字:向侧面 倾斜 相机 移动 OpenGL      更新时间:2023-10-16

我正在尝试在OpenGL中自己实现一个相机(我使用glfw和gml(。 至于现在,我没有任何课程。我稍后会创建它。因此,这是我对相机运动进行编码的尝试;它适用于简单的鼠标移动,但除此之外,相机会侧向倾斜。我仍然是OpenGL的新手,所以我没有太多要展示的内容,但这里有说明我的问题:https://i.stack.imgur.com/7YK5t.jpg

我有几个(目前是全局的(变量:

float lastX = 0.0f, lastY = 0.0f, yaw = 0.0f, pitch = 0.0f;
glm::vec3 cameraPos(0.0f, 0.0f, 3.0f);
glm::vec3 cameraUp(0.0f, 1.0f, 0.0f); // As a reminder, x points to the right, y points upwards and z points towards you
glm::vec3 cameraFront(0.0f, 0.0f, -1.0f);

有了这些,我可以通过这种方式创建一个视图矩阵:

glm::mat4 view;
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);

我希望能够在屏幕上垂直(偏航(和横向(俯仰(移动相机,即向上、向下、向右、向左移动。为此,适当地旋转 cameraFront 矢量和 cameraUp 矢量,然后使用更新的矢量更新视图矩阵就足够了。

我的光标位置回调如下所示:

glm::vec3 rotateAroundAxis(glm::vec3 toRotate, float angle, glm::vec3 axisDirection, glm::vec3 axisPoint) { // angle in radians
toRotate -= axisPoint;
glm::mat4 rotationMatrix(1.0f);
rotationMatrix = glm::rotate(rotationMatrix, angle, axisDirection);
glm::vec4 result = rotationMatrix*glm::vec4(toRotate, 1.0f);
toRotate = glm::vec3(result.x, result.y, result.z);
toRotate += axisPoint;
return toRotate;
}
void mouseCallback(GLFWwindow* window, double xpos, double ypos) {
const float maxPitch = float(M_PI) - float(M_PI) / 180.0f;
glm::vec3 cameraRight = -glm::cross(cameraUp, cameraFront);
float xOffset = xpos - lastX;
float yOffset = ypos - lastY;
lastX = xpos;
lastY = ypos;
float sensitivity = 0.0005f;
xOffset *= sensitivity;
yOffset *= sensitivity;
yaw += xOffset; // useless here
pitch += yOffset;
if (pitch > maxPitch) {
yOffset = 0.0f;
}
if (pitch < -maxPitch) {
yOffset = 0.0f;
}
cameraFront = rotateAroundAxis(cameraFront, -xOffset, cameraUp, cameraPos);
cameraFront = rotateAroundAxis(cameraFront, -yOffset, cameraRight, cameraPos);
cameraUp = rotateAroundAxis(cameraUp, -yOffset, cameraRight, cameraPos);
}

正如我所说,它适用于简单的上下左右相机移动,但是当我开始绕圈或像疯子一样移动鼠标时,相机开始纵向旋转(滚动(。

我试图强制 cameraRight.y = cameraPos.y,以便 cameraRight 矢量不会由于数值错误而向上/向下倾斜,但它不能解决问题。我还尝试添加一个(全局(cameraRight矢量来跟踪它,而不是每次都计算它,因此函数的结尾如下所示:

cameraFront = rotateAroundAxis(cameraFront, -xOffset, cameraUp, cameraPos);
cameraRight = rotateAroundAxis(cameraRight, -xOffset, cameraUp, cameraPos);
cameraFront = rotateAroundAxis(cameraFront, -yOffset, cameraRight, cameraPos);
cameraUp = rotateAroundAxis(cameraUp, -yOffset, cameraRight, cameraPos);

但这并不能解决问题。有什么建议吗?

似乎您的右侧有全局 X 轴,Y 轴深入屏幕,Z 轴向上。和你本地摄像头轴系统类似。 所需的行为是将相机旋转到
其当前位置,鼠标左右移动是围绕全局Z 旋转,向上 dowm 鼠标移动是围绕局部 X 旋转。围绕这些旋转进行一些思考,直到您很好地理解它们,以及为什么一个围绕全局而另一个围绕局部方向。想象一下,一个安全摄像头及其运动来可视化轴系统和旋转。

目标是获取用于定义视图转换的参数lookAt函数。

首先围绕局部X旋转。我们通过反转当前的视图矩阵将这个局部向量转换为全局轴系统,你称之为view

glm::vec3 currGlobalX = glm::normalize((glm::inverse(view) * glm::vec4(1.0, 0.0, 0.0, 0.0)).xyz);

我们不仅需要旋转cameraUp向量,还需要旋转全局坐标中定义的current target,即所谓的cameraPos + cameraFront

cameraUp = rotateAroundAxis(cameraUp, -yOffset, currGlobalX, glm::vec3(0.0f, 0.0f, 0.0f)); //vector, not needed to translate
cameraUp = glm::normalize(cameraUp);
currenTarget = rotateAroundAxis(currenTarget, -yOffset, currGlobalX, cameraPos); //point, need translation

现在绕全局 Z 轴旋转

cameraUp = rotateAroundAxis(cameraUp, -xOffset, glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, 0.0f)); //vector, not needed to translate
cameraUp = glm::normalize(cameraUp);
currenTarget = rotateAroundAxis(currenTarget, -xOffset, glm::vec3(0.0f, 0.0f, 1.0f), cameraPos); //point, need translation

最后,更新view

view = glm::lookAt(cameraPos, currenTarget, cameraUp);