How Matter.js Calculates Penetration Depth and MTV
Matter.js determines collision responses between rigid bodies by implementing the Separating Axis Theorem (SAT) to detect overlapping geometries. During this process, the physics engine identifies candidate normal axes, projects the vertices of both colliding bodies onto these axes, and measures the resulting intervals. By evaluating the smallest positive overlap across all projected axes, Matter.js defines the penetration depth and its corresponding Minimum Translation Vector (MTV), which dictates the exact distance and direction required to separate the overlapping shapes.
Candidate Axis Generation
Matter.js relies on the convex hull representation of shapes. To evaluate whether two convex bodies intersect, the engine must test a specific set of candidate axes:
- Polygon-to-Polygon: The engine extracts the edge vectors of both bodies and computes their perpendicular normals. For two polygons with \(n\) and \(m\) vertices, up to \(n + m\) potential axes are evaluated.
- Circle Interactions: When circles or rounded bodies are involved, the candidate axes include the normalized vector connecting the centers of the two bodies, as well as vectors connecting the circle's center to the closest vertex of an adjacent polygon.
Projecting Vertices Onto the Axes
For each candidate axis, Matter.js normalizes the axis vector to ensure unit length (\(\hat{u}\)). It then projects every vertex of Body A and Body B onto this axis using the scalar dot product:
\[\text{projection} = \vec{v} \cdot \hat{u}\]
By tracking the minimum and maximum scalar projections for each body, Matter.js creates two 1D intervals:
- \(\text{Interval}_A = [\min_A, \max_A]\)
- \(\text{Interval}_B = [\min_B, \max_B]\)
Overlap Detection and Early Exit
If any candidate axis demonstrates a gap where \(\max_A < \min_B\) or \(\max_B < \min_A\), the bodies do not intersect. According to SAT, finding a single separating axis confirms that no collision has occurred. When this happens, Matter.js stops further calculation for that pair and returns no collision data, optimizing performance.
If an overlap exists on the tested axis, the scalar overlap distance is calculated as:
\[\text{overlap} = \min(\max_A, \max_B) - \max(\min_A, \min_B)\]
Determining Penetration Depth and the MTV
When an overlap occurs across every single candidate axis, a collision is confirmed. Matter.js then resolves the exact collision manifold:
- Finding Minimum Overlap: The engine iterates through the overlaps recorded for each axis and selects the axis associated with the absolute smallest scalar overlap value.
- Assigning Penetration Depth: The value of this
smallest overlap represents the penetration depth
(
collision.depth). It signifies the minimum distance required to push the bodies apart so they no longer intersect. - Orienting the Normal: Matter.js ensures the chosen unit axis points from Body A toward Body B. If the projection shows the axis pointing in reverse relative to the bodies' centers of mass, the engine flips the direction of the vector.
- Constructing the MTV: The final Minimum Translation Vector is the product of the oriented unit normal and the penetration depth:
\[\vec{\text{MTV}} = \text{depth} \times \hat{n}\]
This vector is subsequently passed to the constraint and position resolution phases of Matter.js, allowing the engine to offset the bodies' positions proportionally based on their respective inverse masses.