Arcball摄像机以90度方位角反转 [英] Arcball camera inverting at 90 deg azimuth
问题描述
我正在尝试实现一个Arcball风格的相机.我使用glm :: lookAt来使相机对准目标,然后使用方位角/倾斜角将其围绕球体表面移动以旋转视图.
I'm attempting to implement an arcball style camera. I use glm::lookAt to keep the camera pointed at a target, and then move it around the surface of a sphere using azimuth/inclination angles to rotate the view.
我遇到一个问题,当方位角接近90度时,视图会上下颠倒.
I'm running into an issue where the view gets flipped upside down when the azimuth approaches 90 degrees.
以下是相关代码:
-
获取投影并查看矩阵.在主循环中运行
Get projection and view martrices. Runs in the main loop
void Visual::updateModelViewProjection()
{
model = glm::mat4();
projection = glm::mat4();
view = glm::mat4();
projection = glm::perspective
(
(float)glm::radians(camera.Zoom),
(float)width / height, // aspect ratio
0.1f, // near clipping plane
10000.0f // far clipping plane
);
view = glm::lookAt(camera.Position, camera.Target, camera.Up);
}
鼠标移动事件,用于相机旋转
Mouse move event, for camera rotation
void Visual::cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
{
if (leftMousePressed)
{
...
}
if (rightMousePressed)
{
GLfloat xoffset = (xpos - cursorPrevX) / 4.0;
GLfloat yoffset = (cursorPrevY - ypos) / 4.0;
camera.inclination += yoffset;
camera.azimuth -= xoffset;
if (camera.inclination > 89.0f)
camera.inclination = 89.0f;
if (camera.inclination < 1.0f)
camera.inclination = 1.0f;
if (camera.azimuth > 359.0f)
camera.azimuth = 359.0f;
if (camera.azimuth < 1.0f)
camera.azimuth = 1.0f;
float radius = glm::distance(camera.Position, camera.Target);
camera.Position[0] = camera.Target[0] + radius * cos(glm::radians(camera.azimuth)) * sin(glm::radians(camera.inclination));
camera.Position[1] = camera.Target[1] + radius * sin(glm::radians(camera.azimuth)) * sin(glm::radians(camera.inclination));
camera.Position[2] = camera.Target[2] + radius * cos(glm::radians(camera.inclination));
camera.updateCameraVectors();
}
cursorPrevX = xpos;
cursorPrevY = ypos;
}
计算相机方向矢量
Calculate camera orientation vectors
void updateCameraVectors()
{
Front = glm::normalize(Target-Position);
Right = glm::rotate(glm::normalize(glm::cross(Front, {0.0, 1.0, 0.0})), glm::radians(90.0f), Front);
Up = glm::normalize(glm::cross(Front, Right));
}
我很确定这与我计算相机正确向量的方式有关,但是我不知道该如何补偿.
I'm pretty sure it's related to the way I calculate my camera's right vector, but I cannot figure out how to compensate.
以前有人遇到过吗?有什么建议?
Has anyone run into this before? Any suggestions?
推荐答案
使用lookAt
旋转相机是一个常见的错误.你不应该.向后/向右/向上方向是视图矩阵的列.如果已经有了它们,那么甚至不需要lookAt
,它会尝试重做一些计算.另一方面,lookAt
并没有帮助您首先找到这些向量.
It's a common mistake to use lookAt
for rotating the camera. You should not. The backward/right/up directions are the columns of your view matrix. If you already have them then you don't even need lookAt
, which tries to redo some of your calculations. On the other hand, lookAt
doesn't help you in finding those vectors in the first place.
相反,首先将视图矩阵构建为平移和旋转的组合,然后从其列中提取这些矢量:
Instead build the view matrix first as a composition of translations and rotations, and then extract those vectors from its columns:
void Visual::cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
{
...
if (rightMousePressed)
{
GLfloat xoffset = (xpos - cursorPrevX) / 4.0;
GLfloat yoffset = (cursorPrevY - ypos) / 4.0;
camera.inclination = std::clamp(camera.inclination + yoffset, -90.f, 90.f);
camera.azimuth = fmodf(camera.azimuth + xoffset, 360.f);
view = glm::mat4();
view = glm::translate(view, glm::vec3(0.f, 0.f, camera.radius)); // add camera.radius to control the distance-from-target
view = glm::rotate(view, glm::radians(camera.inclination + 90.f), glm::vec3(1.f,0.f,0.f));
view = glm::rotate(view, glm::radians(camera.azimuth), glm::vec3(0.f,0.f,1.f));
view = glm::translate(view, camera.Target);
camera.Right = glm::column(view, 0);
camera.Up = glm::column(view, 1);
camera.Front = -glm::column(view, 2); // minus because OpenGL camera looks towards negative Z.
camera.Position = glm::column(view, 3);
view = glm::inverse(view);
}
...
}
然后从updateModelViewProjection
和updateCameraVectors
中删除计算视图和方向矢量的代码.
Then remove the code that calculates view and the direction vectors from updateModelViewProjection
and updateCameraVectors
.
免责声明:此代码未经测试.您可能需要在某处固定减号,操作顺序,或者约定可能不匹配(Z向上或Y向上等等).
Disclaimer: this code is untested. You might need to fix a minus sign somewhere, order of operations, or the conventions might mismatch (Z is up or Y is up, etc...).
这篇关于Arcball摄像机以90度方位角反转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!