Matrices pack translation, rotation, and scale into one object that transforms points. Learn how the transforms work, why matrix multiplication order matters, and how one matrix moves a whole model.
A transformation matrix is a grid of numbers that, when multiplied by a point, moves, rotates, or scales it. The power is composition: you combine translation, rotation, and scale into a single matrix, then apply it to thousands of vertices at once — exactly what the GPU does. Matrices are how every object is positioned and oriented in a scene.
A transform matrix, times a point, produces a moved point.
translate slide by an offset
rotate spin around an axis/origin
scale grow/shrink
Combine several into ONE matrix (multiply them), then apply that single
matrix to every vertex of a model:
final = translate * rotate * scale (one matrix)
worldPoint = final * localPoint (per vertex, done on the GPU)
That's why models render fast: one matrix moves the whole mesh.Each transform is a small matrix. Translation shifts by an offset (using a homogeneous 3×3 matrix so a matrix can encode a shift), rotation turns points around the origin using sine and cosine, and scale multiplies each axis. Seeing the actual numbers demystifies them — a rotation is just sin/cos placed in a grid.
import math
def rotate2d(point, angle):
c, s = math.cos(angle), math.sin(angle)
x, y = point
# rotation matrix applied to (x, y):
# [ c -s ] [x]
# [ s c ] [y]
return (x*c - y*s, x*s + y*c)
def scale2d(point, sx, sy):
return (point[0]*sx, point[1]*sy)
def translate2d(point, tx, ty):
return (point[0]+tx, point[1]+ty)
p = (1, 0)
print(rotate2d(p, math.radians(90))) # ~(0, 1) -> rotated 90°
# rotation is just sin/cos in a grid; scale multiplies axes; translate adds.Matrix multiplication is not commutative — rotate-then-translate gives a completely different result from translate-then-rotate. This trips up everyone: a common bug is a rotating object that orbits the origin because the translation happened before the rotation. The standard model order is scale, then rotate, then translate, applied right-to-left to the point.
Rotate THEN translate ≠ Translate THEN rotate:
R then T: spin in place, then move -> object rotates around ITSELF
T then R: move, then spin around origin -> object ORBITS the origin
Standard model transform order (applied right-to-left to the point):
M = Translate * Rotate * Scale
worldPoint = M * localPoint
= first Scale the model, then Rotate it, then Translate into the world.
"My object orbits instead of spinning" is almost always a wrong T/R order.Combining translation, rotation, and scale into a model matrix places an object in the world. In practice you use a math library (numpy here, or the engine’s matrix type) rather than hand-multiplying. The takeaway is conceptual: each object has a model matrix built from its position, rotation, and scale, and that matrix transforms its local vertices into world space.
import numpy as np
def model_matrix(tx, ty, angle, sx, sy):
c, s = np.cos(angle), np.sin(angle)
# 3x3 homogeneous 2D transform = Translate * Rotate * Scale
T = np.array([[1,0,tx],[0,1,ty],[0,0,1]])
R = np.array([[c,-s,0],[s,c,0],[0,0,1]])
S = np.array([[sx,0,0],[0,sy,0],[0,0,1]])
return T @ R @ S # @ is matrix multiply
M = model_matrix(tx=5, ty=0, angle=np.radians(90), sx=2, sy=2)
local = np.array([1, 0, 1]) # a local vertex (homogeneous)
world = M @ local # placed into the world
print(world[:2])
# each object stores its model matrix; the GPU applies it to every vertex.