Transformations

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

Translation is addition of an offset. e.g. to translate by (-1, 0, 3):

    newx = x + -1
    newy = y + 0
    newz = z + 3
or
    [ newx newy newz ] = [ x y z ] + [ -1 0 3 ]





Scaling

Scaling multiplies each coordinate by a value:

    newx = x * sx
    newy = y * sy
    newz = z * sz





Rotation

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






General Transformations

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 |





Columns vs Rows

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.






Identity Matrix

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  | 





Translation Matrix

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.






Combining Transformations

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 |





Inverse Transformations

The inverse of a transformation T has as its matrix the inverse of T's matrix.

i.e. T * T-1 = Identity






OpenGL Matrices

glMultMatrix(m)
Multiply current transformation by a matrix

glLoadMatrix(m)
Replace current transformation by a matrix

glGetFloatv(GL_MODELVIEW_MATRIX)
Returns current transformation matrix





Rigid Body Transformations

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:






Euler Angles

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:






Matrices

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






Quaternions

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)






Picking Up Objects

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




Texture Transformations

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.






Texture Transformations

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.






Texture Transformations

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:






Texture Transformations

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)





Texture Transformations

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.

    





Color Transformations

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)


Creative Commons License
This document is by Dave Pape, and is released under a Creative Commons License.