EDIT: I've uploaded a video to youtube that shows what's happening now. When I rotate 60 degrees (pitch or yaw) then I get strange shaking. As you can see, the mouse input is working fine (no unwanted roll, and pitch/yaw occurs locally after a roll)
I'm trying to implement a flight simulator camera in an OpenGL game I'm making. I've followed what is mentioned at the bottom of this page and my resulting computation of the view matrix is:
my = my * 0.001f; //per-frame delta
mx = mx * 0.001f; //per-frame delta
glm::vec3 pitchAxis = glm::normalize( glm::cross( cameraDirection, cameraUp ) );
glm::vec3 yawAxis = glm::normalize( cameraUp );
glm::quat pitchQuat = glm::angleAxis( (float)my, pitchAxis );
glm::quat yawQuat = glm::angleAxis( (float)mx, yawAxis );
glm::quat comp = yawQuat * pitchQuat;
cameraDirection = cameraDirection * comp;
pitchAxis = glm::cross( cameraDirection, cameraUp );
cameraUp = glm::cross( pitchAxis, cameraDirection );
return glm::lookAt( cameraPosition, cameraPosition + cameraDirection, cameraUp );
where I calculate an incremental pitch/yaw quaternion based on mouse input and then apply that to the camera's direction. Then I re-calculate the camera's Up vector based on a new pitch axis using the cross-product.
When I test it I don't get any camera locks at 90 degrees but if I pitch and yaw then the camera also starts to roll (not wanted).
The accepted answer in this post suggests to use global pitch/yaw/roll value, not just the delta values I used above. So I went ahead and tried to do that:
//using left-handed coordinate system
glm::vec3 yawAxis = glm::vec3( 0.0f, 1.0f, 0.0f );
glm::vec3 pitchAxis = glm::vec3( -1.0f, 0.0f, 0.0f );
//glm::vec3 rollAxis = glm::vec3( 0.0f, 0.0f, -1.0f );
glm::quat yawQuat = glm::angleAxis( yaw, yawAxis );
glm::quat pitchQuat = glm::angleAxis( pitch, pitchAxis );
glm::quat composite = yawQuat * pitchQuat;
cameraDirection = composite * glm::vec3( 0.0f, 0.0f, -1.0f );
glm::quat rollQuat = glm::angleAxis( roll, cameraDirection );
cameraUp = rollQuat * glm::vec3( 0.0f, 1.0f, 0.0f );
return glm::lookAt( cameraPosition, cameraPosition + cameraDirection, cameraUp );
where yaw and pitch are incremented each frame if the mouse moves. I can still look around nicely but if:
- I pitch 90 degrees up or down and keep going it seems like the camera flips/inverts.
- I roll first, the pitch/yaw is still about the global axes (which is expected from the code) instead of the local camera axes which I think it should be and that's why I tried the first method...
I think the first issue could be fixed with a case that flips the global pitchAxis when the pitch > 90 degrees or <-90 degrees. But I'm stuck with fixing the second issue as my intuition keeps trying to use the first method I tried.
Is there a fundamental flaw with how I'm going about implementing this camera or am I missing something obvious?