Simple Camera Movement

(adapted & extended from MSDN's 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.

Initial Setup

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

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

    float avatarYaw=MathHelper.PiOver4;
    float actualYaw=MathHelper.PiOver4;


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

    Vector3 thirdPersonReference = new Vector3( 0, 1000, -10000 );

    // Set rates in world units per 1/60th second (the default fixed-step interval).
    float rotationSpeed = 2f / 60f;
    //float forwardSpeed = 500f / 60f;
    float forwardSpeed = 2000f / 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 = 50000.0f;

Controling avatar position [UpdateAvatarPosition()]

In this example, it is assumed that the user can pan left and right, and move forward and back. the angle of pan is stored in avatarYaw, this represents an angle about the Y-axis.

 

Forward and back motion along direction of travel is controled by the avatarPosition vector.

if (keyboardState.IsKeyDown( Keys.Down ) ))
{ //create a vector along z-axis Vector3 v = new Vector3( 0, 0, -forwardSpeed ); // rotate this vector to direction of travel
Matrix forwardMovement = Matrix.CreateRotationY( avatarYaw ); v = Vector3.Transform( v, forwardMovement ); //add travel vector to position vector
avatarPosition.Z += v.Z;
avatarPosition.X += v.X;
}

To rotate and move a General (free) camera in 2D [UpdateCamera()]

Determine the camera's position in world coordinates.

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

 

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.Transform a copy of the reference vector using Transform and the rotation Matrix.

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

 

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;

 

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 ) );

 

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.


Viewport viewport = graphics.GraphicsDevice.Viewport;
float aspectRatio = (float)viewport.Width / (float)viewport.Height; proj = Matrix.CreatePerspectiveFieldOfView( viewAngle, aspectRatio, nearClip, farClip );

 

To rotate and move a First Person camera in 2D [UpdateCameraFirstPerson()]

A first person camera is very similar in implementation to a general camera. The main difference is the use of a headOffset. The headOffset is used to position the viewer's eyes in slightly different positions/direction to the avatar. E.g when crouching, looking around corners or looking sidways while moving forward.

 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 );

    }

To rotate and move a Third Person camera in 2D [UpdateCameraThirdPerson()]

A third person camera shows the players character or vehicle from a distance usually an "over the shoulder view", although a fixed camera position tracking the player is also popular.

This code is smiliar to the code for a first person camera; the vector thirdPersonReference positions the camera relative to the character. When the camera rotates it should rotate about the character and not it's self. 3rd person cameras also require that the character be rendered in the scene.

A difference between third and first person camera is the direction that the camera is pointing. There are two main choices here;

  1. point the camera in the same direction that the character is looking
  2. point the camera at the character

This code implements the first option by finding a point, cameraLookAt, in front of the camera in the same direction as cameraReference.

void UpdateCameraThirdPerson()
    {
        float lag = 0.075f;
        float diffYaw=avatarYaw-actualYaw;
        actualYaw+=diffYaw*lag;



        Matrix rotationMatrix = Matrix.CreateRotationY( actualYaw );

        // 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 =  avatarPosition + transformedReference;


        // Calculate the position the camera is looking at
        Vector3 transformedCameraReference = Vector3.Transform(cameraReference, rotationMatrix);
        Vector3 cameraLookat = transformedCameraReference + 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 );

    }

 

A simple 3rd person camera can be very jerky and unpleasnt to use for long periods. A solution is to introduce some lag in to the camera movement. This has the effect of camera responding a little slowly to teh character's movement. The above code implements lag by not turning the camera by the required avatarYaw, rather we calculate the difference between the required yaw and the current yaw (actualYaw) and we turn the camera a fraction of this value. The effect is that the camera takes a little while to match the speed of the character when it starts to move and the camera continues to move after the character has stopped in order to catch up.