How Matter.js Calculates Collision Penetration Depth
In Matter.js, collision penetration depth is calculated primarily using the Separating Axis Theorem (SAT) for convex polygons and geometric distance formulas for circles. The physics engine determines how deeply two intersecting bodies overlap by projecting their vertices onto potential separation axes, identifying the axis with the smallest overlap—known as the Minimum Translation Vector (MTV)—and recording that minimum overlap value as the penetration depth.
The Separating Axis Theorem (SAT) Pipeline
Matter.js relies on the Matter.SAT module for detecting
collisions between rigid bodies. The algorithm follows a structured
pipeline to determine whether an intersection exists and to quantify its
severity.
1. Generating Projection Axes
For convex polygons, potential separation axes are defined by the surface normals of the shapes' edges.
- The engine gathers the unique edge vectors for both Body A and Body B.
- Each edge vector is converted into a perpendicular normal vector and normalized to unit length.
- These normals represent every potential direction along which the two shapes could be separated.
2. Projecting Vertices onto Each Axis
For every candidate axis, Matter.js projects the vertices of both bodies onto that axis using the vector dot product:
\[\text{projection} = \mathbf{v} \cdot \mathbf{axis}\]
By evaluating all vertices for a body, the engine identifies the minimum and maximum scalar projection values:
- Body A produces a range: \([min_A, max_A]\)
- Body B produces a range: \([min_B, max_B]\)
3. Calculating the Overlap
Once the projections are mapped onto the 1D axis, the engine computes the overlap between the two intervals:
\[\text{overlap} = \min(max_A, max_B) - \max(min_A, min_B)\]
If any axis yields an overlap less than or equal to zero, a gap exists. By the Separating Axis Theorem, the shapes are not colliding, and the calculation halts immediately.
4. Determining Penetration Depth and the Normal
If every tested axis produces an overlap greater than zero, a collision has occurred. Matter.js tracks the overlap values across all evaluated axes and selects the smallest one:
- Penetration Depth: The minimum positive overlap value across all axes.
- Collision Normal: The unit vector of the axis corresponding to this minimum overlap, oriented so that it points from Body A toward Body B.
This minimum value represents the shortest distance required to push the bodies apart to resolve the collision without introducing unnecessary displacement.
Circle-to-Circle and Circle-to-Polygon Handling
Because circles have an infinite number of edge normals, Matter.js handles them through specialized projection logic:
- Circle vs. Circle: SAT is bypassed. The engine calculates the Euclidean distance between the centers of the two circles (\(d = \|\mathbf{c}_B - \mathbf{c}_A\|\)) and subtracts this from the sum of their radii (\(r_A + r_B\)). The penetration depth is \((r_A + r_B) - d\).
- Circle vs. Polygon: In addition to testing the polygon's edge normals, Matter.js includes an axis running from the circle's center to the closest vertex on the polygon. The overlap is then evaluated along this axis alongside the standard edge axes to find the minimum depth.
Resulting Collision Data
The calculated depth is assigned to the depth property
of the resulting collision object, paired with
collision.normal. The physics solver uses this depth value
in subsequent steps to apply positional correction, preventing bodies
from sinking into one another, and to calculate the corrective impulse
required to simulate realistic physical restitution.