I am using an FPS-like camera, and it uses quaternions. But, whenever I try looking up and then sideways, it tilts, and sometimes it can turn upside down. How can I fix this?
You could decompose your quaternion into a yaw/pitch/roll set of angles, but that's overkill usually.
Instead of composing your quaternions like this:
cameraOrientation = cameraOrientation * framePitch * frameYaw;
cameraOrientation = framePitch * cameraOrientation * frameYaw;
It will then never generate tilt/roll and is equivalent to storing yaw and pitch separately
This is a problem I had for a while, and I couldn't find any answers for, so I thought I would post it here.
It is actually quite simple. How you are most likely doing the rotations is like this:
currentDirection * newRotation;
But, doing it like this doesn't work either.
newRotation * currentDirection;
What you have to do, is do it in the first order for the up and down rotations, and in the second order for the sideways rotations.
For me, it was like this:
if (keyboard.IsKeyDown(Keys.Up)) Direction = Direction * Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), TurnSpeed); if (keyboard.IsKeyDown(Keys.Down)) Direction = Direction * Quaternion.CreateFromAxisAngle(new Vector3(-1, 0, 0), TurnSpeed); if (keyboard.IsKeyDown(Keys.Left)) Direction = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, 1), TurnSpeed) * Direction; if (keyboard.IsKeyDown(Keys.Right)) Direction = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, -1), TurnSpeed) * Direction;
For a reason why, the first way has the rotation relative to the current sideways direction, which you want for up and down, but you don't want that for the sideways rotations, which is why the second order is needed.
For an FPS camera you usually don't want roll and are limited to +/- 90 degrees pitch, so I'd just keep track of the current state using yaw and pitch angles. The full power of quaternions isn't really helpful for this.
You can still convert the yaw/pitch angles to and from quaternions in case you want to transition between the FPS camera and animated cameras using quaternion keyframe interpolation, or something like that.
Another simple trick is to put the camera in a GameObject, and have the Yaw rotation control the game object, while the child camera is configured with the Pitch coordinates:
playerCameraHolder.transform.Rotate(0, rotationYaw, 0); playerCamera.transform.Rotate(rotationPitch, 0, 0);