Author : Seumas McNally
Page : 1 Next >>
by Seumas McNally
Note for math weenies: This is not meant to be a full tutorial on matrices, and is also not intended to cover the math behind them in the usual manner. It is my personal way of thinking about rotation matrices in 3D graphics, and it will hopefully provide at least some people with a new (and possibly more intuitive) way of visualizing matrices that they may not have considered before.
For serious 3D graphics, you will need to use matrix math. The problem is that at first glance it seems bloody complicated. The truth is there are simpler ways to think about matrix math than as abstract rectangular arrays of numbers. My personal favorite way of thinking about and visualizing 3D rotation matrices is this:
Simple 3-by-3 Rotation Matrices can be thought of simply as three 3D vectors. And those three vectors are usually unit-length (which means having a length of 1.0, where sqrt(x*x + y*y + z*z) = 1.0) and point along the X, Y, and Z axes, respectively, of the coordinate space the matrix represents.
Matrices can be thought of as representing the transformation (or change) in orientation and position required to get from one Coordinate Space, or Frame of Reference, to another one. Imagine two people, one standing up, and one lying down (or try it yourself). To the person who is standing, up is up, down is down, forward is forward, etc. But to the person lying down, forward is really up, and backward is really down, and down is forward, and up is backward. Earth's gravity dictates that our normal frame of reference has "down" pointing towards the center of the earth, but even then, everything has its own local frame of reference, where "up" and "down" are in relation to the person or thing and not in relation to the earth. All a matrix contains is a vector pointing in the direction that the local reference frame considers "up" when seen from the global, Identity reference frame (you have to have some fixed frame that you measure everything else in relation to), plus another vector pointing "right", and another vector pointing either "forward" or "backward", depending on convention.
The Identity Matrix, which produces no rotation at all, simply has an X Axis Vector of (1, 0, 0), a Y Axis Vector of (0, 1, 0), and a Z Axis Vector of (0, 0, 1). Notice how each Axis Vector extends only along the same axis (X, Y, or Z) of the Identity coordinate system. In Matrix notation, this is usually represented (in column-major order) as:
[1, 0, 0] <- X Components of Axis Vectors
identity = [0, 1, 0] <- Y Components of Axis Vectors
[0, 0, 1] <- Z Components of Axis Vectors
^ ^ ^- Z Axis Vector
| |---- Y Axis Vector
|------- X Axis Vector
The cells are ordered (in RAM) like this:
[0, 3, 6]
[1, 4, 7]
[2, 5, 8]
This notation (which is OpenGL's notation style) fits perfectly into C's two-dimensional arrays, where the first index into the array is the Axis Vector you want (0 for X, 1 for Y, and 2 for Z), and the second index is the component (X, Y, or Z) of that Axis Vector. (It's also backwards from C's normal syntax of [row][column], where in this case you specify [column][row] in the matrix.) For example, the number in "matrix[2][1]" is the Y component of the Z Axis Vector for the matrix. A very useful product of that arrangement in RAM is that if you take the address of the X component (second index is 0) of say, the Y Axis Vector (e.g. "&matrix[1][0]"), the result is a pointer to an ordinary 3D vector, which can be passed into vector math functions that expect a pointer to a 3-value vector. This leads into a different way of thinking about the actual calculation of rotations:
Rotating a 3D point through the use of a 3-by-3 rotation matrix can be thought of (and practiced) simply as the scaling and addition of vectors. You don't even need a "matrix" to be able to do it.
What you do is this: Take the X Axis Vector of the Rotation Matrix, and scale it (multiply all three of its components by the same scaling factor) by the X component of the 3D point to be rotated, scale the Y Axis Vector by the Y component of the point, and scale the Z Axis Vector by the Z component of the point. Finally, take those three scaled vectors and add them together (add all of the X components to produce the new X, add all of the Ys to produce the new Y, etc.), and the result is your original 3D point, but rotated into the coordinate space defined by the Axis Vectors in your Matrix. The end result is the same as doing a "normal" point times matrix operation, but with an entirely different way of thinking about it.
See Visualizing Vector Addition for a visual representation of vector addition. Vector Scaling is simply the act of changing the length of the vectors without changing their direction.
To help visualize a rotation matrix, hold out your right hand in a "hand gun" position with thumb up and index finger out, then extend your middle finger so it points out of your palm. Now rotate your whole hand so that your index finger points at you, and you have a standard right-handed Identity Matrix, with your index finger the Z Axis Vector, your thumb the Y Axis Vector, and your middle finger the X Axis Vector. As you rotate your hand, those vectors will rotate in 3D space, and any points multiplied by that matrix will follow. To see for yourself how points are rotated by the matrix using the above scaling and adding method, first start with a point lying along one of the axes, say the point (5, 0, 0) along the X axis. Now the Y and Z components are zero, so the Y and Z Axis Vectors of the Matrix will be scaled to zero, and all you have to think about is the X Axis Vector, which is simply multiplied by 5 (made 5 times as long). So as the X Axis Vector of the Matrix rotates, so does the point which lies on it.
In practice, the scaling and adding of vectors can be simplified to the following math, applicable for use in an actual program. Notice that the X coordinate of the point is only ever multiplied with a component of the X Axis Vector. This is just a simplification and condensation of the scaling and adding of vectors that is still going on under the covers.
NewX = X * Matrix[0][0] + Y * Matrix[1][0] + Z * Matrix[2][0];
NewY = X * Matrix[0][1] + Y * Matrix[1][1] + Z * Matrix[2][1];
NewZ = X * Matrix[0][2] + Y * Matrix[1][2] + Z * Matrix[2][2];
Extending to Affinity
The previous section only covered rotational, or "Linear" transformations. Usually you also want to have a matrix be able to translate, or shift, a point through space as well as rotate it, and that sort of operation is called an "Affine" transformation. You do that with either a 3x4 or a 4x4 matrix, but I'll deal with 3x4 matrices to keep things simpler. 4x4 matrices enter into the realm of Homogeneous Coordinates, and Perspective transforms, which are not things you usually have to deal with yourself. A 3x4 matrix (3 tall, 4 wide) basically just adds another Vector to the matrix, but instead of being an Axis Vector, it is a Translation Vector. The representation is usually as follows:
[1, 0, 0, 0] <- X Components of Vectors
identity = [0, 1, 0, 0] <- Y Components of Vectors
[0, 0, 1, 0] <- Z Components of Vectors
^ ^ ^ ^- Translation Vector
| | |---- Z Axis Vector
| |------- Y Axis Vector
|---------- X Axis Vector
The cells
Page : 1 Next >>