# XNA Framework and looking around relative to the world instead of camera?

So I've been toying around with creating a game in the XNA framework. A great place to start is simply being able to move and walk around.

I kinda have looking around...

I start off with the camera position/direction as follows:

cameraDirection = Matrix.CreateLookAt(new Vector3(0, 0, 1.5f), new Vector3(0, 1, -1), Vector3.Up);


I also have a small cube rendered in a static location, on which I plan to walk around. I'm manipulating the cameraDirection from a controller as follows:

GamePadState one = GamePad.GetState(PlayerIndex.One);
if (one.Buttons.Back == ButtonState.Pressed)
this.Exit();
if (one.ThumbSticks.Right.Length() > .1f) {//Deadzone, must push stick at least 10%
cameraDirection *= Matrix.CreateRotationY((float)(gameTime.ElapsedGameTime.TotalMilliseconds * (.002 * one.ThumbSticks.Right.X)));
cameraDirection *= Matrix.CreateRotationX((float)(gameTime.ElapsedGameTime.TotalMilliseconds * (-.002 * one.ThumbSticks.Right.Y)));
}


And at first this appeared to work. Then I realized that the X and Y axes are relative to the camera's current orientation. If I turn left and right while looking straight forward, that appears to work. If I look straight down and then turn left and right, I'm rotating along a different axis. I want to look around in relation to the world's axes instead of the camera's... How can I do this?

First, you should be aware that there really is no such thing as a camera. There is only the camera view and projection matricies, which transform all the vertices in the world into a position relative to the camera.

That said, your problem is due to the order of transformations applied to the camera view matrix.

Instead of applying transformations to the camera view matrix over and over, which results in weird skewing of the view, and other fun unwanted stuff (like gimbal lock, as 3nixios pointed out).

The order of matrix multiplication matters. If you multiply by x and then by y, you get a different result from y by x. So multiplying many times in a row by different amounts along different axis produces a different result from what you were expecting.

Store yaw, pitch (and roll) in 3 separate floats in your camera. Store position in a Vector3.

Then at each camera update, do this:

cameraView = Matrix.CreateRotationX(Pitch);
cameraView *= Matrix.CreateRotationY(Yaw);
cameraView *= Matrix.CreateTranslation(Position);


Remember that the order of those multiplications matters!

Then just add to yaw/pitch like this:

float elapsed = (float)(gameTime.ElapsedGameTime.TotalMilliseconds;
Yaw += elapsed * (.002 * one.ThumbSticks.Right.X));

if(Yaw > (MathHelper.Pi * 2)){
Yaw -= MathHelper.Pi * 2;
}


(And the same for pitch and roll.)

Add to position like this:

// Move up by 5 units per second.
Position += new Vector3(0, 1, 0) * elapsed * 5.0f;


This way you are recreating the camera view from yaw and pitch each frame, which will help you understand what is going on, and avoid incorrect transformations. It's also about equal in runtime efficiency, if you're worried about that.

• When using Euler angles for rotations, beware of Gimbal Lock! – Jonathan Connell Jun 9 '11 at 9:21
• You can't gimbal lock with this setup. I'm storing yaw and pitch as floats from which a new matrix is created each frame. Gimbal lock can occur in the askers setup, where he uses a single matrix, multiplied by new transformation matricies over and over. My answer avoids that problem. – Olhovsky Jun 9 '11 at 9:25
• 3nixios: See this question about gimbal lock that is similar to my answer's method. stackoverflow.com/questions/1225377/will-this-cause-gimbal-lock – Olhovsky Jun 9 '11 at 9:28
• @Olhovsky Indeedy! I thought it wise to raise the subject, altough I hadn't fully read your answer, my bad! – Jonathan Connell Jun 9 '11 at 9:44
• Your answer makes sense, Olhovsky, and personally I like it as a better model of position/direction than a matrix. I'm at work now, but when I get home I'll try your changes and report back. – Corey Ogburn Jun 9 '11 at 14:48