Stop Rigid Body Velocity with Counter Impulse in Ammo.js

This article explains how to completely counteract and stop the linear velocity of a rigid body in the Ammo.js physics engine using an impulse. You will learn the mathematical logic behind calculating the counteracting impulse, how to retrieve the body’s mass and current velocity, and see a practical JavaScript code implementation to instantly bring any moving physics body to a complete halt.

The Physics Behind the Counter-Impulse

In physics, an impulse (\(\vec{J}\)) is defined as the change in momentum. The formula relating impulse, mass (\(m\)), and change in velocity (\(\Delta \vec{v}\)) is:

\[\vec{J} = m \cdot \Delta \vec{v}\]

To bring a moving body to a complete stop, your target velocity is zero. Therefore, the required change in velocity (\(\Delta \vec{v}\)) is the negative of the body’s current velocity (\(\vec{v}_{current}\)):

\[\Delta \vec{v} = 0 - \vec{v}_{current} = -\vec{v}_{current}\]

Substituting this back into the impulse formula gives the equation for the exact counter-impulse required to stop the body:

\[\vec{J}_{counter} = -m \cdot \vec{v}_{current}\]

Implementation in Ammo.js

To apply this in Ammo.js, you must retrieve the body’s current linear velocity, calculate its mass using its inverse mass, multiply them together negatively, and apply the resulting vector as a central impulse.

Here is the step-by-step code implementation:

// Assuming 'body' is your Ammo.btRigidBody instance

// 1. Get the body's current linear velocity vector
const velocity = body.getLinearVelocity();

// 2. Get the inverse mass of the body
const invMass = body.getInvMass();

// If invMass is 0, the object is static/kinematic and cannot receive impulses
if (invMass > 0) {
    // Calculate the actual mass (mass = 1 / invMass)
    const mass = 1.0 / invMass;

    // 3. Calculate the counter-impulse vector components (-mass * velocity)
    const impulseX = -velocity.x() * mass;
    const impulseY = -velocity.y() * mass;
    const impulseZ = -velocity.z() * mass;

    // Create the Ammo.btVector3 for the counter-impulse
    const counterImpulse = new Ammo.btVector3(impulseX, impulseY, impulseZ);

    // 4. Apply the impulse directly to the center of mass of the body
    body.applyCentralImpulse(counterImpulse);

    // 5. Clean up the allocated Ammo vector to prevent memory leaks
    Ammo.destroy(counterImpulse);
}

Important Considerations