How to: Rotate and Move a Camera

This example demonstrates how to rotate and move the camera by creating a view matrix with CreateLookAt.

The camera's position and orientation are controlled by setting a view Matrix for the camera to use. In this example, it is assumed the camera will move frequently, so the view Matrix is created and set every time Game.Draw is called. Similarly, it is assumed that the projection Matrix may change from frame to frame for effects such as zooming. The example assumes a model has been added to the project as described in How to: Render a Model.

To rotate and move the camera

  1. Determine the camera's position in world coordinates.

  2. Determine the reference Vector3 that rotation of the camera is relative to. The direction should not change during the game and will usually be (0, 0, 1) or (0, 0, −1).

    // Set the direction the camera points without rotation.
    Vector3 cameraReference = new Vector3( 0, 0, 10 );
    
  3. Create a rotation Matrix representing the direction the camera is facing. A rotation Matrix representing rotation around the y-axis would be created with CreateRotationY.

    Matrix rotationMatrix = Matrix.CreateRotationY( avatarYaw );
    
  4. Transform a copy of the reference vector using Transform and the rotation Matrix.

    // Create a vector pointing the direction the camera is facing.
    Vector3 transformedReference = Vector3.Transform( cameraReference, rotationMatrix );
    
  5. Add the camera's current position to the transformed direction vector. The result is the position that the camera is looking toward.

    // Calculate the position the camera is looking at.
    Vector3 cameraLookat = cameraPosition + transformedReference;
    
  6. Create a new view Matrix using CreateLookAt. Pass CreateLookAt the camera's current position and the transformed direction vector. The third parameter of CreateLookAt is the up direction of the camera and will usually be Vector3.Up (0, 1, 0). The view Matrix controls how world coordinate values are transformed to camera coordinates.

    view = Matrix.CreateLookAt( cameraPosition, cameraLookat, new Vector3( 0.0f, 1.0f, 0.0f ) );
    
  7. Create a new projection Matrix with CreatePerspectiveFieldOfView. The projection Matrix controls how camera coordinate values are transformed to screen coordinates. The first parameter is the field of view of the projection Matrix expressed in radians. A typical field of view of 45 degrees would be expressed as pi/4 radians. The second parameter is the aspect ratio of the projection Matrix and corrects for the difference in width and height of a viewspace. The third and fourth parameters specify the near and far distances that objects will be visible in.

    // Set field of view of the camera in radians (pi/4 is 45 degrees).
    static float viewAngle = MathHelper.PiOver4;
    
    // Set distance from the camera of the near and far clipping planes.
    //static float nearClip = 5.0f;
    static float nearClip = 1.0f;
    static float farClip = 2000.0f;
    
    Viewport viewport = graphics.GraphicsDevice.Viewport;
    float aspectRatio = (float)viewport.Width / (float)viewport.Height;
    
    proj = Matrix.CreatePerspectiveFieldOfView( viewAngle, aspectRatio, nearClip, farClip );
    
  8. Loop through each model in the world drawing it as described in How to: Render a Model using the projection matrix and view matrix created above. For the world matrix, use Matrix.CreateTranslation and the object's current position in the world.

    void DrawBoxes()
    {
        for (int z = 0; z < 9; z++)
        {
            for (int x = 0; x < 9; x++)
            {
                DrawModel( box, Matrix.CreateTranslation( x * 60, 0, z * 60 ), boxTexture );
            }
        }
    }
    
    void DrawModel( Model model, Matrix world, Texture2D texture )
    {
        foreach (ModelMesh mesh in model.Meshes)
        {
            foreach (BasicEffect be in mesh.Effects)
            {
                be.Projection = proj;
                be.View = view;
                be.World = world;
                be.Texture = texture;
                be.TextureEnabled = true;
            }
            mesh.Draw();
        }
    }
    
//Game1.cs
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;

class Game1 : Microsoft.Xna.Framework.Game
{
    ContentManager content;
    GraphicsDeviceManager graphics;

    Matrix view;
    Matrix proj;

    Model box;
    Texture2D boxTexture;
    Texture2D avatarTexture;

    // Set the avatar position and rotation variables.
    Vector3 avatarPosition = new Vector3( 0, 0, -20 );

