Matter.js Position Resolver: How solvePosition Works
In Matter.js, the Matter.Resolver.solvePosition function
is responsible for resolving geometric overlap between colliding rigid
bodies without introducing artificial kinetic energy into the physics
simulation. Operating as the positional correction phase of the engine's
constraint solver, it directly displaces interpenetrating bodies along
their collision normals over a configurable number of iterations. By
weighting adjustments according to inverse mass, factoring in positional
slop to prevent jitter, and applying a relaxation damping factor,
solvePosition ensures stable, non-overlapping body
arrangements even in complex scenarios like multi-body stacking.
Collision Detection and Penetration Depth
Before solvePosition executes, the collision detection
phase (using the Separating Axis Theorem) identifies colliding pairs and
calculates two essential geometric values: the minimum translation
vector (the collision normal) and the penetration depth. The penetration
depth represents how deeply the shapes overlap along the normal axis.
These metrics are stored on the collision pair objects and passed into
the resolver.
Mass-Weighted Correction Distribution
When two bodies interpenetrate, solvePosition must
decide how much each body should move to clear the overlap. Rather than
splitting the separation distance equally, the function weights the
displacement using each body's inverse mass:
\[\text{Share}_A = \frac{\text{inverseMass}_A}{\text{inverseMass}_A + \text{inverseMass}_B}\]
\[\text{Share}_B = \frac{\text{inverseMass}_B}{\text{inverseMass}_A + \text{inverseMass}_B}\]
A static body has an inverse mass of zero, meaning its share of the correction is zero, forcing the dynamic body to move the entire distance. If both bodies are dynamic and possess equal mass, each body moves by half the required separation distance.
Positional Slop and Damping
Directly applying the full separation distance in a single step often
leads to overshooting, instability, and visual jitter. To counteract
this, solvePosition incorporates two stabilization
techniques:
- Slop Allowance: A small threshold of allowable penetration is subtracted from the total penetration depth. By tolerating a microscopic amount of overlap, the engine avoids continuous, erratic adjustments for resting contacts.
- Positional Damping (Baumgarte-style relaxation): The solver does not push bodies entirely out of collision in a single iteration. Instead, it multiplies the effective penetration by a damping factor (typically around 0.2 to 0.8 depending on configuration). This gradual pushing prevents aggressive displacement that could launch adjacent objects.
Direct Position and Vertex Translation
Unlike impulse solvers that adjust linear and angular velocity,
solvePosition performs a direct geometric projection:
- The calculated scalar correction is multiplied by the collision normal to produce a translation vector.
- The vector is applied directly to the body's coordinates
(
body.position.xandbody.position.y). - The body's vertices, axes, and bounding box are translated alongside the position to keep collision geometry synchronized.
Because this displacement modifies position directly without increasing velocity, bodies do not accumulate velocity-based energy simply from being pushed out of overlapping states.
Iterative Relaxation Loop
A single push can resolve one collision while inadvertently creating
or worsening another, particularly in stacks or densely clustered
bodies. To achieve equilibrium, Matter.js executes
solvePosition repeatedly within an iterative loop
controlled by engine.positionIterations.
During each iteration, the solver cycles through all active collisions, recalculates the remaining overlap, and applies incremental positional nudges. Across successive passes, the system converges toward a state where all interpenetrations fall below the slop threshold, successfully stabilizing the simulation.