The idea is a sleight of dimension. Instead of comparing two 2-D (or 3-D) shapes directly, you
crush each one down onto a line — a 1-D shadow — and ask whether the two
shadows overlap. A shadow is just an interval
Step 1 — projecting a shape onto an axis is one dot product. Pick a direction
For a polygon you only need its vertices: the min and max over the corners is the min and max over the whole shape (convexity again).
Step 2 — a gap on one axis proves separation. Suppose for some
Then every point of
Step 3 — convexity makes the converse true. The deep half of the theorem is that if the shapes don't overlap, a separating axis is guaranteed to exist. Two disjoint convex sets can always be cleanly split by a hyperplane (the separating-hyperplane theorem); the normal of that plane is the axis on which their shadows part. So for convex shapes the test is exact, not merely conservative:
Step 4 — only finitely many axes can matter. There are infinitely many directions, but a separating plane for two polytopes can always be slid until it lies flush against a face of one of them. So you need only test a small candidate set:
A box-versus-box test in 3-D is thus
Step 5 — the algorithm, and its early-out. Loop the candidate axes; on each, project both shapes and compare intervals. The instant you find a gap, stop — you've proved they're apart, no further axes needed. This early-out is why SAT is so fast on the common case of objects not colliding: most pairs separate on the first axis or two.
Step 6 — if no axis separates them, they intersect — and you get the push-out for free. Should every axis show overlap, the shapes collide. Track the smallest overlap depth across all axes; that axis is the minimum translation vector (MTV) — the shortest shove that pulls the shapes apart. The penetration depth is the overlap amount, and the direction is that axis. One pass gives you both the boolean and the collision response.
SAT is one of two algorithms every physics engine ships for convex-convex collision. The
other is GJK (Gilbert–Johnson–Keerthi), which attacks the same question from
the opposite end. Instead of testing separating axes, GJK works in the
Minkowski difference
The trade-offs split cleanly. SAT is simplest for boxes and low-poly polytopes and hands you the penetration axis directly; its axis count grows with the face count, so it gets pricey for detailed meshes. GJK scales to arbitrary convex hulls and is fast, but on its own only answers are they touching? — recovering penetration depth needs its companion EPA (expanding polytope algorithm). Engines mix and match: SAT for the ubiquitous box pairs, GJK+EPA for the general case.