6DOF camera: inverted yaw and roll when orientation changes

Whenever I change the orientation of the camera, yaw and roll become inverted (or correct); the strafing, movement and pitch do remain correct however.

Can you tell what is causing this and how to fix it ?

private Vector3 _cameraOrientation;
private Vector3 _cameraPosition;
private Matrix _matrixProjection;
private Matrix _matrixView;

protected override void Update(GameTime gameTime)
{
if (state.Buttons.Back == ButtonState.Pressed ||
Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
if (state.Buttons.Start == ButtonState.Pressed) _cameraPosition = _cameraOrientation = Vector3.Zero;

var right = state.ThumbSticks.Right;
var left = state.ThumbSticks.Left;

// get position/orientation deltas from gamepad
var position = new Vector3
{
X = left.X,
Y = state.Buttons.A == ButtonState.Pressed ? -1 : state.Buttons.Y == ButtonState.Pressed ? 1 : 0,
Z = -left.Y,
};
var orientation = new Vector3
{
X = -right.Y,
Y = -right.X,
Z = state.Buttons.X == ButtonState.Pressed ? -1 : state.Buttons.B == ButtonState.Pressed ? 1 : 0
};

// update position according orientation
_cameraOrientation += orientation;
var cameraReference = Vector3.Forward;
var cameraRotation =
_cameraPosition += Vector3.Transform(position, cameraRotation);

// update matrices
var cameraPosition = _cameraPosition;
var cameraTransformedReference = Vector3.Transform(cameraReference, cameraRotation);
var cameraTarget = cameraPosition + cameraTransformedReference;
var cameraUpVector = Vector3.Transform(Vector3.Up, cameraRotation); // Vector3.Up;
_matrixView = Matrix.CreateLookAt(cameraPosition, cameraTarget, cameraUpVector);

• I've just started going through the code. If you keep this algorithm, I'd recommend that you rename variables like position to velocity, positionDelta, or anything else that is more indicative of their purposes. – Jon May 4 '15 at 0:04
• Also, you can accumulate just the rotation, first, and then determine the correct movement direction from cameraRotation; i.e. cameraRotation.Forward, cameraRotation.Left. Both of the directions returned are relative to the stored rotation, not "the world". So, If (left.X != 0) _cameraPosition += cameraRotation.Right * left.X; – Jon May 4 '15 at 0:05
• Unconfirmed, but I think your problem may be order-of-operations; i.e. Matrix.CreateRotationX creates "pitch". You are applying X, then Y, then Z which is Pitch, then Yaw, then Roll. Each of the matrices you are creating is relative to world-space ("Up" is +Y). When you pitch the camera past 90 degrees (first), camera-space "Up" becomes world-space "Down". – Jon May 4 '15 at 0:11
• (Sorry Mods; I'll compile all of my comments into an answer after a little feedback from the OP) -- You are also starting your camera at Vector3.Forward, looking toward (0,0); that means that, initially, Camera.Forward is Vector3.Backward. Positive rotations are clock-wise, relative to the axis being twisted which is why starting at Vector3.Forward is an intuitive solution. The other and, more common, intuitive solution is starting at Vector3.Backward, looking toward (0,0), and inverting your sticks' pitch values. – Jon May 4 '15 at 0:23