Rendering a model – Free Camera

Building on the last post, we’ll create a free moving camera. Add a new class to the “Cameras” folder in the “ProjectVanquish” project. Name the class “FreeCamera”. We need to change the class declaration to inherit our “BaseCamera” class.

public class FreeCamera : BaseCamera
{
}

Add the following to the namespaces:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

You’ll see that we are referencing the “Input” namespace. This is so we can use Input devices like the Keyboard, Mouse and even GamePads. We’ll need to declare a “MouseState” object for us to store the original position of the Mouse before it’s moved. Add in the following variable declaration:

MouseState originalMouse;

Let’s create the constructor, remembering that we’ll need to pass in variables to the base camera class:

public FreeCamera(GraphicsDevice device, Vector3 position, Vector3 target, float aspectRatio, float near, float far)
    : base(device, position, target, aspectRatio, near, far)
{
    originalMouse = Mouse.GetState();
}

We don’t need to do anything else with the constructor as all of the values are set within the “BaseCamera” class. Let’s look at overriding the “Move” and “Update” methods, starting with the “Move” method:

public override void Move(Vector3 vector)
{
    // Move the cameras position based on the way its facing
    Vector3 rotatedVector = Vector3.Transform(vector, rotationMatrix);
    Position += speed * rotatedVector;
}

This code moves the cameras position based on the direction that it’s facing. Let’s do the “Update” method:

public override void Update(GameTime gameTime)
{
    // Free movement
    float dt = (float)gameTime.ElapsedGameTime.Milliseconds / 1000f;
    // Rotation
    MouseState currentMouseState = Mouse.GetState();
    if (currentMouseState != originalMouse && Keyboard.GetState().IsKeyDown(Keys.Space))
    {
        Vector3 rot = Rotation;
        float xDifference = currentMouseState.X - originalMouse.X;
        float yDifference = currentMouseState.Y - originalMouse.Y;
        rot.Y -= 0.3f * xDifference * dt;
        rot.X += 0.3f * yDifference * dt;
        Mouse.SetPosition(device.Viewport.Width / 2, device.Viewport.Height / 2);

        Rotation = rot;
    }

    originalMouse = Mouse.GetState();

    // Key press movement
    KeyboardState keyboard = Keyboard.GetState();
    Vector3 direction = Vector3.Zero;
    if (Keyboard.GetState().IsKeyDown(Keys.W))
        Move(new Vector3(0, 0, -1) * dt);

    if (Keyboard.GetState().IsKeyDown(Keys.S))
        Move(new Vector3(0, 0, 1) * dt);

    if (Keyboard.GetState().IsKeyDown(Keys.A))
        Move(new Vector3(-1, 0, 0) * dt);

    if (Keyboard.GetState().IsKeyDown(Keys.D))
        Move(new Vector3(1, 0, 0) * dt);
}

That’s all we need to do for this class. We have added input handling in the “Update” method for the Keyboard and Mouse devices. All we need to do now is to tie this in with our “ProjectVanquishTest” project.

The code below is for reference purposes only. It won’t actually be used in the next part, so if you add it in, be prepared to remove it for the next post.

Open up the “Game1” file within the “ProjectVanquishTest” project and add the following namespace:

using ProjectVanquish.Cameras;

Declare a new variable:

FreeCamera camera;

We’ll instantiate this variable in the “Initialize” method:

camera = new FreeCamera(GraphicsDevice, 
                        new Vector3(0, 10, 0), 
                        Vector3.Zero, 
                        GraphicsDevice.Viewport.AspectRatio, 
                        0.1f, 
                        1000f);

We are positioning the camera at X:0, Y:10, Z:0 looking at X:0, Y:0, Z:0. Find the “Update” method and then add the following:

camera.Update(gameTime);

So, we have now incorporated our new Camera into the test project.

However, we will still see nothing on the screen at the moment, and also, this camera isn’t in the correct place. I believe that the camera management should be done in the Scene Manager, so in the next part, we’ll create a simple Scene Manager to handle this.

Advertisements

Rendering a model – Creating a Camera

The engine is finally beginning to take shape.  Before we can render a model, we’ll need to create a camera.  We’ll create two new classses, a base camera class and a free camera.  We’ll inherit from the base camera class to create our free camera.  Let’s start off with the base camera class.  In the “ProjectVanquish” project, add a new Class file to the Cameras folder called “BaseCamera”.  Declare the class as:

public abstract class BaseCamera
{
}

Add the following namespaces:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

Add in the following variables:

protected Matrix viewMatrix;
protected Matrix projectionMatrix;
protected Matrix rotationMatrix;
protected GraphicsDevice device;
protected Vector3 target;
protected Vector3 position;
protected Vector3 rotation;
protected Vector3 up;
protected float speed;
float near;
float far;

Add the following properties:

public Matrix View { get { return viewMatrix; } }
public Matrix Projection { get { return projectionMatrix; } }
public float NearClip { get { return near; } }
public float FarClip { get { return far; } }
public Vector3 Position
{
    get { return position; }
    set
    {
        position = value;
        UpdateView();
    }
}

public Vector3 Target
{
    get { return target; }
    set
    {
        target = value;
        viewMatrix = Matrix.CreateLookAt(Position, Target, new Vector3(0, 1, 0));
    }
}

public Vector3 Rotation
{
    get { return rotation; }
    set
    {
        rotation = value;
        rotationMatrix = Matrix.CreateRotationX(rotation.X) 
                       * Matrix.CreateRotationY(rotation.Y);
        UpdateView();
    }
}

public Matrix World
{
    get
    {
        return Matrix.CreateTranslation(Position.X, Position.Y, Position.Z)
             * Matrix.CreateRotationX(rotation.X)
             * Matrix.CreateRotationY(rotation.Y)
             * Matrix.CreateRotationZ(rotation.Z);
    }
}

Now we need a constructor for the class:

public BaseCamera(GraphicsDevice device, Vector3 position, Vector3 target, float aspectRatio, float near, float far)
{
    Position = position;
    Rotation = Vector3.Zero;
    Target = target;
    this.speed = 30;
    this.near = near;
    this.far = far;
    this.device = device;
    this.up = Vector3.Up;

    // Setup Field of View, Aspect Ratio and Clipping Planes
    projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
                         MathHelper.PiOver4, 
                         aspectRatio, 
                         near, 
                         far
                       );

    // Update the View
    UpdateView();
}

The last line in the constructor is calling an “UpdateView” method. Let’s add this in:

public virtual void UpdateView()
{
    Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
    Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, rotationMatrix);
    Vector3 cameraFinalTarget = position + cameraRotatedTarget;
    Vector3 cameraRotatedUpVector = Vector3.Transform(up, rotationMatrix);

    viewMatrix = Matrix.CreateLookAt(Position, cameraFinalTarget, cameraRotatedUpVector);
}

So, that is the camera initialisation code out of the way. Let’s add a few more methods so our other classes can inherit the functionality, but override them if the developer chooses too:

public virtual void Move(Vector3 vector)
{
}

public virtual void Update(GameTime gameTime)
{
}

Excellent. We now have a good base class that we can create new Cameras from. In the next part, we’ll create a “Free” camera for our first camera and to use in testing.