Sign in to follow this  
Galantida

Matrix for FPS Camera

Recommended Posts

Galantida    100
Hello All,

I don't normally post questions on any forums so I am new not just to this forum but forums in general. I have been pretty proud of myself learning C# and XNA. I have a stationary camera sitting at 0,0,0 that follows a space ship which I steer using the mouse to free look and the keys to go forward, back and strafe left and right. I thought it would be simple to now convert my camera to first person by simply applying the same matrix that I do to the ship model to my camera but I just cant get it to work. I have read many camera tutorials and picked this up and put it down more than a few times over the past few months but just can't get past this. Below is my draw function and the matrix functions.

I am really stuck if anyone can help.


ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)Window.ClientBounds.Width / (float)Window.ClientBounds.Height, 1, 3000);


protected override void Draw(GameTime gameTime)
{
// Clear Display
GraphicsDevice.Clear(Color.Black);

// Camera Matrix
Matrix CameraMatrix;
if (World.FirstPerson == true) CameraMatrix = this.CameraFirstPerson(World.CameraObject);
else CameraMatrix = this.CameraFollow(World.CameraObject, World.LookAtObject);

// Terrain
basicEffect = new BasicEffect(GraphicsDevice);
basicEffect.VertexColorEnabled = true;
basicEffect.World = Matrix.CreateTranslation(GraphicsDevice.Viewport.Width / 2f - 150, GraphicsDevice.Viewport.Height / 2f - 50, 0);
basicEffect.View = CameraMatrix;
basicEffect.Projection = ProjectionMatrix;

foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
DrawTriangleStrip();
}

// Render World Objects (Models and Sounds)
foreach (KeyValuePair<int, clsObject> kvp in World.Objects)
{
// set object value to current object
clsObject Object = kvp.Value;


// ***************************
// Draw Model for each object
// ***************************
Model Model = ModelBank[Object.ModelName];
Matrix[] transforms = new Matrix[Model.Bones.Count];
Model.CopyAbsoluteBoneTransformsTo(transforms);


// Object Matrix (Rotation /scale etc...)
Matrix ObjMatrix = ObjectMatrix(Object);

foreach (ModelMesh mesh in Model.Meshes)
{
foreach (BasicEffect be in mesh.Effects)
{
be.EnableDefaultLighting();
be.Projection = ProjectionMatrix; // using the view settings defined earlier (Near & Far planes, Camera Lens, etc...)
be.View = CameraMatrix; // Camera is from the view matrix from the object we are currently viewing from
be.World = ObjMatrix * mesh.ParentBone.Transform; // Apply the view matrix from the object we are currently drawing.
}
mesh.Draw();
}

}


// Display HUD
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.Opaque);

spriteBatch.DrawString(Arial, "Camera Object" + World.CameraObject.Name + " (Use Alt # to Change)", new Vector2(10, 10), Color.Red);
spriteBatch.DrawString(Arial, "Location: " + World.CameraObject.X + "," + World.CameraObject.Y + "," + World.CameraObject.Z, new Vector2(10, 30), Color.White);
spriteBatch.DrawString(Arial, "Rotation: " + World.CameraObject.Yaw + ", " + World.CameraObject.Pitch + ", " + World.CameraObject.Roll, new Vector2(10, 50), Color.White);

spriteBatch.DrawString(Arial, "Input Object" + World.InputObject.Name + " (Use Ctrl # to Change)", new Vector2(10, 90), Color.Red);
spriteBatch.DrawString(Arial, "Location: " + World.InputObject.X + "," + World.InputObject.Y + "," + World.InputObject.Z, new Vector2(10, 110), Color.White);
spriteBatch.DrawString(Arial, "Rotation: " + World.InputObject.Yaw + ", " + World.InputObject.Pitch + ", " + World.InputObject.Roll, new Vector2(10, 130), Color.White);

spriteBatch.DrawString(Arial, "Look At Object" + World.LookAtObject.Name + " (Use Shift # to Change)", new Vector2(10, 170), Color.Red);
spriteBatch.DrawString(Arial, "Location: " + World.LookAtObject.X + "," + World.LookAtObject.Y + "," + World.LookAtObject.Z, new Vector2(10, 190), Color.White);
spriteBatch.DrawString(Arial, "Rotation: " + World.LookAtObject.Yaw + ", " + World.LookAtObject.Pitch + ", " + World.LookAtObject.Roll, new Vector2(10, 210), Color.White);

