Spaces and Matrix in XNA
XNA requires 3 matrices to be set before 3D geometry can be rendered. These matrices are used to transform the 3D geometry from its initial definition in model space e.g. your art package into the final image drawn on the screen in 2D screen space.
The steps the geometry goes through are:
- You initially define your 3D object in an editor (like 3DS max, Maya etc.) or by hard coding the values. You normally set 0,0,0 as the centre of your object with vertex positions defined relative to the centre. These positions are defined in Model Space
- We want to position, rotate and scale our 3D model into our game world. In order to do this we must provide a matrix that XNA can use to convert the vertex positions from model space into this new space, known as World Space. This matrix is called the World Matrix
- We need the world to be transformed so it appears as if it is being viewed from a certain position in our world. This position is the location of the eye or camera. So we provide a matrix that allows XNA to convert from World Space into View Space (sometimes known as camera space). This matrix is called the View Matrix
- Finally we need to tell XNA how to project this 3D View Space onto our flat 2D screen. So we provide a matrix that allows XNA to convert from View Space into Screen Space. This matrix is known as the Projection Matrix.
So the three matrix are:
- World Matrix - Transforms 3D data from Model Space into World Space. You need to calculate this before rendering every entity in your world.
- View Matrix - Transforms from World Space into View Space. You need to calculate this each time your camera changes position
- Projection Matrix - Transforms from View Space into Screen Space. You normally calculate and set this just once during initialisation.
XNA provides many functions to help you create these matrices. Some are described below along with common settings and examples.
Different graphic libraries vary in the axis system they use. For example native Direct3D uses a left handed system where X is right, Y up and Z in to the screen while XNA and OpenGL use a right handed system where X is right, Y is up and Z is out of the screen. To convert between the two systems you can invert any one of the axis (but only one). I normally invert Z but inverting either of the others is also valid. Note that you cannot convert from one of these co-ordinate systems to another using rotations.
Note: these are the two most commonly used co-ordinate systems but there are others e.g. 3DS Max has Z up Y into the screen and X right. To convert from a right handed system to the 3DS Max system you swap -Z and Y co-ordinates.
XNA provides a matrix type called Matrix. This is a class that contains 4 by 4 elements for the matrix values. You can declare one simply:
This creates a variable of type Matrix, calls it worldMatrix and sets it to the identity matrix. The identity matrix is one which when multiplied by another results in the other i.e. no change. So Identity * MatrixA = MatrixA. It is therefore common to initialise matrix to identity.
Your world matrix is used to transform from model space into world space. You use it to take your 3D models and position, scale and rotate them into the game world. Model space is the space you created your model in e.g. in an art package where 0,0,0 is normally the centre of the object and vertex positions are defined relative to this. You want to place this object into your game world so you need to translate, rotate and scale it into world space. There are a number of helper functions that you can use to create this matrix:
This function takes a Vector3 with the x, y and z position of the object in the world. It then returns a matrix that, when applied to the model geometry, will transform it into world space correctly. So if you want your object to be located at 10,0,50 you might write:
Matrix worldTranslation=Matrix.CreateTranslation(new Vector3(10,0,50));
After this call the matrix is filled with the values required to carry out this transform.
These three functions allow you to set up your matrix to rotate the object around one of the axis. You use the function you require and specify the rotation angle in radians. E.g. to rotate a object 180 degrees around the Y axis we could write:
MathHelper.Pi is a provided value for PI, PI is 180 degrees in radians. The Math class also provides PI but the MathHelper one returns a float which is more convenient here. See the note at the end of this section about converting Radians and Degrees
The final thing you can do with your world matrix is specify a scale. So you could make your object twice as big by scaling it with a value of 2
Not that the above scaled the model in all axis by 2. Other overloads exist to allow you to scale it differently in the different axis.
Using the above functions you can position, rotate and scale your 3D object into your world. There is one important thing to note however and that is that you must do these matrix operations in a certain order since matrix multiplication is not cumulative. In XNA you must combine your matrix in SRT order (scale * rotation * translation).
Sometimes you will heard these axis rotations referred to by yaw, pitch and roll. Rotation around the y axis is called yaw, around the x axis is called pitch and around the z axis is roll.
Therefore if you want to position your entity at position position with scale scale and rotation rotations you could write:
Matrix modelWorldMatrix = Matrix.CreateScale(scale) * Matrix.CreateRotationX(rotations.X) *
The above multiplies all three rotations separately to show the working but you could do them in one using
Do remember to always multiply the matrix in Scale, Rotation, Translation (SRT) order!
The view matrix transforms from world space into view space. It allows you to specify a position in the world where the view will be seen from. This needs to be set whenever the camera position and/or direction is changed.
Camera control is in a separate topic (see XNA Camera), here I will just describe a simple method for creating the view matrix. The function builds a view matrix from some inputs:
Matrix Matrix.CreateLookAt(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector)
- cameraPosition - the world position of the eye point
- cameraTarget - the position in the world we are looking at (used to calculate direction)
- cameraUpVector - defines which way is up. This is needed because if you are positioned somewhere in the world looking in a certain direction you could be upright or standing on your head and in each case the position and direction would still be the same.
An example of creating and setting a view matrix to represent the camera positioned at 0,3,5 looking at 0,0,0 and upright (0,1,0):
Matrix viewMatrix=Matrix.CreateLookAt(new Vector3(0,3,5), new Vector3(0,0,0), new Vector3(0,1,0));
XNA usefully provides a zero vector and up vector so we could also write the above as:
Matrix viewMatrix=Matrix.CreateLookAt(new Vector3(0,3,5),Vector3.Zero,Vector3.Up);
The projection matrix specifies how our 3D view space data is transformed onto our 2D screen. This is where we can specify the perspective to use. We use the following function that builds a projection matrix for us:
Matrix.CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance)
- fieldOfView - this is the field of view we require in radians. PI/4 is commonly used here. It must be between 0 and PI (180) degrees
- aspectRatio - this is the aspect ratio we require. Normally set to the screen width divided by the screen height.
- nearPlaneDistance - this is the distance to the near view plane. Anything that is closer than this value is not shown. You often set this to 1.0f
- farPlaneDistance - this is the distance to the far view plane. Anything in your world that is further away than this will not be shown. So if your world is 100 units in size you will want this value to be at least 100. The actual value to use will depend very much on your game.
Note: this matrix is normally only set once in a game, at the start unless you are doing any fancy effects or techniques like rendering to a texture.
An example of creating and setting this matrix might be:
float aspect = (float)screenWidth / (float)screenHeight;
Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect, 1, 100);
Note the use of the MathHelper class. It provides lots of useful constants like PiOver4, PiOver2 and useful functionality like clamp.
Radians and Degrees
PI radians is 180 degrees. 2 PI is 360 degrees. Often it is easier to think in terms of degrees rather than radians. To convert between the two you can use the following MathHelper functions
There are three matrix used by XNA to transform your 3D models into the final 2D image you see on the screen. They are the World Matrix, the View Matrix and the Projection Matrix. Note: If you are coming from a OpenGL background OpenGL combines the first two together.
You create your 3D model in Object Space. You apply a world matrix to transform from object space into world space. To take the camera into account you apply a view matrix to transform from world space into view space and finally you apply a projection matrix to transform from view space into screen space.
XNA provides a number of functions that allow you to easily create your matrix.
The world matrix needs to be calculated to position every entity you render
The view matrix is calculated each time the camera changes position or orientation
The projection matrix is normally calculated just once at the start of your game