Get Total Applied Force on Ammo.js Rigid Body

This article explains how to retrieve the total applied force acting on a specific ammo.js rigid body during a physics frame. You will learn how to use the built-in getTotalForce() method, understand the importance of timing within the simulation loop, and discover how to calculate external impact forces from collisions.

Using the getTotalForce Method

In ammo.js (the Emscripten port of the Bullet Physics engine), the btRigidBody class provides a direct method to query the accumulated forces applied by the user during the current frame. This includes forces applied via applyForce() or applyCentralForce().

To read this force, call getTotalForce() on your rigid body instance. This returns a btVector3 object:

// Ensure your rigid body is active and initialized
const rigidBody = body; // Your Ammo.btRigidBody instance

// Retrieve the total force vector
const totalForce = rigidBody.getTotalForce();

// Extract the X, Y, and Z components
const forceX = totalForce.x();
const forceY = totalForce.y();
const forceZ = totalForce.z();

console.log(`Applied Force: X: ${forceX}, Y: ${forceY}, Z: ${forceZ}`);

The Importance of Simulation Loop Timing

To get accurate readings, you must query getTotalForce() at the correct time in your game loop.

The physics engine clears the accumulated forces at the end of each simulation step inside dynamicsWorld.stepSimulation(). If you attempt to read getTotalForce() after stepSimulation() has run, the method will return zero because the forces have already been integrated into velocity and cleared.

To read the forces applied during the current frame, you must call getTotalForce() before calling stepSimulation():

// 1. Apply user forces
rigidBody.applyCentralForce(new Ammo.btVector3(0, 10, 0));

// 2. Read the total applied forces BEFORE stepping the simulation
const force = rigidBody.getTotalForce(); 
console.log(force.y()); // Outputs: 10

// 3. Step the physics world (this integrates and clears the forces)
physicsWorld.stepSimulation(deltaTime, 10);

// Reading here will output 0

Reading Collision and Contact Forces

The getTotalForce() method only tracks user-applied forces. It does not include the forces exerted by gravity or the reaction forces generated by collisions (which Bullet handles via impulses).

If you need to read the physical impact force acting on a body during a collision, you must iterate through the physics world’s contact manifolds, retrieve the applied impulse, and divide it by your simulation step time (\(Force = Impulse / dt\)):

const dispatcher = physicsWorld.getDispatcher();
const numManifolds = dispatcher.getNumManifolds();

for (let i = 0; i < numManifolds; i++) {
    const contactManifold = dispatcher.getManifoldByIndexInternal(i);
    const body0 = Ammo.castObject(contactManifold.getBody0(), Ammo.btRigidBody);
    const body1 = Ammo.castObject(contactManifold.getBody1(), Ammo.btRigidBody);

    // Check if one of the bodies is your target rigid body
    if (body0 === rigidBody || body1 === rigidBody) {
        const numContacts = contactManifold.getNumContacts();
        let totalImpulse = 0;

        for (let j = 0; j < numContacts; j++) {
            const contactPoint = contactManifold.getContactPoint(j);
            totalImpulse += contactPoint.getAppliedImpulse();
        }

        // Calculate force: Force = Impulse / deltaTime
        const collisionForce = totalImpulse / deltaTime;
        console.log(`Collision Force on body: ${collisionForce} N`);
    }
}