Matrices are used all the time in XNA and here we cover the most important things you absolutely must know to get anywhere with XNA programming.
If you have a PHD in mathematics, are an engineer, have taken Calculus and Linear Algebra, or otherwise know all about Matrix Algebra, there's probably not much point in reading through this tutorial. I will just be discussing how XNA uses matrices.
Matrices - What they are and what they're used for.
Now we’re going to talk about the Matrix. And no, you are not the one Neo. Sorry, I just couldn’t resist.
Actually, the matrix we’re going to talk about has very little to do with the silver screen unless we’re talking about making computer graphics to make our movie. The matrix that that movie title comes from is probably a double entendre for the “womb” and “electrical circuits that have a common purpose” (http://www.merriam-webster.com/dictionary/matrix definitions 1 and 5c). The word has the same origin as the Latin word for mother. The idea being that Neo is being reborn, for the first time, into the real world from the world of circuits.
Anyway, the matrices we use in XNA are definition 5a which I believe can only loosely be connected to the title of the Keanu Reeves movie. A matrix is a mathematical concept. I don’t want to go too deep into the concept because I don’t think it’s necessary. By the time you need to really know what a matrix is, you should be ready to go learn it on your own.
If you must know, a matrix is basically just a grid with numbers in it like an Excel spreadsheet. It has columns and rows with cells that store numbers in those columns and rows. Sometimes they even store trig functions in the cells. There’s a whole branch of mathematics, called Matrix Algebra, that covers all the rules for multiplying them together as well as addition, subtraction and so forth.
I remember them introducing them to us in middle school. So, the concept doesn’t have to be that hard, but I never had a math class after that that covered them. After you take a few years of Calculus in college, you’ll probably take Linear Algebra on your way to your PHD in mathematics (you are currently working on your PHD in mathematics aren’t you?) Linear Algebra gets into a lot of Matrix Algebra . If you feel like you absolutely must know about matrix algebra, Khan Academy has some videos that you might watch. http://www.khanacademy.org/math/algebra/#algebra-matrices
But fear not. You really don’t need to know matrix algebra to do most of what you want to do playing around with 3D programming in XNA. That’s because XNA knows how to do Matrix Algebra, so you don’t have to. Quite frankly, I don’t remember hardly any of the rules of matrix algebra. (Crazily enough I spent a lot of time studying it when I started trying to learn 3D programming because everyone seemed to think you couldn’t spell your own name unless you knew matrix algebra forwards and backwards. I have to say that – so far – that has proven to be a huge number of wasted days of my life that I’ll never get back. Who knows, maybe I’ll get to put that knowledge to good use at some point in these tutorials. But I would have to review the subject to remember almost any of it.)
What you really need to know is when to use a matrix, what to use it for, and how to use it. And that’s not all that difficult once you kind of get the hang of it. It wouldn’t surprise me if that’s all a huge number of professional game programmers know. I mean, even if you want to do the matrix algebra yourself there are routines you could probably copy and paste from the internet.
Really, you should probably think of a Matrix as a black box that you load up with math formulas and then apply all the formulas at once to an object. You should probably memorize that last sentence.
In XNA you have 3 different matrices (matrices is plural for matrix) that you use all over the place, and you absolutely need to know how to make those 3 do their “magic”.
The first is the Projection Matrix. The Projection Matrix is usually thought of as being similar to the lens system of a camera. You’re going to load it up with math formulas that tell it how things are going to be drawn on the screen. You usually will just load it up when your program starts and then forget about it. It’s real easy. Basically 1 line of code loads it up and then you pass it to the graphics card every time you draw something on the screen. You’ll figure it out in no time and there’s basically no math involved other than the formula to load it prefers radians rather than degrees.
The second matrix is the View Matrix. Basically this is your camera. Generally, you’re going to load it up with formulas that move the camera around your 3D world and change the direction the camera is facing. Ok. This one actually does involve a whole lot of math, but it’s mostly gonna be covered by what I’ll discuss in a minute. Still, there’s no need to get intimidated. You’re still not going to do any matrix algebra to speak of. Instead you’re just going to load it up with formulas and let XNA do the matrix algebra for you. It’s like plugging values into a calculator. And ultimately, all this view is asking for is a 3D position where the camera is at, what spot in the 3D world to look at, and which direction is up.
The third matrix is the World Matrix. First thing to know is – unlike the other matrices we just talked about – there is going to be a world matrix for pretty much every object in your 3D world. The world matrix tells XNA how to place your object into the scene that it’s drawing. You load it up with formulas that tell it where to place the object, what direction to make it face towards, and what size to make it be. When you want an object to move to another position in your 3D world, or turn around and face the other direction, you load up a matrix with 1 or more formulas and then put it in that object’s world matrix, or you can combine it with the formulas that are already in the world matrix for that object.
The whole point of your world matrix is that your models are going to be placed into your 3D world at its origin, or center, without a world matrix. If you don’t specify a world matrix for your object it will appear exactly like it was created in the modeling program that it was created with. In other words, every object in your entire 3D world will all be on top of each other at the center and you won't really have a way to move them elsewhere. By using a world matrix for each object you can tell XNA to draw the object in a different position than the one it was created with.
What Kind of Formulas do you Typically Put in a Matrix? Usually, the way you use matrices in XNA is you load them up with a math formula, and then you set the View matrix or the world matrix of an object equal to the matrix that you loaded up. XNA has methods for loading formulas into a matrix, so you don’t need to know how. Mainly you are going to be using matrices to translate, rotate, or scale.
When you translate an object you are moving it. Rotating an object is just turning it, but you’ll be turning it around either the x,y, or z axes – one at a time. Scaling means resizing; sometimes the object will be too big or small and you just want to change its size; that’s called scaling the object.
So let’s say you want to move the object, rotate it around on the Y axis 90 degrees, and make it twice as big. You also want to rotate it 10 degrees on the X axis. Basically, you load up a matrix for each of these changes and then combine all the matrices together. So you would create a matrix, combine it with a matrix for rotate around Y 90 degrees, combine that with a matrix to rotate 10 degrees around X, combine that with a matrix to scale it to twice the original size, and combine that with a matrix that has a translation formula for movement. Finally, you take the result matrix and load it into the object’s world matrix and viola, the object obeys.
There are some tricks to this. One of the big ones is that you may have to move the object back to the center of the world, or origin, in order to get it to rotate correctly. Then you can move it where you want it. I should probably do a tutorial on that. Another is that the order you combine them in is very important. Combining Matrices In XNA, when you want to combine the information in two matrices you multiply them together. The big catch here is that the information in the matrices does not act on models; it acts on the vertices of the model. That's a very important distinction. The other part of the "catch" is that all of these operations take place in relation to the center of this 3D universe you're building, known as the origin.
When you tell XNA to use a scale matrix to make a model bigger or smaller, you're really saying "Move all the vertices away from the origin by this percentage." Scaling by 2.0 is going to give you 200% of the original size. However, it will only work correctly if the model's center is at the origin, or center of the 3D universe, because it's really pushing the vertices away from the center by that amount.
Likewise, applying a rotation matrix rotates the vertices around the origin. It does not rotate the model. However, if the model is centered at the origin, rotating all the vertices will have the affect of rotating the model. The problem comes when you try to rotate after the model is moved away from the origin, because a rotation matrix (or the rotation formulas themselves) just rotate vertices around the origin. So the end result will be the entire model orbiting the origin rather than rotating.
You can actually use that to your advantage if you want one object to orbit another. Just simply get the translation of the orbited object and translate the orbiting object by that amount towards the origin. Then apply a rotation. Then move the orbiting object back by the same translation amount before the Draw occurs and viola, the object orbits the other object.
Just remember that scaling and rotation can only occur when the object is at the origin.
Even translations are relative to the origin. But once the object is translated, you can keep applying more translation matrices over and over to keep moving the object. You just have to take the model back to the origin if you intend on doing any more scaling or rotation.
The Identity Matrix is kind of special. It’s not a matrix that you load, like the view matrix. It’s a matrix that you create. Usually, you will be putting it into a world matrix by setting the world matrix equal to the identity matrix. Think of an Identity Matrix as an empty matrix. It essentially has the value 1 in it. So, when you combine a matrix with it, the result matrix is exactly the same as what you combined it with just like multiply some number times one gives you that same number. When combining with an identity matrix, you can think of it as combining an empty matrix with a loaded matrix and the result being whatever was in the loaded matrix. That would be kind of pointless. But you use the identity matrix mostly to empty a matrix. Then any future combinations will start off from “scratch”.
When you want to combine the information in two or more matrices, you multiply them together. Generally that's written as *= in C#. You can keep combining the formulas in the object's world matrix over and over again. They are cumulative but they still require you to move the object back to the origin for scaling or rotation, but then you can just move them back to where they were after the rotation or scaling matrix is applied. A lot of programmers don't even notice that this is a requirement, because they do their scaling and rotations first before anything else and then only translate after that. If you never need to scale or rotate after that, you don't have to worry about it. But most programmers hit the brick wall when they suddenly need to do a rotation and their rotation causes the object to orbit the origin rather than rotate. They don't realize that a rotation matrix says "rotate the vertices by this angle around the origin" and that that results in a rotation only when the object is at the origin. They also may not realize that there's nothing wrong with popping the model back to the origin, applying the rotation or scale, and then popping it right back to where it was between Draw frames. Since it happens between Draw frames it won't be seen on screen.
Sometimes you don't really care how an object, or model, is oriented currently but simply want to tell it how it needs to be now. Say for example, you have a character in a game that teleports from one place in the game directly to another. This may not even be magic, but rather the result of moving the player's character from one game zone to another.
In that case, you don't care where the character model was before, but simply want to assign it a position (translation) and a facing (rotation).
Setting an object's world matrix (or any matrix) with the equals sign will overwrite any existing information in the matrix.
If you want to empty out an object's world matrix - but you are not ready to assign it a new value, you can set the object's world matrix equal to the identity matrix. This empties it out without really assigning it a value. It's like "zero'ing" it out except that it performs mathematically like it has a one in it. Maybe it's better to say that it "empties" it out rather than "zeros" it out.
But if you already know what you want to load into the object's world matrix, you can skip the step of setting it equal to the Identity Matrix and just simply set it equal to the matrix that's already loaded up with the orientation information that you want.
Setting the object's world matrix equal to another matrix will overwrite and replace all information that was previously in the object's world matrix. Again, remember that if you don't want to overwrite, but rather want to combine, you multiply the object's world matrix times the new matrix and put the result in the object's world matrix.
I should probably say a few words about using XNA matrices for 3D rotations. Rotating a model in XNA is as simple as loading up a rotation matrix and combining it to the model's world matrix while the model is centered at the origin.
The catch is that you can't rotate on all three axes at once. The reason is, to the best of my knowledge, that there is no formula that allows you to do this in 3D. The rotation formulas are 2D formulas. Here they are:
x = X * (float)Math.Cos(TurnAngle) - Y * (float)Math.Sin(TurnAngle);
y = X * (float)Math.Sin(TurnAngle) + Y * (float)Math.Cos(TurnAngle);
Notice that there's no Z in those formulas. One formula rotates the X coordinate of the 2D point and the other rotates the Y coordinate of the 2D point, but both formulas are required to move any point in 2D space. You can't rotate using only one of those formulas.
Anyway, under the hood XNA is using these formulas in it's rotation matrices. The reason it works in 3D is that the formula, as written, will rotate a 3D point in 3D space around the Z axis. Because the X,Y plane is a 2D plane existing in 3D space, this formula can be used to rotate a 3D point as long as it stays on that plane.
The next logical step is to realize that you can rewrite this formula so that it rotates on the X,Z plane instead of the X,Y plane. And then you could reason that you could also rotate on the Y,Z plane as well. Finally, you would realize that combining these three rotations allows you to rotate to anywhere in 3D space.
That's why you have 3 different rotation matrices:
The input (Single) on those matrices is the angle to rotate by measured in radians rather than degrees.
In order to use matrices in XNA it's pretty straight forward. Whether you are doing rotation, scaling, or transformation, applying these matrices is the same for any object's world matrix.
You set the object's world matrix equal to some value to place it in the world. And then any change you want to make you just multiply the object's world matrix times a matrix containing the change. It's all cumulative, so it will store the sum of any changes made until you set the object's world matrix equal to something, which will overwrite all those previous changes with the new orientation.
And then you pass the object's world matrix to the shader, such as BasicEffect, when you go to draw, so that the shader knows how to place the object into the scene to be drawn. That's pretty much it.
Now keep in mind that the view matrix is a bit different. The view matrix controls the camera rather than game objects. So, the view matrix is loaded a bit differently:
The three parameters on that are Position, Target Point, and Up all represented as 3D vectors. Up is easy because it's just a normalized vector pointing straight up and XNA gives you Vector3.Up to do the job without any thought. Position is just a 3D coordinate (stored as a vector) of where the camera is at. And Target Point is a 3D coordinate (stored as a vector) of what spot the camera looks at.
You don't really apply rotation, scaling, or translation matrices to the view matrix. And there's usually only one view matrix per game unless you're doing something tricky like a split screen. I generally just create a brand new LookAt matrix and load it into the view matrix every time it needs to change.
The projection matrix you just set once in your initialization method and forget about it. I'm not certain that it's even possible to change it once you get the program actually going. All attempts I've made to change it have failed miserably, but perhaps there's some way to change it without going to drastic extremes.
The first parameter is FieldOfView. This is just how wide of an area the camera sees. Real world camera lenses have a field of view. Fish eye lenses can see very wide angles, while telephoto lenses tend to have a very narrow viewing angle. As always, this angle is in radians. Aspect ratio is the ratio between your screen height and screen width. Most screens today are either 4:3 or 6:9 but you can query the graphics card to get it to give you the answer. Then you have near plane and far plane distances. Nothing will be drawn if it's closer to the camera than the near plane and nothing will be drawn if it's further than the far plane.
Again, set the projection matrix once and leave it. But you have to pass it to the shader, like BasicEffect, in order to tell it how to draw every object in the scene. I haven't tested this, but it may not be necessary to pass it to the shader more then once, since BasicEffect doesn't like you changing it after the first time you pass it.
So that pretty much wraps it up for matrices. I can't think of anything else you're likely to need to know in XNA about matrices. If you understand everything on this page regarding matrices, you probably know about as much as you'll ever need to know about matrices in XNA.
But I think once you get ready to learn HLSL in XNA you'll have to start digging a bit deeper and actually start understanding matrix algebra. But understanding what's on this page will even help you with that since you'll have a good idea how this stuff is getting used at a high level already. Digging into the low level specifics of how the math is done will just be a whole lot easier when you know what it is you're trying to accomplish with the math.
If you're interested in what's going on inside these matrices, I found a pretty good video on YouTube where the guy explains some of the math behind XNA matrices here.
I think you can get pretty deep into 3D XNA programming without knowing much at all about Matrices or Matrix Algebra because XNA handles so much of the work for you. But this tutorial covers the things that you absolute must know about matrices to get anywhere with XNA in 3D.