This is the code I use to control my (first person) camera's movement and rotation. Translation successfully keeps orientation in mind, so that up and left and such are always in the expected directions, and 'mouselook' controlling rotation around the Y (yaw) and X (pitch) axes starts out working fine as well.
My problems are two-fold;
First, rotating around the Y and X axes slowly builds up rotational drift around the Z axis. Now what I think I need to do to correct this is to keep track of an additional 'up' vector, and to rotate the quaternion so that the camera's up direction always coincides with this up vector (which would only change when intended, instead of by drift). But I have no idea how to go about doing this.
The second problem is more clearly a bug. When rotating around the Y (yaw) axis, the rotation around the X (pitch) axis starts to freak out. At Y 180 degrees, the up and down motion of the camera's pitching are precisely inverted. And at 90 degree Y angles from the starting orientation, it's as if pitch has become roll instead, rotating around the Z axis.
So, how do I 'roll up', and what's going on with the pitching?
glm::quat mOrientationQuaternion;
glm::vec3 mPositionVector;
glm::mat4 mViewMatrix;
/*
* Takes a translation value for each axis, turns it into a vector, then
* rotates that vector by the current orientation in the quaternion, before
* adding the result to the position vector.
*/
void Camera::translate(float x, float y, float z)
{
glm::vec3 translation(x, y, z);
translation = translation * mOrientationQuaternion;
mPositionVector += translation;
}
/*
* Takes three angles in degrees, and creates a quaternion via an
* intermediate vector to represent their rotations. Then the orientation
* quaternion is multiplied by this new rotation quaternion to get the new
* orientation.
*/
void Camera::rotate(float x, float y, float z)
{
glm::vec3 angles(glm::radians(-x), glm::radians(y), glm::radians(z));
glm::quat rotation(angles);
mOrientationQuaternion = glm::normalize(mOrientationQuaternion * rotation);
}
/*
* Creates the view matrix from the orientation quaternion, then translates
* it by the position vector.
*/
void Camera::buildViewMatrix()
{
mViewMatrix = glm::mat4_cast(mOrientationQuaternion);
mViewMatrix = glm::translate(mViewMatrix, mPositionVector);
}