Search code examples
c++glm-math

Opengl camera that can move beyond 90 degrees pitch


I'm trying to create something like this: https://www.youtube.com/watch?v=QjIPocx7auA and wanted to ask how do I approach creating camera view matrix that can freely look beyond 90 degrees pitch? Is it possible to do using euler angles without encountering gimbal lock? Or do I have to use quaternions?

I'm using glm library for calculations and I tried doing following using quaternions:

glm::vec3 xAxis = {1.0, 0.0, 0.0};
glm::vec3 yAxis = {0.0, 1.0, 0.0};
glm::vec3 zAxis = {0.0, 0.0, 1.0};
glm::quat quatPitch;
quatPitch.w = glm::cos(glm::radians( pitch)/2.0f);
quatPitch.x = (glm::sin(glm::radians(pitch)/2.0f) * xAxis).x;
quatPitch.y = (glm::sin(glm::radians(pitch)/2.0f) * xAxis).y;
quatPitch.z = (glm::sin(glm::radians(pitch)/2.0f) * xAxis).z;
glm::quat quatYaw;
quatYaw.w = glm::cos(glm::radians(yaw)/2.0f);
quatYaw.x = (glm::sin(glm::radians(yaw)/2.0f) * yAxis).x;
quatYaw.y = (glm::sin(glm::radians(yaw)/2.0f) * yAxis).y;
quatYaw.z = (glm::sin(glm::radians(yaw)/2.0f) * yAxis).z;

view = glm::toMat4(glm::normalize(quatPitch * quatYaw));`

it kinda works but I'm not really sure if this even solves gimbal lock. I'm also struggling with rotating xAxis and yAxis along with camera so that xAxis is camera right, yAxis camera Up and zAxis camera front but I haven't found any way to do this. Am I even doing this right?


Solution

  • The terms "pitch" and "yaw" already assume that you specify your orientation using Euler angles; which brings all the problems of Euler angles like the gimbal lock at pitch=90°. Note that it doesn't prevent you from specifying pitches higher than 90°, as this is not what gimbal lock is about. Also going through quaternions as an intermediary step is pointless, since your problem is in the way you parametrize your orientation in the first place rather than the way you calculate it from those parameters.

    To implement a 3d flight-simulator like the one in the linked video, you'd keep the orientation as a quaternion (or a rotation matrix), and apply the rotations in response to user input. E.g. if the user "pitches up" you'll apply a rotation around the right vector to the current orientation. In such a setup you won't have a state for the "current pitch". To recover the current pitch (e.g. for a HUD showing the pitch) you'd calculate it based on the forward vector: pitch = atan2(forward.z, sqrt(forward.x*forward.x + forward.y*forward.y)). The forward/right/up vectors (relative to the plane reference frame) can be recovered from its orientation matrix.