Introduction
Any 3D developer ought to understand the essential mathematics behind
transformations. Although the math looks complicated, it really isn't
too bad, once you get past the unfamiliar notation.
Points and Vectors
You have been using the term vector quite a bit. It is
used to describe a point in 2D or 3D space, and alternatively a line
segment between the origin and that point. The term also has a
mathematical definition. A vector in 3D geometry would consist of
three floats, usually arranged like this:
_ _
| |
| x |
| |
| y |
| |
| z |
|_ _|
The nice thing about thinking about a point as a vector is there are
certain mathematical properties associated with vectors. If you use
the computer to apply these principles, you can generate any kind of
transformation you wish.
Translation
Essentially, translation refers to adding a vector to each point in a
shape. Imagine a point at (0, 0, 0). If you wanted to translate that
point up one unit, you could convert the point to a vector and add it
to another vector, like this:
_ _ _ _ _ _
| | | | | |
| 0 | | 0 | | 0 |
| | | | | |
| 0 | + | 1 | = | 1 |
| | | | | |
| 0 | | 0 | | 0 |
|_ _| |_ _| |_ _|
In essence, translating an object amounts to adding a vector to each
point in the object.
Scaling
If translating an object means adding each point to a vector, scaling
could be seen as a multiplying function. For example, if you have a
circle with a point at (0, 1, 0) and another point at (1, 0, 0), you
could make the circle twice as large by multiplying each x, y, and z
value by 2. The resulting calculation would look something like this:
_ _ _ _ _ _ _ _
| | | | | | | |
| 0 | | 0 | | 1 | | 2 |
| | | | | | | |
| 1 | * 2 = | 2 | | 0 | * 2 = | 0 |
| | | | | | | |
| 0 | | 0 | | 0 | | 0 |
|_ _| |_ _| |_ _| |_ _|
In fact, you can actually scale in X, Y, and Z axes
independantly. Most 3D packages allow you to specify a vector for
scaling which separately indicates how much you scale in each axis.
Although it's not exactly done this way mathematically, you can think
of multiplying two vectors together for a scale, so if you have a
point (2, 2, 2) and you want to scale it by (3, 4, 5), you could
(somewhat inaccurately) think of it like this...
_ _ _ _ _ _
| | | | | |
| 2 | | 3 | | 6 |
| | | | | |
| 2 | * | 4 | = | 8 |
| | | | | |
| 2 | | 5 | | 10 |
|_ _| |_ _| |_ _|
Please note that this is NOT exactly how it's
done. However, I have simplified the math to make the concept a
little easier to understand. In reality, the scale is usually done
with either a single value, one direction at a time, or in a 3 x 3
matrix. Since I haven't shown you matrices yet, I'm simplifying the
math. See any linear algebra book for the complete truth.
Two - Dimension Rotation
To perform a rotation around the origin in two dimensions,
mathemeticians have come up with a series of trig formulas. Let's say
we have a point at (x, y) and we want to rotate the point by a
radians. The new x and y values can be determined by the following formulas:
x' = (x * cos(a)) + (y * -sin(a))
y' = (x * sin(a)) + (y * cos(a))
Given any x, y, and a values, you can use these formulas to generate a
new point x'y' that is rotated a radians around the origin.
For example, consider the following situation: You have a point at
(1, 1) and you want to rotate it 90 degrees (pi/2 radians).
By observation, you can probably tell that the result should be (-1,
1).
cos(pi/2) is 0, and sin(pi/2) is 1. Use a calculator to confirm these
results if necessary. Now, you can replace the variables with the
appropriate values:
x' = (x * cos(a)) + (y * -sin(a))
= (1 * 0) + (1 * -1)
= 0 - 1
= -1
y' = (x * sin(a)) + (y * cos(a))
= (1 * 1) + (1 * 0)
= 1 + 0
= 1
(x', y') = (-1,1)
3D Rotations
To consider 3D rotation around the Z axis, all you need to do is
recognize that the z value does not change at all. So a 3D rotation
around the Z axis can be calculated with three formulas:
x' = (x * cos(a)) + (y * -sin(a))
y' = (x * sin(a)) + (y * cos(a))
z' = z
Likewise, a rotation around the Y axis keeps the Y value alone, but
involves trig functions on the X and Z values. Here's the function
list for rotating around the Y axis:
x' = (x * cos(a)) + (z * sin(a))
y' = y
z' = (x * -sin(a)) + (z * cos(a))
... and rotation about the x axis uses a similar set of functions.
x' = x
y' = (y * cos(a)) + (z * -sin(a))
z' = (y * sin(a)) + (z * cos(a))
Don't get all hung up on memorizing these formulas. You can look them
up when you need them. The more important thing is to understand the
pattern. You'll see a technique for combining these formulas into a
cleaner structure in a few minutes. For the time being, note that
there is a consistent pattern emerging.
Finding the pattern
Take another look at rotation around the Z axis. The formulas look
like this:
x' = (x * cos(a)) + (y * -sin(a))
y' = (x * sin(a)) + (y * cos(a))
z' = z
Here is another way of viewing the same information:
|
x * |
y * |
z * |
x' |
cos(a) |
-sin(a) |
0 |
y' |
sin(a) |
cos(a) |
0 |
z' |
0 |
0 |
1 |
The table is a more concise way of summarizing the formulas. Each row
pertains to a part of the target vector. Each column represents an
element that will be multiplied. You can expand the formulas by
reading the chart. You could read the first row as this:
x' = (x * cos(a)) + (y * -sin(a)) + (z * 0)
All the data of all three functions can be encapsulated on this table.
Introducing the Matrix
Mathematicians use this type of structure all the time, and they call
it the matrix. Here is the exact same table in matrix form:
_ _
| |
| cos(a) -sin(a) 0 |
| |
| sin(a) cos(a) 0 |
| |
| 0 0 1 |
|_ _|
This particular matrix can be set at any angle of a. Given any value
of A, this matrix can generate the formulas to calculate a rotation of
a radians around the z axis. Similar matrices can be formulated for
the other axes.
Multiplying a matrix and a vector
You can multiply a vector by a matrix, giving the following results:
_ _ _ _ _ _
| x | | a b c | | xa + yb + zc |
| | | | | |
| y | * | d e f | = | xd + ye + zf |
| | | | | |
| z | | g h i | | xg + yh + zi |
|_ _| |_ _| |_ _|
You can also multiply a matrix by another matrix of the same size,
resulting in a third matrix of the same size as the first two.
This becomes useful because a point can be stored as a vector, and a
rotation can be stored as a matrix. Given any angle a you can
generate a matrix to rotate a radians around the X, Y, or Z
axis. You can multiply these three matrices to get a new matrix
combining all three rotations. Each point in a geometry can be
written as a vector, and you can get a new geometry by multiplying
each point vector by the rotation matrix.
Revisiting Scale
I mentioned above that scaling 'feels' like multiplying a vector, but
that's not exactly what happens. If you want to scale some point by
the vector <sx, sy, sz>, you can
think of it as multiplying by the following matrix:
_ _
| Sx 0 0 |
| |
| 0 Sy 0 |
| |
| 0 0 Sz |
|_ _|
If you multiply this scale matrix by each of the rotation matrices,
you'll get a three-by-three matrix which encapsulates all the rotation
and scaling on each point in the shape.
Note on translation
You might wonder how translation (which is really done with a vector
rather than a matrix) fits into all this matrix multiplication. It
turns out that computer scientists use a dirty trick. Since they
simply want to add a vector to the rest of the matrix multiplication,
they work with a four-by-four matrix instead of three-by-three. The
fourth row is always all zeros, and the fourth column contains the
translation elements. It's a sneaky trick, but it works.
Conclusion
In the final analysis, all the transformations you do to a shape are
calculated as individual matrices, and then these matrices are
multiplied together to make one master matrix of transformation. That
matrix is multiplied by each point in the shape to produce the
transformed shape. Although you don't have to do the math yourself,
it's very handy to know what's going on under the skin.
© Andy Harris
Indiana University / Purdue University, Indianapolis
email:
aharris@cs.iupui.edu
homepage:
http://www.cs.iupui.edu/~aharris