OpenGL飞行模拟器风格的相机旋转无法正常工作

时间:2015-03-22 21:14:01

标签: opengl camera quaternions

我正在尝试创建一个像飞行模拟器(因为我正在制作飞行模拟器)相机的相机 - 我希望能够执行俯仰,偏航和滚动以及翻译。翻译工作得很好,但轮换导致我非常严重的头痛。

使用四元数,使用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;

如果您想查看我的相机课程的所有代码,您可以在我的Google云端硬盘中找到它:

http://goo.gl/FFMPa0

1 个答案:

答案 0 :(得分:1)

您正在经历的四元数相机正常运行。如果你想避免这个问题,只需在偏航时使用固定的向上矢量,但要注意,当你直视时会出现异常情况。您可能希望明确处理它。并且总是通过将静态视图与视图交叉来重建视图矩阵。

编辑:

以下是一步一步:

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

    // 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也可以)。

当然,每一帧重复一步。