This appendix gathers the book's formulas in one place, in the order the chapters teach them, so you can look one up without hunting for it. Each section names its chapters, and each formula is written as its chapter writes it. A formula here is a reminder, not an explanation: the chapter builds it up, says why it works, and shows it working in a demo.
A few conventions hold throughout. In 2D, y points down the window, as it does in SDL, and the demos work in those coordinates. Angles are in radians, and a positive angle turns from x toward y, which is clockwise on the screen. In 3D, y points up. A dot, as in a · b, is the dot product. A cross, as in a × b, is the cross product when both sides are vectors. Otherwise, × is plain multiplication.
Points and Vectors (Chapters 1 to 3)
For the book's 1,000 by 700 window, with the world's origin in the middle and its y pointing up, the two spaces convert like this:
worldX = screenX - 500
worldY = 350 - screenY
A vector is a direction and a size. These are its everyday sums:
from A to B = B - A
|v| = √(x² + y²)
distance = |B - A|
normalized = v / |v|
step = speed × dt
Compare lengths by their squares, which need no square root. A vector of length 0 has no direction, so normalized returns the zero vector for it.
The Dot and Cross Products (Chapter 4)
The dot product measures how much two vectors point the same way:
a · b = ax bx + ay by = |a| |b| cos θ
along = b · u
in view when direction · facing >= cos(halfAngle)
Here u is 1 long, and along is how far b reaches along it. The dot product is positive for vectors less than a quarter turn apart, 0 at right angles, and negative beyond.
The 2D cross product is a single number, and its sign says which side:
perp((x, y)) = (-y, x)
a × b = ax by - ay bx = perp(a) · b
side = (B - A) × (P - A)
distance = |side| / |B - A|
A positive side means P is clockwise from the line from A to B, which is to its right, as the screen shows it. The cross product's size is the area of the parallelogram that a and b make, twice their triangle's.
Angles (Chapter 5)
An angle in radians is the distance around a circle of radius 1:
s = r θ
radians = degrees × π / 180
fromAngle(θ) = (cos θ, sin θ)
cos² θ + sin² θ = 1
Going back, from a vector to its angle, takes std::atan2(y, x), which gets the angle right all the way round. Compare floats with a small tolerance, never with ==.
Rotation (Chapter 6)
A turn by θ about the origin sends the x axis to (cos θ, sin θ) and the y axis to (-sin θ, cos θ):
rotated = (x cos θ - y sin θ, x sin θ + y cos θ)
To turn about a pivot, subtract the pivot, turn, and add it back.
Motion (Chapter 7)
Each frame, the acceleration changes the velocity, drag takes its share, and then the new velocity changes the position:
vel += acc * dt
vel -= vel * (drag * dt)
pos += vel * dt
Scaling by dt makes the motion the same at any frame rate.
Interpolation and Easing (Chapter 8)
Lerp finds the value a fraction of the way between two others, and its inverse finds the fraction:
lerp(a, b, t) = a + (b - a) × t
t = (v - a) / (b - a)
smoothstep(t) = t² (3 - 2t)
A remap chains the two: the inverse lerp in one range, then the lerp in another. To close a share of a gap every frame at any frame rate, raise the share kept to the power of the frames' worth of time:
kept = 0.9 ^ (dt × 60)
share = 1 - 0.9 ^ (dt × 60)
Chapter 27 writes the same thing with a rate a second, as 1 - e^(-rate × dt).
Steering (Chapter 9)
Every steering behavior picks a desired velocity, and turns toward it:
steering = (desired - vel) / responseTime
braking distance = v² / (2 × a)
Arrive slows down inside a radius bigger than its braking distance, so that it can stop on the target.
Forces and Bouncing (Chapter 10)
A fall from a height h, and the speed that drag allows:
time = √(2 × h / g)
speed = √(2 × g × h)
terminal velocity = g / drag
A bounce splits the velocity against the surface's normal n, which is 1 long:
across = v · n
along = v - n × across
reflected = v - 2 × (v · n) × n
bounced = along - n × (across × restitution)
Friction holds a body still on a slope while tan θ ≤ μ, where μ is the friction coefficient.
Shapes, Lines and Closest Points (Chapters 11 to 13)
A box can be its corners or its center and half its size:
center = (min + max) / 2
half = (max - min) / 2
A line is a point A and a normal n, and P is on it when n · (P - A) is 0. A point's distance from the line through A and B, and the foot of its perpendicular, are these, with n 1 long:
distance = |(B - A) × (P - A)| / |B - A|
signed distance = n · (P - A)
foot = P - n × signed distance
A ray from O along d meets the segment from A along s where both are the same point:
O + t × d = A + u × s
t = ((A - O) × s) / (d × s)
u = ((A - O) × d) / (d × s)
They meet when t ≥ 0 and u is from 0 to 1. The closest point on a segment is the foot, with its fraction, (P - A) · (B - A) / |B - A|², clamped to the range from 0 to 1. The closest point in a box clamps each coordinate to the box.
Curves (Chapter 14)
A Bezier curve is lerps of lerps, which multiply out to these:
quadratic = (1 - t)² × P0 + 2(1 - t)t × P1 + t² × P2
B(t) = (1 - t)³ × P0 + 3(1 - t)²t × P1 + 3(1 - t)t² × P2 + t³ × P3
velocity = 3 × (e - d)
The velocity's d and e are de Casteljau's last two points. A Catmull-Rom spline through the waypoints W0 to W3 has these handles, between W1 and W2:
handle 1 = W1 + (W2 - W0) / 6
handle 2 = W2 - (W3 - W1) / 6
So each piece leaves W1 heading the way from W0 to W2, and the pieces join smoothly.
Overlap Tests (Chapters 15 and 16)
Two circles overlap when their centers are no farther apart than their radii added together. Compare squares:
overlap when |B - A|² <= (rA + rB)²
Two boxes overlap when their ranges overlap in x and in y both. A point is inside a convex polygon when it's on the inner side of every edge, by the cross product, as Chapter 13 found. By the separating axis theorem, two convex shapes overlap only when their shadows overlap on every axis that's an edge's normal. The axis with the least overlap gives the shortest push that parts them.
Raycasting and Response (Chapters 17 and 18)
A ray from O along d, which is 1 long, meets a circle of radius r around C at these t, with m as O - C:
t² + 2bt + c = 0 where b = m · d, and c = m · m - r²
t = -b ± √(b² - c)
With b² - c below 0, the ray misses. A fast object can't tunnel through a wall while step × cos θ ≤ 2r + thickness. After a hit, a response slides or bounces:
across = vel · n
slide: vel = vel - n × across
bounce: vel = vel - n × ((1 + e) × across)
An e of 0 slides with no bounce, and 1 bounces with no loss.
Space and Physics (Chapters 19 and 20)
Testing every pair of n objects takes n × (n - 1) / 2 tests, which a grid of cells cuts to the pairs that share a neighborhood. A cell is found with std::floor of a coordinate over the cell size. Physics adds mass:
acceleration = force / mass
momentum = mass × velocity
closing = (vB - vA) · n
j = -(1 + e) × closing / (1/mA + 1/mB)
vA after = vA - n × j / mA
vB after = vB + n × j / mB
Each body moves out of an overlap in proportion to one over its mass. A spring pulls with SPRING × (mouse - pos) - DAMPING × vel. A fixed step draws between its last two states:
alpha = accumulator / stepTime
drawn = lerp(prevPos, pos, alpha)
So the motion is smooth at any frame rate, though the physics runs at one.
Randomness and Noise (Chapter 21)
A point spread evenly over a disc takes the square root of a random u from 0 to 1:
radius = R × √u
Value noise blends random values at the corners of a grid, with smoothstep. Fractal noise adds octaves, each with twice the frequency of the one before, and half the amplitude.
Pathfinding (Chapters 22 and 23)
Breadth-first search takes cells in the order they were reached, and Dijkstra's search takes the cheapest first, from a priority queue. A* orders by an estimate of the whole route:
f = g + h
h(a) <= cost(a, b) + h(b)
Manhattan = dx + dy
Euclidean = √(dx² + dy²)
Chebyshev = max(dx, dy)
octile = max(dx, dy) + (√2 - 1) × min(dx, dy)
A heuristic that never overestimates is admissible, and A* finds the best path with it. One that meets the second line is consistent, so a cell's g is final when it's closed.
Textures (Chapter 24)
A texture's texels run row after row from the top left, four bytes each in RGBA32:
index = (y × width + x) × 4
Texture coordinates run from (0, 0) at the top left to (1, 1) at the bottom right. Moving a cell's coordinates in by half a texel keeps linear sampling from bleeding in its neighbors.
Transforms and Matrices (Chapters 25 and 26)
A child's world transform comes from its parent's. Its scale is its parent's scale times its own, and its turn is its parent's turn plus its own. Its place is its local position, taken into the world by its parent's transform. As a matrix, a transform turns a point in three steps, read from the right:
M = T R S
M p = T (R (S p))
A 2 by 2 block's determinant is its area's scale, and a negative one flips:
det = a d - b c
p = A⁻¹ (p' - t)
(A B)⁻¹ = B⁻¹ A⁻¹
The inverse of a 2 by 2 block swaps a and d, negates b and c, and divides by the determinant.
The 2D Camera (Chapter 27)
The view is the camera's placement undone, around the window's middle:
view = T(middle) S(zoom) R(-camRot) T(-camPos)
share = 1 - e^(-rate × dt)
The second line is the follow's share of the gap for a frame, the same at any frame rate.
Vectors in 3D (Chapter 28)
The 3D cross product is a vector at right angles to both of its inputs, and it gives a triangle's normal:
a × b = (ay bz - az by, az bx - ax bz, ax by - ay bx)
b × a = -(a × b)
normal = ((b - a) × (c - a)), normalized
brightness = N · L
n · (p - p0) = 0
The normal comes toward you when a, b and c run counterclockwise as you see them. Lambert's law lights a face by its brightness, with 0 for a face turned away. The last line is a plane.
3D Transforms, Projection and the Camera (Chapters 29 to 31)
A model matrix is M = T R S, and Transforming a Cube's turn is R = Rz Ry Rx. Each turn leaves its own axis alone. The perspective projection puts -z into w, and the divide by w makes far things small:
f = 1 / tan(fov / 2)
| f / aspect 0 0 0 |
| 0 f 0 0 |
| 0 0 A B |
| 0 0 -1 0 |
A = (far + near) / (near - far)
B = 2 * far * near / (near - far)
windowX = (x * 0.5 + 0.5) * WINDOW_WIDTH
windowY = (0.5 - y * 0.5) * WINDOW_HEIGHT
After the divide, depth runs from -1 at the near plane to 1 at the far one, and half its range is used up by a distance of 2 far near / (far + near). The view is the camera's placement undone, and a turn's inverse is its transpose:
C = T(eye) R
V = Rᵀ T(-eye)
f = normalize(target - eye)
s = normalize(f × up)
u = s × f
forward = (sin(yaw) cos(pitch), sin(pitch), -cos(yaw) cos(pitch))
Look-at's view has s, u and -f as its rows, and -s · eye, -u · eye and f · eye in its fourth column.
The Pipeline and Hidden Surfaces (Chapters 32 and 33)
One matrix takes a corner to clip space, where an edge is clipped at the near plane:
MVP = P V M
t = da / (da - db)
Here da and db are z + w at the edge's two ends, and the edge is cut where z + w is 0. Filling a triangle starts from Chapter 4's cross product:
(b - a) × (p - a)
z = b0 z0 + b1 z1 + b2 z2
draw a face when n · (eye - center) > 0
A pixel's three weights are its small triangles' cross products, each over the whole triangle's. Depth after the divide can be blended straight across the picture with them.
Texturing in 3D (Chapter 34)
Texture coordinates blended straight across the picture are wrong on a slant. Blend them over w, and divide:
affine u = b0 u0 + b1 u1 + b2 u2
correct u = (b0 u0 / w0 + b1 u1 / w1 + b2 u2 / w2) / (b0 / w0 + b1 / w1 + b2 / w2)
The same goes for v, and for anything else blended across a triangle in 3D.
Quaternions (Chapter 35)
A quaternion holds a turn by θ about an axis, as half the angle:
w = cos(θ / 2)
(x, y, z) = axis × sin(θ / 2)
q1 q2 = (w1 w2 - v1 · v2, w1 v2 + w2 v1 + v1 × v2)
turned point = q v q*
The product turns by q2 first, and q* is q's conjugate, with its axis reversed. Slerp walks the arc between two quaternions at an even pace, after flipping b to -b when their dot product is negative:
s0 = sin((1 - t) θ) / sin θ
s1 = sin(t θ) / sin θ
slerp(a, b, t) = s0 a + s1 b
Here θ is the angle between a and b on the sphere of quaternions, from their dot product. A camera's view turns by the matrix of its quaternion's conjugate, after the move by -eye.