string CameraMode;
if (World.FirstPerson == true) CameraMode = "First Person";
else CameraMode= "Follow Look At Object";
spriteBatch.DrawString(Arial, "Camera Mode: " + CameraMode + " (Use function keys to change)", new Vector2(10, 250), Color.Red);

spriteBatch.End();


// Draw all Game Components
base.Draw(gameTime);
}



private Matrix ObjectMatrix(clsObject WorldObject)
{
// Objects Location, Scale and Roatation
Matrix ScaleMatrix = Matrix.CreateScale(WorldObject.ScaleX, WorldObject.ScaleY, WorldObject.ScaleZ);
Matrix LocationMatrix = Matrix.CreateTranslation(WorldObject.Location);
Matrix RotationMatrix = Matrix.CreateFromYawPitchRoll(MathHelper.ToRadians(WorldObject.Yaw), MathHelper.ToRadians(WorldObject.Pitch), MathHelper.ToRadians(WorldObject.Roll));

// Combine Matrix
Matrix ResultMatrix;
ResultMatrix = Matrix.Multiply(LocationMatrix, ScaleMatrix);
ResultMatrix = Matrix.Multiply(RotationMatrix, ResultMatrix);
return ResultMatrix;
}

private Matrix CameraFirstPerson(clsObject FromPerspectiveOf)
{
// Objects Position and Rotation
Matrix LocationMatrix = Matrix.CreateTranslation(FromPerspectiveOf.Location);
Matrix RotationMatrix = Matrix.CreateFromYawPitchRoll(MathHelper.ToRadians(FromPerspectiveOf.Yaw),MathHelper.ToRadians(FromPerspectiveOf.Pitch),MathHelper.ToRadians(FromPerspectiveOf.Roll));

// Camera Matrix (For when we are looking from this Objects perspective
return Matrix.Multiply(RotationMatrix, LocationMatrix);
}

private Matrix CameraFollow(clsObject FromPerspectiveOf, clsObject LookingAt)
{
// Build camera view matrix
Vector3 cameraDirection = LookingAt.Location - FromPerspectiveOf.Location;
cameraDirection.Normalize();
return Matrix.CreateLookAt(FromPerspectiveOf.Location, FromPerspectiveOf.Location + cameraDirection, Vector3.Up);
}

Share this post


Link to post
Share on other sites
MJP    19786
Welcome to the forums. :)

Anyway, this is actually pretty simple. A world matrix transforms a coordinate from object local space (AKA object space) to world space. A view matrix transforms from world space to the camera's local space (AKA view space). For any transformation matrix you can flip the direction of the transformation by inverting it. So for instance if you have a world matrix that transforms from object space to world space, the inverse will transform world space to object space. This means that if you invert your ship's world matrix, you'll have a matrix that transforms from world space to the ship's local space...which means you can use it as a view matrix:
[code]
private Matrix CameraFirstPerson(clsObject FromPerspectiveOf)
{
return Matrix.Invert(ObjectMatrix(FromPerspectiveOf));
}
[/code]

You can also use this property of matrices to go the other way around: if you invert a view matrix you get a world matrix for your camera. This can be handy for rendering things that you always want to be in front of a camera...for instance a gun in a first person shooter.

Also on a side note...when you want to post code here you can use the "code" or "source" tags like I did in my post. See this: [url="http://www.gamedev.net/blog/1037/entry-2249817-new-syntax-highlighting-in-forums-and-journals/"]http://www.gamedev.n...s-and-journals/[/url]

Share this post


Link to post
Share on other sites
Galantida    100
MJP You are the best, it worked like a charm!!! I have been trying to work through that for so long. [img]http://public.gamedev.net/public/style_emoticons/default/biggrin.gif[/img]

The only problem is I am not sure if I understand why the inverted matrix of my object works. I have been thinking of the camera as a physical object in space with a location and rotation. I guess I should think of it more as a space or coordinate system in it's self? Even if that is the case why doesn't the same matrix work for the camera as for the object since they are both in the same world?

If it's too difficult to explain the forum I will understand. Just knowing the answer now may help me make a break though in understanding it now.

Thanks again!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this