SAT Narrow-Phase Collision Detection in Matter.js

This article explains how Matter.js utilizes the Separating Axis Theorem (SAT) during its narrow-phase collision pipeline to achieve precise collision detection between convex bodies. It covers the mathematical foundation of SAT, how potential separating axes are derived, how vertex projections detect intersections, and how Matter.js extracts collision manifolds—including penetration depth and normals—to feed its constraint resolution engine.

The Role of Narrow-Phase Collision

In Matter.js, physics updates occur in distinct stages. First, the broad-phase stage uses Axis-Aligned Bounding Boxes (AABBs) or spatial hashing to quickly filter out pairs of bodies that are nowhere near each other. Once candidate pairs are identified, they are passed to the narrow-phase stage.

The narrow-phase engine needs to perform exact geometric testing. Matter.js relies on the Separating Axis Theorem (SAT) for this purpose, evaluating rigid bodies composed of convex polygons and circles.

The Separating Axis Theorem Principle

The Separating Axis Theorem states that two convex shapes do not intersect if there exists a line (an axis) onto which the projections of the two shapes do not overlap. Conversely, if the projections overlap across all possible candidate axes, the two shapes are intersecting.

If even one axis reveals a gap between the projections, Matter.js immediately confirms there is no collision and terminates further checks for that pair, saving computational resources.

Step-by-Step SAT Process in Matter.js

1. Generating Candidate Axes

Matter.js does not need to test an infinite number of axes. For two-dimensional convex polygons, the only axes capable of separating them are the perpendicular vectors (normals) to the edges of both shapes:

2. Projecting Vertices

Once candidate axes are generated, Matter.js projects the vertices of both shapes onto each axis using the vector dot product:

\[\text{projection} = \mathbf{v} \cdot \mathbf{axis}\]

For each shape, the algorithm calculates the minimum and maximum projection values, effectively mapping the 2D polygon into a 1D scalar interval \([ \min, \max ]\) along the axis.

3. Overlap Testing and Early Exits

Matter.js compares the scalar intervals of Body A and Body B on the active axis:

4. Finding the Minimum Translation Vector (MTV)

If projections overlap on every single candidate axis, a collision is confirmed. Matter.js then looks for the axis with the smallest overlap value.

This smallest overlap defines the Minimum Translation Vector (MTV):

The MTV represents the shortest distance and optimal direction required to push the two bodies apart so they no longer overlap.

5. Contact Point Generation

Knowing the normal and depth is not enough to simulate realistic angular momentum and friction; Matter.js also requires specific contact points.

Using the collision normal derived from SAT, the engine finds the "incident" edge and "reference" edge—the edges on each polygon that are most aligned against the collision normal. Matter.js then clips the incident edge against the reference edge planes to extract one or two distinct contact points, forming a contact manifold.

Practical Considerations and Limitations