Identify Colliding Objects Using Ammo.js Manifolds

In 3D web development using ammo.js—the JavaScript port of the Bullet physics engine—detecting collisions requires querying the physics world’s collision dispatcher. This article provides a direct, step-by-step guide on how to iterate through contact manifolds, retrieve the pointers for the two colliding bodies, and identify the corresponding 3D objects in your JavaScript application.

Understanding the Manifold Pointer

In ammo.js, a collision manifold (btPersistentManifold) caches contact points between pairs of colliding objects. To find which objects are colliding, you must query the dispatcher for these manifolds, verify that an active contact exists, and then extract the collision objects.

Step-by-Step Implementation

1. Retrieve the Dispatcher and Iterate Manifolds

First, access the collision dispatcher from your physics world during your animation or physics update loop. You will iterate through all active manifolds.

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

for (let i = 0; i < numManifolds; i++) {
    const manifold = dispatcher.getManifoldByIndexInternal(i);
    
    // Only proceed if there is at least one actual contact point
    const numContacts = manifold.getNumContacts();
    if (numContacts > 0) {
        // Colliding objects are processed here
    }
}

2. Extract the Colliding Bodies

From the manifold pointer, use getBody0() and getBody1() to obtain references to the two colliding objects. You must use Ammo.castObject to cast these generic pointers into btCollisionObject instances.

const ob0 = manifold.getBody0();
const ob1 = manifold.getBody1();

const body0 = Ammo.castObject(ob0, Ammo.btCollisionObject);
const body1 = Ammo.castObject(ob1, Ammo.btCollisionObject);

3. Identify the Objects Using User Pointers

Because ammo.js runs in WebAssembly/C++, the rigid bodies are pointers and do not automatically contain your custom JavaScript properties. To identify which game objects or Three.js meshes these bodies belong to, you should assign a unique identifier or pointer when creating the rigid bodies.

Setting the Identifier (During Object Creation)

When you initially create your rigid body, assign a unique ID or reference using setUserPointer or setUserIndex:

// Example: Storing a unique ID integer
rigidBody.setUserIndex(gameObject.id);

// Example: Storing a pointer/reference to a custom object (if supported by your build)
// rigidBody.setUserPointer(gameObjectPointer);

Retrieving the Identifier (During Collision Loop)

Inside your collision loop, retrieve these values to identify the colliding pair:

const id0 = body0.getUserIndex();
const id1 = body1.getUserIndex();

console.log(`Collision detected between Object ID: ${id0} and Object ID: ${id1}`);

Using getUserIndex() is the most reliable, cross-platform method to map WebAssembly physics bodies back to your JavaScript application state.