    Vector3 avatarHeadOffset = new Vector3( 0, 10, 0 );

    float avatarYaw;

    // Set the direction the camera points without rotation.
    Vector3 cameraReference = new Vector3( 0, 0, 10 );

    Vector3 thirdPersonReference = new Vector3( 0, 500, -500 );

    // Set rates in world units per 1/60th second (the default fixed-step interval).
    float rotationSpeed = 1f / 60f;
    //float forwardSpeed = 500f / 60f;
    float forwardSpeed = 50f / 60f;

    // Set field of view of the camera in radians (pi/4 is 45 degrees).
    static float viewAngle = MathHelper.PiOver4;

    // Set distance from the camera of the near and far clipping planes.
    //static float nearClip = 5.0f;
    static float nearClip = 1.0f;
    static float farClip = 2000.0f;

    // Set the camera state, avatar's center, first-person, third-person.
    int cameraState;
    bool cameraStateKeyDown;


    public Game1()
    {
        graphics = new GraphicsDeviceManager( this );
        content = new ContentManager( Services );
    }

    protected override void Initialize()
    {
        // TODO: Add your initialization logic here.

        base.Initialize();
    }

    protected override void LoadGraphicsContent( bool loadAllContent )
    {
        if (loadAllContent)
        {
            box = content.Load<Model>( "box" );
            boxTexture = content.Load<Texture2D>( "boxtexture" );
            avatarTexture = content.Load<Texture2D>( "avatartexture" );
        }
    }

    protected override void UnloadGraphicsContent( bool unloadAllContent )
    {
        if (unloadAllContent)
        {
            content.Unload();
        }
    }

    protected override void Update( GameTime gameTime )
    {
        // Allows the default game to exit on Xbox 360 and Windows.
        if (GamePad.GetState( PlayerIndex.One ).Buttons.Back == ButtonState.Pressed)
            this.Exit();

        GetCurrentCamera();
        UpdateAvatarPosition();

        base.Update( gameTime );
    }

    protected override void Draw( GameTime gameTime )
    {
        graphics.GraphicsDevice.Clear( Color.CornflowerBlue );

        switch (cameraState)
        {
            default:
            case 0:
                UpdateCamera();
                break;
            case 1:
                UpdateCameraFirstPerson();
                break;
            case 2:
                UpdateCameraThirdPerson();
                break;
        }
        //graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
        DrawBoxes();
        Matrix World = Matrix.CreateRotationY( avatarYaw ) * Matrix.CreateTranslation( avatarPosition );
        if (cameraState == 2)
        {
            DrawModel( box, World, avatarTexture );
        }

        base.Draw( gameTime );
    }


    // Update the position and direction of the avatar.
    void UpdateAvatarPosition()
    {
        KeyboardState keyboardState = Keyboard.GetState();
        GamePadState currentState = GamePad.GetState( PlayerIndex.One );

        if (keyboardState.IsKeyDown( Keys.Left ) || (currentState.DPad.Left == ButtonState.Pressed))
        {
            // Rotate left.
            avatarYaw += rotationSpeed;
        }
        if (keyboardState.IsKeyDown( Keys.Right ) || (currentState.DPad.Right == ButtonState.Pressed))
        {
            // Rotate right.
            avatarYaw -= rotationSpeed;
        }
        if (keyboardState.IsKeyDown( Keys.Up ) || (currentState.DPad.Up == ButtonState.Pressed))
        {
            Matrix forwardMovement = Matrix.CreateRotationY( avatarYaw );
            Vector3 v = new Vector3( 0, 0, forwardSpeed );
            v = Vector3.Transform( v, forwardMovement );
            avatarPosition.Z += v.Z;
            avatarPosition.X += v.X;
        }
        if (keyboardState.IsKeyDown( Keys.Down ) || (currentState.DPad.Down == ButtonState.Pressed))
        {
            Matrix forwardMovement = Matrix.CreateRotationY( avatarYaw );
            Vector3 v = new Vector3( 0, 0, -forwardSpeed );
            v = Vector3.Transform( v, forwardMovement );
            avatarPosition.Z += v.Z;
            avatarPosition.X += v.X;
        }
    }
    void GetCurrentCamera()
    {
        KeyboardState keyboardState = Keyboard.GetState();
        GamePadState currentState = GamePad.GetState( PlayerIndex.One );

        // Toggle the state of the camera.
        if (keyboardState.IsKeyDown( Keys.Tab ) || (currentState.Buttons.LeftShoulder == ButtonState.Pressed))
        {
            cameraStateKeyDown = true;
        }
        else if (cameraStateKeyDown == true)
        {
            cameraStateKeyDown = false;
            cameraState += 1;
            cameraState %= 3;
        }
    }

