Transformations are functions that take a position and return a new position
newpos = ApplyRotation(pos)
All GL transformations (translate, rotate, scale) are simple operations on the (X, Y, Z) values of points
Translation is addition of an offset. e.g. to translate by (-1, 0, 3):
newx = x + -1 newy = y + 0 newz = z + 3or
[ newx newy newz ] = [ x y z ] + [ -1 0 3 ]
Scaling multiplies each coordinate by a value:
newx = x * sx newy = y * sy newz = z * sz
Rotation about the Z axis:
newx = x * cos(a) - y * sin(a) newy = x * sin(a) + y * cos(a) newz = z
Rotation about X or Y is similar, with just the x, y, & z variables shuffled around.
Rotation about an arbitrary axis is more complex, but based on the same idea
In general, the math for any transformation, or combination of transformations, looks like:
newx = Ax + By + Cz + D newy = Ex + Fy + Gz + H newz = Ix + Jy + Kz + L
This can be simplified by treating positions as 4-coordinate vectors, where the last coordinate (w) is usually 1.
The transformation is then a 4x4 matrix which the vectors are multiplied by.
| A E I M | [ X Y Z W ] = [ x y z w ] * | B F J N | | C G K O | | D H L P |
In some cases, the matrix transformation is written flipped around:
| x | | A B C D | | x | | y | = | E F G H | * | y | | z | | I J K L | | z | | w | | M N O P | | w |
The two are mathematically the same.
The identity matrix, generated by glLoadIdentity(), leaves vertex data unchanged:
| 1 0 0 0 | | 0 1 0 0 | | 0 0 1 0 | | 0 0 0 1 |
A translation matrix looks like:
| 1 0 0 0 | | 0 1 0 0 | | 0 0 1 0 | | tx ty tz 1 |
e.g. translating by (-1, 0, 3) is
| 1 0 0 0 | [ x y z 1 ] * | 0 1 0 0 | | 0 0 1 0 | | -1 0 3 1 |
The matrices for translation, rotation, scaling, and projections are all described in Appendix F of the OpenGL book.
Two transformations are combined by multiplying their matrices.
glTranslatef(-1,0,3) glRotatef(45, 0, 0, 1)yields:
| .707 -.707 0 0 | | 1 0 0 0 | | .707 -.707 0 0 | | .707 .707 0 0 | * | 0 1 0 0 | = | .707 .707 0 0 | | 0 0 1 0 | | 0 0 1 0 | | 0 0 1 0 | | 0 0 0 1 | | -1 0 3 1 | | -1 0 3 1 |
The inverse of a transformation T (one that "undoes" T) has as its matrix the inverse of T's matrix.
i.e. T * T-1 = Identity
Fixed-function OpenGL stores a ModelView matrix and a Projection matrix, which can be manipulated by glTranslate, glRotate, etc, as well as the following:
Shader-based OpenGL supports matrices as a basic data type in shaders, but does not include glTranslate, etc.
They must be replaced by a separate library, with the matrices passed as shader attributes.
Fixed-function OpenGL maintains a stack of saved transformation matrices.
glPushMatrix() & glPopMatrix() save and restore transformation state.
Make sure you always have the same number of pushes & pops.
The number of transformations you can save is finite; it is at least 32.
Example: pushpop.py
Hierarchical transformations can be thought of as transformations that are "attached to" other transformations.
They are used to transform objects relative to other objects.
A common use is in articulated bodies.
We can draw this "car" by transforming the two wheels relative to the body of the car.
We'd like each wheel to be affected by the car body's transformation, but not by any other wheel's transformation.
This can be accomplished by saving & restoring transformation state.
apply body transformation draw body save state apply front wheel transformation draw wheel restore saved state apply rear wheel transformation draw wheel
Examples:
Hierarchical transformations are often represented as a tree of transformations.
This is the basis of scene graph systems.