Game Development Community

Quick primer on Vectors, Matricies, and Quaternions

by Russell Bishop · in Torque X 2D · 05/07/2008 (8:10 pm) · 3 replies

Note: Some of this might be incorrect or over-simplified. Please feel free to add comments, corrections, or your own explanations to help others understand 3D math better. When I first started messing with this stuff it took me a while to get a grip on what exactly Vector3.Cross meant in 3D space or what a Matrix really meant to me (geometry 101 was a few years ago).


1. Vectors

A Vector can represent several different things: a point in 3D space, an amount of movement along the X, Y, and Z axis, etc.

To have a direction you need two vectors: A starting point, then either a magnitude/length (how far to move in the X, Y, and Z directions), or an ending point. If you think about it, you should be able to see that you can always get the ending point by adding the length vector to the starting point vector.

Vectors of length 1 are your unit vectors: up, right, and forward. They are important because in many cases you will want to find out directions of things, offset objects relative to each other forward/backward, etc. In order to do that you need to know how the object is rotated because if the object is turned slightly to the left then it's forward is no longer the same as the world's forward.

In TorqueX, the vectors are:
Right 1,0,0
Forward 0,1,0
Up 0,0,1

Note: These are NOT the same as Vector3.Forward or Vector3.Up! Torque uses a different coordinate system than XNA so keep that in mind. You can always create public static readonly vectors on your Game class so you can handily access them from anywhere.



2. Matricies

A Matrix is just a set of instructions that represent scaling an object in the X, Y, and/or z directions, rotating the object in space, then moving the object to a new location. Every object starts off at 0,0,0 with its forward facing forward (front moves toward positive Y) and up facing up (top moves toward positive z).

The movement in the X,Y,Z coordinates is the Translation of the Matrix. Trying to separate out the scale and rotation is complicated and the next version of XNA will include methods to do it for you so I'll leave it alone for now. In reality, TorqueX uses SceneGroups and you will probably never apply a scale to the main SceneGroup (such as the one named PlayerMesh in the FPS demo), so we'll ignore it for now. If you want to scale a model apply the scale to the T3DTSRenderComponent's Transform3D, which should scale just the model without affecting the main scene group (or associated components, like the Rigid Body stuff).



Not Grandma's Multiplication

Matrix multiplication is not commutative. Matrix1 * Matrix2 != Matrix2 * Matrix1, but that makes sense when you think about it for a second. If I move an object slightly forward, but still perform a rotation around the X axis, instead of spinning in place the object will start appearing to make large loops in space, like a ball on the end of a string being swung around in the air. If I rotate it first, then translate it, that's more like a spinning top that is dropped onto a table. You may want to rotate around a point on the object that isn't its exact center... if so, add to the transltion, perform the rotation, then subtract what you added.

#1
05/07/2008 (8:11 pm)
3. Quaternions

A Quaternion is a rotation around an arbitrary axis. You'll see people mention gimbal lock - that's when you rotate an object around some axis (X, Y, or Z) 90 degrees. Now the object's up is its left or its right is its forward, etc. Now when you go to do the next rotation around the next axis, such as Z, the previous rotation effectively causes this rotation to be around the wrong axis. In other words you get into a situation where you can't either yaw, pitch, or roll (eg: the object ends up situated such that roll always gets mapped onto yaw and you can't get out of it).

Quaternions solve this problem by representing rotations differently and they don't suffer from gimbal lock. To get a Quaternion from a rotation matrix or vice-versa:
Quaternion q = Quaternion.CreateFromRotationMatrix(obj.Transform);
Matrix rot = Matrix.CreateRotation(q);

If you have several different rotations, just add the Quaternions and you'll get the sum of all the rotations without the problem of gimbal lock. You can also easily rotate around some arbitrary axis instead of plain X, Y, and Z. (A rotation about X, Y, then Z added together is effectively a rotation around an arbitrary axis anyway).




What is normal?

Both vectors and quaternions can be normalized. In the case of quaternions, you definitely need to normalize them - if they aren't normalized many algorithms will break down and do crazy things. For vectors, normalizing should turn a vector into a unit vector (a normal).




Which way is my object facing?

Think about it... if you had just the rotation of your object, you could apply that to the forward vector and you'd get a vector result indicating which way your object was pointed, yes? So how do we get just the rotation part of a matrix? Simple - set the .Transform to Vector3.Zero:
Matrix rotationMatrix = sceneGroup1.Transform;
rotationMatrix.Translation = Vector3.Zero;

Vector3 direction = Vector3.Transform(forward, rotationMatrix);

You can do a similar operation to find out what up/down or left/right are to your object (multiplying one of these unit vectors by -1.0f will reverse the direction). If you just added an offset vector to the translation your offset would appear to be randomly incorrect, since it is offsetting relative to the world, not the object's current direction. In other words if the object turns around and starts moving backwards your "backwards" offset just became a "forwards" offset!

To fix this get the rotation matrix for the object and apply that to the offset vector, then add it to the translation. Now your offset will pickup the same rotation as your object - backwards will always be backwards.



Right angles are cool

So let's say I have two vectors, objectRight and objectForward. How can I figure out which way is objectUp? Simple - take the Cross product of the vectors. The cross of two vectors imagines that there is a plane in 3D space created by those vectors. Start at 0,0,0, then draw a line in the direction indicated by each vector, and you'll see a plane appear. Now draw a line perpendicular to that plane in 3D space - that's the cross product of the vectors, a new Vector describing that perpendicular line. This is often called a "Normal".



Go the distance

The dot product of two vectors, assuming that the second vector is a unit vector indicating what direction you wish to travel, is the length that the first vector travels in that direction. Think of it this way - grab one hand with the other and hold both out in front of you. Now move your hands six inches to the left, still holding them together. Your left arm is the unit vector - the direction to travel. Your right arm is another vector, perhaps representing a player moving across terrain. As you can see, since your right arm isn't travelling at the same angle as your left arm it travels a different distance than just its length would indicate in the direction of your left arm.

To put it another way, if you have a vector indicating which way is forward and a vector indicating an object's travel, you can take the dot product of the object's travel and forward to get how much of that travel is forward travel. Do it again for your right vector and now you can divide the object's movement into forward and sideward travel separately.

Also note, if the two vectors are unit vectors then the dot product is the cosine of the angle between them, assuming they both start at 0,0,0 and point in some direction.
#2
05/07/2008 (8:43 pm)
Thats awesome Russel, thank you!
#3
09/29/2008 (7:28 am)
It's useful (albeit irritating) to find out the coordinate systems of XNA and Torque X don't match.

I had been wondering why using the 'Forward' property of a Matrix was giving me the wrong result...