    void UpdateCamera()
    {
        // Calculate the camera's current position.
        Vector3 cameraPosition = avatarPosition;

        Matrix rotationMatrix = Matrix.CreateRotationY( avatarYaw );

        // Create a vector pointing the direction the camera is facing.
        Vector3 transformedReference = Vector3.Transform( cameraReference, rotationMatrix );

        // Calculate the position the camera is looking at.
        Vector3 cameraLookat = cameraPosition + transformedReference;

        // Set up the view matrix and projection matrix.
        view = Matrix.CreateLookAt( cameraPosition, cameraLookat, new Vector3( 0.0f, 1.0f, 0.0f ) );

        Viewport viewport = graphics.GraphicsDevice.Viewport;
        float aspectRatio = (float)viewport.Width / (float)viewport.Height;

        proj = Matrix.CreatePerspectiveFieldOfView( viewAngle, aspectRatio, nearClip, farClip );
    }


    void UpdateCameraFirstPerson()
    {
        Matrix rotationMatrix = Matrix.CreateRotationY( avatarYaw );


        // Transform the head offset so the camera is positioned properly relative to the avatar.
        Vector3 headOffset = Vector3.Transform( avatarHeadOffset, rotationMatrix );

        // Calculate the camera's current position.
        Vector3 cameraPosition = avatarPosition + headOffset;

        // Create a vector pointing the direction the camera is facing.
        Vector3 transformedReference = Vector3.Transform( cameraReference, rotationMatrix );

        // Calculate the position the camera is looking at.
        Vector3 cameraLookat = transformedReference + cameraPosition;

        // Set up the view matrix and projection matrix.

        view = Matrix.CreateLookAt( cameraPosition, cameraLookat, new Vector3( 0.0f, 1.0f, 0.0f ) );

        Viewport viewport = graphics.GraphicsDevice.Viewport;
        float aspectRatio = (float)viewport.Width / (float)viewport.Height;

        proj = Matrix.CreatePerspectiveFieldOfView( viewAngle, aspectRatio, nearClip, farClip );

    }

    void UpdateCameraThirdPerson()
    {
        Matrix rotationMatrix = Matrix.CreateRotationY( avatarYaw );

        // Create a vector pointing the direction the camera is facing.
        Vector3 transformedReference = Vector3.Transform( thirdPersonReference, rotationMatrix );

        // Calculate the position the camera is looking from.
        Vector3 cameraPosition = transformedReference + avatarPosition;

        // Set up the view matrix and projection matrix.
        view = Matrix.CreateLookAt( cameraPosition, avatarPosition, new Vector3( 0.0f, 1.0f, 0.0f ) );

        Viewport viewport = graphics.GraphicsDevice.Viewport;
        float aspectRatio = (float)viewport.Width / (float)viewport.Height;

        proj = Matrix.CreatePerspectiveFieldOfView( viewAngle, aspectRatio, nearClip, farClip );

    }


    void DrawBoxes()
    {
        for (int z = 0; z < 9; z++)
        {
            for (int x = 0; x < 9; x++)
            {
                DrawModel( box, Matrix.CreateTranslation( x * 60, 0, z * 60 ), boxTexture );
            }
        }
    }

    void DrawModel( Model model, Matrix world, Texture2D texture )
    {
        foreach (ModelMesh mesh in model.Meshes)
        {
            foreach (BasicEffect be in mesh.Effects)
            {
                be.Projection = proj;
                be.View = view;
                be.World = world;
                be.Texture = texture;
                be.TextureEnabled = true;
            }
            mesh.Draw();
        }
    }

}

See Also

How to: Render a Model