How Matter.js solveVelocity Handles Resting Contacts
In Matter.js, the Matter.Resolver.solveVelocity function
is responsible for adjusting the linear and angular velocities of
colliding bodies to ensure realistic physical interactions. This article
explores how the engine processes collision pairs, suppresses
micro-bouncing on resting contacts, computes normal and frictional
impulses, and applies those impulses to update both linear speed and
rotational velocity across resting bodies.
The Role of solveVelocity in the Engine Pipeline
Matter.Resolver.solveVelocity executes during the
collision resolution phase of the physics update loop. After collision
detection identifies overlapping bodies and generates contact manifolds,
solveVelocity iterates over these contact points to
calculate and apply momentum transfers (impulses).
When bodies are at rest relative to one another—such as a box resting
on a floor or stacked crates—the goal of solveVelocity is
to eliminate relative normal velocity at the contact points and oppose
relative tangential velocity (sliding) without causing instability or
visual jitter.
1. Calculating Relative Contact Velocity
For each contact point between two bodies, Body A and Body B, the solver computes the total velocity at the exact point of contact. Because a rigid body's local point velocity depends on both its center-of-mass translation and its rotation, the velocity at contact offset vector \(r\) is:
\[v_{point} = v + \omega \times r\]
Where:
- \(v\) is the linear velocity vector of the body's center of mass.
- \(\omega\) is the scalar angular velocity (in 2D).
- \(r\) is the vector pointing from the body's center of mass to the contact point.
The relative velocity \(v_{rel}\) between the two bodies at the contact point is then:
\[v_{rel} = (v_B + \omega_B \times r_B) - (v_A + \omega_A \times r_A)\]
2. Restitution Thresholding for Resting Contacts
Restitution defines how bouncy a collision is. Under standard conditions, separating velocity equals approaching velocity multiplied by the restitution coefficient. However, if applied continuously to resting contacts, even minute velocities would cause objects to vibrate or bounce perpetually.
To manage resting contacts, Matter.js evaluates whether the approaching velocity along the contact normal falls below a minimum threshold. When relative normal velocity is sufficiently small, the engine overrides the restitution coefficient, treating it effectively as zero. This dampening stops restitution from generating artificial kinetic energy, allowing bodies to settle into equilibrium.
3. Resolving Normal and Tangential Impulses
Once relative velocity is determined, solveVelocity
computes the corrective impulses required to satisfy physical
constraints:
Normal Impulse (Penetration Prevention)
The solver projects \(v_{rel}\) onto the contact normal. It determines the scalar impulse magnitude \(J_n\) necessary to bring the relative normal speed to zero (or the restitution target). The impulse is scaled by the effective mass of the system, which accounts for both the inverse masses (\(1/m_A, 1/m_B\)) and the rotational inertias (\(1/I_A, 1/I_B\)) relative to the contact point:
\[m_{eff} = \frac{1}{\frac{1}{m_A} + \frac{1}{m_B} + \frac{(r_A \times n)^2}{I_A} + \frac{(r_B \times n)^2}{I_B}}\]
Tangential Impulse (Friction)
The solver projects \(v_{rel}\) onto the tangent vector perpendicular to the normal. It calculates a friction impulse \(J_t\) to halt lateral sliding. To satisfy Coulomb's law of friction, the tangential impulse is clamped so that \(|J_t| \le \mu J_n\), where \(\mu\) is the combined friction coefficient of the two surfaces. For resting contacts with low lateral forces, this clamping prevents sliding entirely (static friction).
4. Applying Impulses to Linear and Angular Speeds
Once the total impulse vector \(J = J_n n + J_t t\) is established, it is applied directly to alter the velocities of the participating bodies:
Linear Velocity Adjustment
Linear momentum changes inversely proportional to mass:
- For Body A: \(v_A \leftarrow v_A - \frac{J}{m_A}\)
- For Body B: \(v_B \leftarrow v_B + \frac{J}{m_B}\)
Angular Velocity Adjustment
The contact impulse generates a torque around the center of mass based on the cross product of the contact offset \(r\) and the impulse vector \(J\):
- For Body A: \(\omega_A \leftarrow \omega_A - \frac{r_A \times J}{I_A}\)
- For Body B: \(\omega_B \leftarrow \omega_B + \frac{r_B \times J}{I_B}\)
Because the cross product \(r \times J\) accounts for both the normal impulse (which resists rotational tipping) and the friction impulse (which induces or counters spin), both angular and linear speeds are adjusted simultaneously in a physically consistent manner.
Iteration and Convergence
In complex scenes with resting stacks or multiple simultaneous
contacts, resolving one contact point may alter the velocities at an
adjacent contact. Matter.js addresses this by running
solveVelocity over multiple iterations, governed by the
engine.velocityIterations configuration. Through repeated
passes, velocity adjustments converge toward a balanced state where
normal velocities approach zero and friction holds resting bodies
stable.