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 that is 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 has as its matrix the inverse of T's matrix.
i.e. T * T-1 = Identity
Transformations that do not change the shape or volume of an object - no scaling, shearing, perspective, etc.
Composed of translation and rotation
Representations for rotation:
Represent any arbitrary rotation as rotation-about-X, rotation-about-Y,
rotation-about-Z
Sometimes described as "Heading, Pitch, Roll" or similar
Generally human-friendly
Problems:
Represent any rotation by its 3x3 matrix
Or, represent translation + rotation by 4x4 matrix
Good for combining transformations and other mathematical manipulations
Not so human-friendly
Interpolation can yield non-rigid-body transformations
Similar to axis + angle representation
4-element vector: [ qw qx qy qz ] = qw + qx * i + qy * j + qz * k
i*i = -1, j*j = -1, k*k = -1, i*j = k, j*i = -k, etc.
qw = cos(angle/2)
qx = axisX * sin(angle/2)
qy = axisY * sin(angle/2)
qz = axisZ * sin(angle/2)
Combine quaternions by multiplying them
Interpolate them with "slerp" (spherical linear interpolation) or "nlerp" (normalized linear interpolation)
Grabbing an object, or dynamically attaching one to another, requires manipulating transformations.
Easiest using matrix representation of transformations
If object A has world-relative transformation TA, and object B starts out by itself, then becomes attached to A,
when B is not attached to anything, its world transformation is T1B
when B is attached to A, it will use a transformation T2B,
and its world transformation is T2B * TA
At the moment of attachment, we want these two transformations to be the same.
So, T2B = T1B * TA-1
Transformations can be applied to textures, similar to how they are applied to geometry.
The exact same OpenGL function calls are used. The only difference is that the matrix mode is changed to GL_TEXTURE.
glMatrixMode(GL_TEXTURE) glTranslatef(0.1, 0.05, 0) glMatrixMode(GL_MODELVIEW)
Setting the matrix mode to GL_TEXTURE means that any subsequent transformation calls will be applied to texture coordinates, rather than vertex coordinates.
We switch the matrix mode back to the "default" of GL_MODELVIEW when we're done, so as to not adversely affect other code.
The same effect could be achieved by changing the
texture coordinates directly.
The advantages are: GL transformation functions simplify things
and take care of the math, and transformations can be applied to
objects where we might not have direct control of the texture
coordinates.
One trick that we can use a texture transformation for is to make sure that a texture is always applied at the same scale, as an object is transformed.
If we apply a texture to an object normally, and then scale the object, the texture appears to stretch:
By applying the same scaling to the texture coordinates as to the geometry, the texture "grows", and does not stretch:
glMatrixMode(GL_TEXTURE) glLoadIdentity() glScalef(size, 1, 1) glMatrixMode(GL_MODELVIEW) glScalef(size, 1, 1)
Be aware that texture transformations are not applied to the texture per se, but to the texture coordinates.
This means that the visual result might be the opposite of what you expect - applying glRotate(30.0, 0, 0, 1) will cause the texture itself to appear to rotate 30 degrees clockwise, not counter-clockwise.
A color - [R, G, B, A] - is effectively a 4-dimensional coordinate.
It can be transformed by a matrix also.
OpenGL's Imaging subset allows such operations on pixel images and texture images.
glMatrixMode(GL_COLOR) glLoadMatrixf([0,0,1,0, 0,1,0,0, 1,0,0,0, 0,0,0,1]) glMatrixMode(GL_MODELVIEW)