Appendix T—The Transformation Matrix |
The more I traced down this extensive coverage, the worse it got. Wikipedia, a resource I otherwise love, is utterly incomprehensible on the Transformation matrix . "Using homogeneous coordinates, both affine transformations and perspective projections on
Fortunately, as Chapter 15 demonstrates, you can make effective use of the Transformation class without the "required" knowledge. I was going to introduce this material in Chapter 15, but it was really not needed. So I stuck it back here in the appendices for those who never stop asking, "Why?"
The matrix is really a 3x3 matrix, that handles rotation and scale, in the top-left corner of a 4x4 matrix, that adds translation (move) transformations:
RS | RS | RS | U |
RS | RS | RS | U |
RS | RS | RS | U |
Xt | Yt | Zt | Wt |
RS | Rotation and Scale Matrix |
U | Unused or application-specific use (may always be zero) |
Xt ... | Translation Vector (Wt may always be one) |
1 | 0 | 0 | 0 |
0 | 1 | 0 | 0 |
0 | 0 | 1 | 0 |
0 | 0 | 0 | 1 |
Now let's rotate. Create a transformation matrix that specifies a rotation. (For the moment, assume this is possible. Details are coming.) Multiply this rotating matrix by the geometry's transformation matrix. The result replaces the geometry's transformation matrix. Now when you multiply each vertex by the new matrix, the result is the vertex's location after applying the rotation.
Now let's scale. It's the same as rotating. A matrix that specifies the desired scaling is multiplied by the existing matrix to get a new matrix that specifies the previous rotating plus the new scaling.
Assume your geometry has a hundred vertices. We just did one hundred matrix multiplications to rotate it; another hundred to scale it. Dumb. Let's get smart.
Take the matrix that specifies rotation. Multiply it by the matrix that specifies scaling. The result matrix specifies both rotation and scaling. Multiply the result by each vertex to locate the vertices in space. That's a hundred and one matrix multiplications. Smart.
Do you want to rotate around three axes and scale by different amounts in two axes? That would be 105 multiplcations if you do it the smart way, 500 multiplications if you're not smart. This matters. Now, how do you multiply a vertex (original location) by a matrix that specifies transformations?
x | a b c | xa + yb + zc | ||
y | * | d e f | = | xd + ye + zf |
z | g h i | xg + yh + zi |
x | 1 0 0 | x*1 + y*0 + z*0 | x | |||
y | * | 0 1 0 | = | x*0 + y*1 + z*0 | = | y |
z | 0 0 1 | x*0 + y*0 + z*1 | z |
xrot = (x * cos(a)) + (y * -sin(a)) yrot = (x * sin(a)) + (y * cos(a)) zrot = z
Vertex | X * | Y * | Z * |
---|---|---|---|
x | cos(a) | -sin(a) | 0 |
y | sin(a) | cos(a) | 0 |
z | 0 | 0 | 1 |
x | cos(a) | -sin(a) | 0 | x*cos(a) + y*-sin(a) + z*0 | xrot | |||
y | * | sin(a) | cos(a) | 0 | = | x*sin(a) + y*cos(a) + z*0 | = | yrot |
z | 0 | 0 | 1 | x*0 + y*0 + z*1 | zrot |
scaleX | 0 | 0 |
0 | scaleY | 0 |
0 | 0 | scaleZ |
Let's double our geometry's size in the x and y directions but leave it unchanged in the z direction. (In SketchUp, those are the red, greeen and blue axis directions.)
x | 2 | 0 | 0 | x*2 + y*0 + z*0 | x*2 | |||
y | * | 0 | 2 | 0 | = | x*0 + y*2 + z*0 | = | y*2 |
z | 0 | 0 | 1 | x*0 + y*0 + z*1 | z |
Multiplying one scaling matrix by another scaling matrix combines to give both operations. Multiplying a rotating matrix by a scaling matrix combines the operations.
In the last row, add a "homogeneous coordinate", [x,y,z],w
. This is trickier to pronounce than to understand. Begin with [0,0,0],1
. This specifies no translation. The fourth value is a divisor for the others, so [4,6,8],2
is another way of saying [2,3,4],1
.
The translation vector's origin point is unspecified. SketchUp's translation is always relative to the [0,0,0] origin.
To translate you add the translation (after dividing by w
if w
is not 1) to the rotated and scaled point. For more detail on the homogeneous coordinate, see this Google knol.
I have dug through many of the references Google returns if you ask about a "3d transformation matrix." Not all of them agree on every point. All agree that the exact order of applying transforms matters. Not all agree on what the order should be. I find that rotating, then scaling and last translating seems to work. (That is suggestive, but not definitive. Sorry.)
Is there a hand raised in back? "Speak up." The question is, "How do you multiply matrices?" It's like multiplying a vertex by an array, only messier. Stefan Waner at Hofstra explains the process very well. After I learned it from him I thought, "The SketchUp engineers programmed this years back. I should have just believed them."
P.S. I should have just believed them accept for the fatal bug in ComponentInstance.move!()
. To get around the bug, for Chapter 16's work, I had to program a matrix class that knew how to multiply. Thank you, Stefan Waner.