Rotation Matrices in 3-D
A game world is three-dimensional, and so are its rotations: a camera pitches up, a character
turns to face a door, a die tumbles. The
complex-number trick
was a single multiplication, but matrices generalise to three dimensions immediately — and
they remain the workhorse representation inside a vertex shader. We build the three
elementary rotations about the coordinate axes, then compose them, working in
3-D vectors.
Rotating about the x-axis
Step 1 — rotate about x. Spinning about the
x-axis leaves the x-coordinate
fixed and rotates the (y, z)-plane by
\theta — exactly the 2-D rotation we already know, now living in
the lower-right block:
R_x(\theta) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos\theta & -\sin\theta \\ 0 & \sin\theta & \cos\theta \end{bmatrix}.
The first row and first column are the untouched x-axis: a
1 on the diagonal and zeros around it.
Rotating about the y- and z-axes
Step 2 — rotate about y. Now the
y-coordinate is fixed and the
(z, x)-plane turns. The fixed row/column is the middle one (the
y-axis), and the sign pattern flips compared with the others — a
consequence of the cyclic order x \to y \to z \to x:
R_y(\theta) = \begin{bmatrix} \cos\theta & 0 & \sin\theta \\ 0 & 1 & 0 \\ -\sin\theta & 0 & \cos\theta \end{bmatrix}.
Step 3 — rotate about z. The
z-coordinate is fixed and the
(x, y)-plane turns — the plain 2-D rotation sitting in the top-left
block, with the z-axis (last row/column) untouched:
R_z(\theta) = \begin{bmatrix} \cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1 \end{bmatrix}.
In each one, the axis you spin about keeps its own coordinate, and the
2 \times 2 rotation block lives in the other two.
Composing for a general rotation
Step 4 — multiply elementary rotations to reach any orientation. A single
product of the three building blocks reaches every rotation in space. For example, pitch then
yaw then roll:
R = R_z(\gamma)\,R_y(\beta)\,R_x(\alpha).
Matrix multiplication composes the spins, and — unlike the plane — order
matters: R_x R_y \ne R_y R_x in general, because 3-D
rotations don't commute. This is precisely
composing transformations
applied to spins, and naming those three angles is the subject of the next page.
Inverting a rotation is free
Step 5 — the columns are an orthonormal right-handed frame. Each column of a
rotation matrix is the image of a basis vector; for a rotation those images are still
mutually perpendicular unit vectors (the spin doesn't stretch or shear). A matrix whose
columns are orthonormal is called orthogonal, and orthogonal matrices have a
defining property:
R^{\mathsf T} R = I.
Step 6 — read off the inverse. That equation says
R^{\mathsf T} is the inverse:
R^{-1} = R^{\mathsf T}.
Inverting a rotation costs nothing but
a transpose —
no determinant, no Gaussian elimination, just swap rows and columns. An engine that needs to
undo a camera rotation a thousand times a frame loves this. And since the frame is
right-handed (a proper rotation, no mirror flip),
\det R = +1.
Rotation about a coordinate axis by an angle \theta is given by one
of three elementary matrices, and:
-
R_x(\theta), R_y(\theta),
R_z(\theta) each fix their own axis and apply a
2\times 2 rotation to the other two coordinates;
-
any orientation is a product of these, e.g.
R = R_z(\gamma) R_y(\beta) R_x(\alpha) — and the product is
order-dependent (3-D rotations don't commute);
-
every rotation matrix is orthogonal:
R^{-1} = R^{\mathsf T}, so inverting a rotation is just a
transpose;
-
its columns are an orthonormal right-handed frame and
\det R = +1 (a proper rotation, no reflection).
Here is the most useful way to read a rotation matrix in a game. Its three columns
are the images of \hat{x}, \hat{y}, \hat{z} — which means they
are exactly the object's own local x, y and z axes expressed in world
coordinates:
R = \big[\; \mathbf{right} \;\big|\; \mathbf{up} \;\big|\; \mathbf{forward} \;\big].
The first column is where the object's right vector points in the world, the second its up
vector, the third its forward. So a rotation matrix isn't an abstract array — it is a
little gimbal-free description of which way the object is facing. Want to know where a
spaceship's nose points? Read off the appropriate column. This is also why
R^{\mathsf T} = R^{-1} is so natural: transposing turns the
columns (the local axes in world space) into rows (the world axes in local space), which is
exactly the reverse transform.
Turn a 3-D frame
Pick an axis — x, y or
z — and drag the angle. The little right-handed frame (its red
x, green y and blue
z arrows) spins about the chosen axis, shown in a simple isometric
projection. The axis you select stays put while the other two arrows swing around it — the
geometric meaning of "this row/column is fixed".