Transform Order

Here is the bug that bites everyone at least once: you translate your character, you rotate it, and instead of spinning on the spot it swings around the map like a hammer thrower. The cause is one of the most important facts in all of linear algebra — matrix multiplication is not commutative. The order in which you apply transforms changes the answer, and swapping two of them is not a harmless typo.

AB \;\neq\; BA \quad \text{in general.}

A worked example: translate-then-rotate vs rotate-then-translate

Take a concrete case. Let R = R(90^\circ) = \left[\begin{smallmatrix} 0 & -1 \\ 1 & 0 \end{smallmatrix}\right] (a quarter-turn) and \vec{t} = (3, 0) (slide three to the right). Apply both to the point \vec{p} = (1, 0), in each order.

Step 1 — translate, then rotate. First slide, then turn the result about the origin:

R(\vec{p} + \vec{t}) = R\begin{bmatrix} 4 \\ 0 \end{bmatrix} = \begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix} \begin{bmatrix} 4 \\ 0 \end{bmatrix} = \begin{bmatrix} 0 \\ 4 \end{bmatrix}.

Step 2 — rotate, then translate. First turn about the origin, then slide:

R\vec{p} + \vec{t} = \begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix} \begin{bmatrix} 1 \\ 0 \end{bmatrix} + \begin{bmatrix} 3 \\ 0 \end{bmatrix} = \begin{bmatrix} 0 \\ 1 \end{bmatrix} + \begin{bmatrix} 3 \\ 0 \end{bmatrix} = \begin{bmatrix} 3 \\ 1 \end{bmatrix}.

Step 3 — compare. Same point, same rotation, same translation — different destinations: (0, 4) versus (3, 1).

R(\vec{p} + \vec{t}) = (0, 4) \;\neq\; (3, 1) = R\vec{p} + \vec{t}.

Step 4 — see why geometrically. Rotation is always about the origin. If you translate first, the object is now far from the origin, so the rotation swings it in a wide arc around the origin — the "hammer thrower". If you rotate first, the object spins in place at the origin and only then slides out to its spot — which is what you almost always actually want.

Which way do I read the product?

Step 5 — mind the vector convention. The order you write the matrices depends on whether your vectors are columns or rows, and the two graphics conventions read in opposite directions:

Step 6 — note they're transposes of one another. The two write the same pipeline in reversed order, because (ABC)^{\top} = C^{\top} B^{\top} A^{\top}. Pick a convention and stick to it — half of all "my transforms are backwards" bugs are a column/row mix-up.

Because matrix multiplication is not commutative, the order of transforms is load-bearing:

You place a coin at (10, 0) and ask it to spin to show off, so you set its rotation each frame. But it doesn't spin where it stands — it sails in a huge circle around the world origin, ten units away. The fix is the whole lesson: you built R \cdot T (translate first, then rotate, so the rotation orbits the far-away coin around the origin) when you wanted T \cdot R (rotate the coin in place at the origin, then translate it out to (10, 0)).

\underbrace{T \cdot R}_{\text{spins in place}} \quad\text{not}\quad \underbrace{R \cdot T}_{\text{orbits the origin}}.

To spin about the object's own centre when it's already elsewhere, the general recipe is "translate to the origin, rotate, translate back" — T(\vec{c})\,R\,T(-\vec{c}) — the same non-commutativity, now working for you.