Understanding the transformation matrix
---------------------------------------
by Dan L'Ecuyer
The transformation matrix is a very important tool in 3D games. It is a
mathematical device which is used to rotate, scale and even distort an object
in 3D space. The vehicle damage models in Carmageddon, for example, are
fascinating examples of what can be done through the creative application of
the transformation matrix. Fenders, bumpers, wheels and other vehicle parts
can be made to appear damaged by distorting (shearing) the models using a
mathematical trick applied to the transformation matrix. It is beyond the
scope of this document to explain how this works but it will become obvious,
I think, that the transformation matrix is wide open to all sorts of clever
tampering.
The easy part about a t-matrix (I'll use this abbreviation to avoid a lot
of typing) is actually using it. The matrix is arranged in this pattern:
Xx Yx Zx
Xy Yy Zy
Xz Yz Zz
Let's say that we have an arbitrary point in 3D space specified as "xyz".
We want to apply the t-matrix in order to calculate the new position of this
point in 3D space. Let's say that we are rotating the point around a circle
whose centre point is "abc". First, we need to subtract "abc" from "xyz":
x = x - a
y = y - b
z = z - c
We do this because we need to ensure that the rotation will be relative to
the centre of the circle and not the centre of the 3D world. So, we now have
a new "xyz" to which we apply the matrix:
x = (x * Xx) + (y * Xy) + (z * Xz)
y = (x * Yx) + (y * Yy) + (z * Yz)
z = (x * Zx) + (y * Zy) + (z * Zz)
You can see why I named the nine cells in the matrix the way that I did.
It helps to clarify the relationship of each cell to its usage in practice.
Now we need to restore the absolute position in 3D space:
x = x + a
y = y + b
z = z + c
If the above algorithm is applied to every point in an object, the entire
object will rotate in space. If the t-matrix was correctly derived then the
operation will leave the object looking exactly the same but in a different
place. A bad or deliberately distorted matrix will leave the object looking
wrong or distorted.
The t-matrix can also be used to simply scale an object (making it bigger
or smaller). The matrix would look like this:
1 0 0
0 2 0
0 0 1
The effect of applying this matrix is that the object will grow twice as
large in the Y direction. Observe the equations with the cell names replaced
by their values:
x = (x * 1) + (y * 0) + (z * 0)
y = (x * 0) + (y * 2) + (z * 0)
z = (x * 0) + (y * 0) + (z * 1)
Makes perfect sense, right? The above matrix is known as a scaling matrix.
An identity matrix is a scaling matrix where the scale values are all equal
to 1. Applying the identity matrix leaves the object unchanged and unmoved
(its original identity, so to speak).
Rotation is more complex because it involves sines and cosines. Other than
the fact that you need to calculate the sine and cosine, rotation is really
not too complicated. For example, to rotate an object around the Z-axis, we
need to fill the matrix this way:
cos sin 0
-sin cos 0
0 0 1
You just need to calculate the sine and cosine for the number of degrees of
rotation and then pop the numbers into the matrix. Note that the sine value
is negated in one cell but the cosine value is not negated. This is an
important property of the t-matrix. It is a consequence of the fact that the
sine and cosine each operate in different quadrants but don't worry about the
math. Just remember this fact. For rotation around the X axis:
1 0 0
0 cos sin
0 -sin cos
Around the Y axis:
cos 0 -sin
0 1 0
sin 0 cos
There's an obvious pattern to this. Compare the position of the sine and
cosine values to the cell names and you'll see the pattern. Does it make
sense to you? I hope it does. Let's move on to rotation around multiple axes.
Here's where it gets very tricky. We need to do something called matrix
multiplication. Essentially, this works by multiplying the rows in the first
matrix with the columns in the second matrix. For example, to perform a
rotation around the X axis followed by a rotation around the Y axis, we need
to multiply the rotation matrices for X and Y:
X1 X2 X3 Y1 Y2 Y3
X4 X5 X6 * Y4 Y5 Y6 =
X7 X8 X9 Y7 Y8 Y9
(X1*Y1 + X2*Y4 + X3*Y7) (X1*Y2 + X2*Y5 + X3*Y8) (X1*Y3 + X2*Y6 + X3*Y9)
(X4*Y1 + X5*Y4 + X6*Y7) (X4*Y2 + X5*Y5 + X6*Y8) (X4*Y3 + X5*Y6 + X6*Y9)
(X7*Y1 + X8*Y4 + X9*Y7) (X7*Y2 + X8*Y5 + X9*Y8) (X7*Y3 + X8*Y6 + X9*Y9)
That is some pretty tedious arithmetic. Fortunately, we can take a shortcut
because of those zeroes and ones that are in the X and Y matrices. The
equations can be reduced to:
Y1 0 Y3
X6*Y7 X5 X6*Y9
X9*Y7 X8 X9*Y9
Substituting with the sines and cosines:
cosY 0 -sinY
sinX*sinY cosX sinX*cosY
cosX*sinY -sinX cosX*cosY
What if we want to rotate around the Z axis as well? In that case, the
matrix which we have just derived will need to be multiplied with the matrix
for rotation around Z. Rather than reproduce the same tedious math all over
again, I'll give you the final equations. In fact, I will give you all of the
equations for each of the possible rotation orders.
Rotation around X, Y, and then Z:
cy*cz cy*sz -sy
sx*sy*cz - cx*sz sx*sy*sz + cx*cz sx*cy
cx*sy*cz + sx*sz cx*sy*sz - sx*cz cx*cy
Rotation around Y, X, and then Z:
cy*cz - sx*sy*sz cy*sz + sx*sy*cz -cx*sy
-cx*sz cx*cz sx
sy*cz + sx*cy*sz sy*sz - sx*cy*cz cx*cy
Rotation around X, Z, and then Y:
cy*cz sz -sy*cz
sx*sy - cx*cy*sz cx*cz sx*cy + cx*sy*sz
cx*sy + sx*cy*sz -sx*cz cx*cy - sx*sy*sz
Rotation around Z, X, and then Y:
sx*sy*sz + cy*cz cx*sz sx*cy*sz - sy*cz
sx*sy*cz - cy*sz cx*cz sx*cy*cz + sy*sz
cx*sy -sx cx*cy
Rotation around Y, Z, and then X:
cy*cz cx*cy*sz + sx*sy sx*cy*sz - cx*sy
-sz cx*cz sx*cz
sy*cz cx*sy*sz - sx*cy sx*sy*sz + cx*cy
Rotation around Z, Y, and then X:
cy*cz cx*sz + sx*sy*cz sx*sz - cx*sy*cz
-cy*sz cx*cz - sx*sy*sz sx*cz + cx*sy*sz
sy -sx*cy cx*cy
I mentioned something earlier about the sine being negated in some of the
cells (the cosine is always positive). This negation affects the direction of
rotation around the axis. I have adjusted the equations to match the axis
orientation used in Carmageddon. That is, the X axis increases toward the
east, the Y axis increases toward the sky, and the Z axis increases toward
the south. When considering the angle of rotation, you need to view the axis
from the positive end toward the negative end. The rotation will be clockwise
as the angle increases.
Now, here is how you will apply the equations. First of all, you need to
know the desired angle of rotation around each of the axes. The sine and
cosine for each of the angles must be computed (your programming language
probably has this capability). For no rotation, use 0 for the sine and 1.0
for the cosine. Oh, by the way, you do know that you will have to use
floating point data types for this, huh?
You should name some temporary variables like this:
cx, sx - cosine and sine for angle X
cy, sy - cosine and sine for angle Y
cz, sz - cosine and sine for angle Z
This way, you can copy and paste the above equations into your program
without having to change all of the names. You have nine equations to run and
you will get one result for each of the nine cells in the t-matrix. Where
should you put this matrix? Heck, that depends on why you are reading this
tutorial. If you're writing some code for the Carmageddon game, I can tell
you what to do with your numbers. Otherwise, you're on your own.
The most likely reason to want to compute a t-matrix for Carmageddon is to
rotate a noncar object into position in the game. This means that you will be
dropping your t-matrix into an ACT file. See the companion tutorial on the
C2 file formats. Listed there is the record type for the t-matrix. I've also
put a little picture like the one earlier in this tutorial. The nine numbers
will need to have been computed using a 32-bit floating point data type. I
have described the format for this data type in the companion tutorial. Make
sure your programming language supports this data type exactly (if not then
you have a problem and I can't help you). The nine numbers need to be written
to the ACT file in this order: Xx Yx Zx Xy Yy Zy Xz Yz Zz. That's it.
The last thing I want to cover is another type of rotation. This is
rotation around an arbitrary axis. You don't always want to rotate around the
XYZ axes. Maybe your object needs to rotate around a pole but the pole is
not exactly vertical so it's not clear how the heck you're going to rotate
the object. Well, just use the pole as an axis. Here are the equations:
C = cos
S = sin
T = 1 - cos
X, Y, Z = axis
T*X*X + C T*Y*X + S*Z T*Z*X - S*Y
T*X*Y - S*Z T*Y*Y + C T*Z*Y + S*X
T*X*Z + S*Y T*Y*Z - S*X T*Z*Z + C
The axis can be computed by subtracting one vertex at the bottom of the
pole from one vertex at the top of the pole. This subtraction generates a
vector pointing upward. Next, the vector needs to be normalized. This means
that the vector length must be made equal to 1. This is how:
L = sqrt (X*X + Y*Y + Z*Z)
X = X / L
Y = Y / L
Z = Z / L
Now you have a valid axis for the rotation. Get the sine and cosine for the
angle of rotation and apply the equations to get the t-matrix. This is really
pretty simple compared to rotation around XYZ. However, each type of rotation
has its use. Also, it is extremely difficult to convert between an XYZ
rotation and an axis rotation.
End of document