How to Perform Bounding Box Queries in Ammo.js
This article explains how to perform a bounding box query in the Ammo.js physics engine to detect all rigid bodies within a specific 3D area. You will learn how to define an Axis-Aligned Bounding Box (AABB), implement a contact result callback, execute the query using the dynamics world, and manage memory properly to prevent WebAssembly memory leaks.
To perform a bounding box query in Ammo.js, you use the
aabbTest method available on the dynamics world object.
This method tests a virtual axis-aligned bounding box against all
collision shapes in the physics world and reports any intersections
through a callback.
Here is the step-by-step implementation.
Step 1: Define the Query Bounds
First, define the minimum and maximum coordinates of the 3D space you
want to query using btVector3.
// Define the minimum and maximum corners of the bounding box
const minBounds = new Ammo.btVector3(minX, minY, minZ);
const maxBounds = new Ammo.btVector3(maxX, maxY, maxZ);Step 2: Create the Contact Callback
Ammo.js utilizes a callback system to report overlaps. You must
instantiate a ConcreteContactResultCallback and override
its addSingleResult method. This method executes whenever
an object overlaps with the defined bounding box.
const detectedObjects = [];
// Instantiate the callback object
const callback = new Ammo.ConcreteContactResultCallback();
// Override the collision result function
callback.addSingleResult = function(
manifoldPoint,
collisionObjectWrap0,
partId0,
index0,
collisionObjectWrap1,
partId1,
index1
) {
// Extract the collision objects from the wrappers
const colObj0 = Ammo.castObject(collisionObjectWrap0.getCollisionObject(), Ammo.btCollisionObject);
const colObj1 = Ammo.castObject(collisionObjectWrap1.getCollisionObject(), Ammo.btCollisionObject);
// Store unique objects detected within the bounding box
if (colObj0 && !detectedObjects.includes(colObj0)) {
detectedObjects.push(colObj0);
}
if (colObj1 && !detectedObjects.includes(colObj1)) {
detectedObjects.push(colObj1);
}
return 0; // Return value is required by the C++ signature
};Step 3: Run the Query
Invoke the aabbTest function on your Ammo.js dynamics
world instance, passing in the boundary vectors and the callback.
// Execute the bounding box query against the physics world
dynamicsWorld.aabbTest(minBounds, maxBounds, callback);After this call completes, the detectedObjects array
will contain references to all the btCollisionObject
instances that lie within or intersect the specified area. You can
identify specific objects by checking their user pointer or user
index:
detectedObjects.forEach(obj => {
const userPointer = obj.getUserPointer();
// Use the user pointer to map back to your graphics engine objects (e.g., Three.js meshes)
});Step 4: Clean Up Memory
Because Ammo.js is a WebAssembly/asm.js port of C++, you must
manually deallocate objects created with the new keyword to
prevent memory leaks.
// Free WebAssembly memory heap allocations
Ammo.destroy(minBounds);
Ammo.destroy(maxBounds);
Ammo.destroy(callback);