OpenGL 飞行模拟器风格的相机旋转不起作用

OpenGL flight simulator styled camera rotations not working

我正在尝试创建一个像飞行模拟器一样工作的相机(因为我正在制作飞行模拟器)相机 - 我希望能够执行俯仰、偏航和滚动以及平移。翻译工作完美,但轮换让我非常头疼。

旋转是使用四元数计算的,使用 GLM,如下所示:

// Fuck quaternions
glm::fquat pitchQuat(cos(TO_RADIANS(pitch / 2.0f)), m_rightVector * (float)sin(TO_RADIANS(pitch / 2.0f)));
glm::fquat yawQuat(cos(TO_RADIANS(yaw / 2.0f)), m_upVector * (float)sin(TO_RADIANS(yaw / 2.0f)));
glm::fquat rollQuat(cos(TO_RADIANS(roll / 2.0f)), m_direction * (float)sin(TO_RADIANS(roll / 2.0f)));

m_rotation = yawQuat * pitchQuat * rollQuat;

m_direction = m_rotation * m_direction * glm::conjugate(m_rotation);
m_upVector = m_rotation * m_upVector * glm::conjugate(m_rotation);
m_rightVector = glm::cross(m_direction, m_upVector);

如果我单独计算俯仰或滚动或偏航,一切正常,但是,一旦我引入另一个旋转,一切都会出错。这个视频应该足以告诉你出了什么问题:

https://www.youtube.com/watch?v=jlklem6t68I&feature=youtu.be

翻译工作正常,旋转不是那么多。当我以圆周运动(即偏航和俯仰旋转)移动鼠标时,房子慢慢开始倒转。您可能已经在视频中注意到,旋转会导致房屋伸展,这也是不需要的。

我不知道哪里出了问题。 C谁能解释一下我如何创建一个具有俯仰、偏航和滚动功能的相机?

如果有任何帮助,视图矩阵是使用以下方法计算的:

m_viewMatrix = glm::lookAt(m_position, m_position + m_direction, m_upVector);

投影矩阵的计算方式为:

float t = tan(fov * 3.14159 / 360.0) * nPlane;

float r = aspectRatio * t;
float l = aspectRatio * -t;

m_projectionMatrix[0][0] = (2 * nPlane) / (r - l);
m_projectionMatrix[0][2] = (r + l) / (r - l);
m_projectionMatrix[1][1] = (2 * nPlane) / (t + t);
m_projectionMatrix[1][2] = (t - t) / (t + t);
m_projectionMatrix[2][2] = (nPlane + fPlane) / (nPlane - fPlane);
m_projectionMatrix[2][3] = (2 * fPlane * nPlane) / (nPlane - fPlane);
m_projectionMatrix[3][2] = -1;

如果您想查看我的所有相机代码 class,您可以在我的 Google 驱动器中找到它:

http://goo.gl/FFMPa0

您遇到的问题对于四元数相机来说是正常的。如果你想避免这个问题,只需在偏航时使用一个固定的向上矢量,但要注意,当你直视时会有一个例外。您可能想要明确地处理它。并始终通过使用此静态向上交叉视图来重建您的视图矩阵。

编辑:

这是一步一步的:

首先,计算你围绕静态向上矢量的旋转,同时你的方向像往常一样从视图中提取(右边是十字):

    // Quaternions
    glm::fquat pitchQuat(cos(TO_RADIANS(pitch / 2.0f)), cross(m_direction,vec3(0,1,0) * (float)sin(TO_RADIANS(pitch / 2.0f)));
    glm::fquat yawQuat(cos(TO_RADIANS(yaw / 2.0f)), vec3(0,1,0) * (float)sin(TO_RADIANS(yaw / 2.0f)));
    glm::fquat rollQuat(cos(TO_RADIANS(roll / 2.0f)), m_direction * (float)sin(TO_RADIANS(roll / 2.0f)));
    m_rotation = yawQuat * pitchQuat * rollQuat;

然后使用四元数重建视图,如here所示(lm::lookAt 也可以)。

而且,当然 - 每帧重复步骤。