Get Constraint Reaction Forces in Ammo.js

This article explains how to extract the reaction forces and torques acting upon a specific physics constraint (joint) in ammo.js. You will learn how to enable joint feedback, access the applied impulse data after a physics simulation step, and convert those impulses into readable force and torque vectors.

Understanding Reaction Forces in Ammo.js

Ammo.js (the Emscripten port of the Bullet Physics engine) handles collisions and constraints using impulses rather than continuous forces. To obtain the actual reaction forces and torques acting on a constraint, you must enable joint feedback on the target constraint. Once enabled, Ammo.js records the applied impulses during each physics step. You can then retrieve these values and divide them by the simulation time step to calculate the reaction forces.

Step-by-Step Implementation

1. Enable Joint Feedback

To begin tracking forces, you must instantiate a btJointFeedback object and assign it to your constraint. This tells the physics solver to save the constraint forces during the island solving phase.

// Assume 'constraint' is an instantiated Ammo.btTypedConstraint (e.g., hinge, point-to-point)
const jointFeedback = new Ammo.btJointFeedback();
constraint.setJointFeedback(jointFeedback);
constraint.enableFeedback(true);

2. Step the Simulation

Run your physics simulation loop as usual. The solver will populate the joint feedback object with impulse data during each step.

// Step the physics world
const timeStep = 1 / 60;
physicsWorld.stepSimulation(timeStep, 10);

3. Extract and Convert Impulses to Forces

After stepping the simulation, read the applied force and torque vectors from the joint feedback object. Because Bullet calculates impulses, you must divide the returned vectors by the simulation timeStep to get the force in Newtons (or your world’s equivalent unit of force).

// Retrieve the feedback object from the constraint
const feedback = constraint.getJointFeedback();

if (feedback) {
    // Get applied impulse vectors for Body A
    const impulseForceA = feedback.get_m_appliedForceBodyA();
    const impulseTorqueA = feedback.get_m_appliedTorqueBodyA();

    // Convert impulses to reaction forces: Force = Impulse / timeStep
    const reactionForceX = impulseForceA.x() / timeStep;
    const reactionForceY = impulseForceA.y() / timeStep;
    const reactionForceZ = impulseForceA.z() / timeStep;

    const reactionTorqueX = impulseTorqueA.x() / timeStep;
    const reactionTorqueY = impulseTorqueA.y() / timeStep;
    const reactionTorqueZ = impulseTorqueA.z() / timeStep;

    console.log(`Reaction Force: X: ${reactionForceX}, Y: ${reactionForceY}, Z: ${reactionForceZ}`);
    console.log(`Reaction Torque: X: ${reactionTorqueX}, Y: ${reactionTorqueY}, Z: ${reactionTorqueZ}`);
}

Key Considerations