Optimize Ammo.js Performance with Physics Sleeping

Ammo.js, the WebAssembly port of the Bullet physics engine, can quickly become a performance bottleneck in complex 3D web applications. This article provides a guide on how to utilize physics sleeping states—also known as rigid body deactivation—to heavily optimize your ammo.js simulation, ensuring high frame rates by bypassing physics calculations for idle objects.

Understanding Physics Sleeping in Ammo.js

In a typical 3D scene, many physics objects eventually come to rest. Calculating collisions, gravity, and velocity for hundreds of stationary objects on every frame wastes massive amounts of CPU power.

To solve this, Ammo.js employs a feature called “sleeping” (or deactivation). When a rigid body’s linear and angular velocities fall below a certain threshold for a specified amount of time, the physics engine puts the body to sleep. While asleep, the engine excludes the object from active dynamics simulation and collision detection passes, drastically reducing CPU overhead. The object remains dormant until another active physical body collides with it or a force is manually applied, at which point it “wakes up” automatically.

How to Configure and Fine-Tune Sleeping States

To maximize performance, you must properly configure how and when your rigid bodies fall asleep.

1. Enable Sleeping Globally

First, ensure that your physics world allows sleeping. When instantiating your collision dispatcher, sleeping is usually enabled by default, but you should confirm your configuration:

const collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
const dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);
// Sleeping is managed automatically by the dynamics world
const dynamicsWorld = new Ammo.btDiscreteDynamicsWorld(
    dispatcher, 
    overlappingPairCache, 
    solver, 
    collisionConfiguration
);

2. Set Custom Sleeping Thresholds

By default, Ammo.js uses predefined thresholds to determine when an object is “idle.” You can fine-tune these thresholds on a per-body basis to make objects sleep sooner. Use setSleepingThresholds(linear, angular) to define the velocity limits below which an object is considered ready to sleep:

// Lower thresholds keep objects active longer; higher thresholds make them sleep sooner
const linearThreshold = 0.8;  // Linear velocity threshold
const angularThreshold = 1.0; // Angular velocity threshold

rigidBody.setSleepingThresholds(linearThreshold, angularThreshold);

3. Adjust Deactivation Time

An object must remain below the velocity thresholds for a specific duration before it transitions to a sleeping state. You can set this duration using setDeactivationTime:

// The object must be almost still for 1.5 seconds before sleeping
rigidBody.setDeactivationTime(1.5);

Managing Activation States Manually

Ammo.js represents the state of a rigid body using integer activation states. Understanding these states allows you to force optimization on specific objects:

If you instantiate objects that you know will start in a resting position (such as debris, bricks, or dropped loot), force them to sleep immediately upon creation to save initial CPU cycles:

// Force the body to sleep immediately after adding it to the world
rigidBody.forceActivationState(2); // ISLAND_SLEEPING

Conversely, if you manually move an object via code (outside of the physics engine) and need it to interact with the environment again, you must wake it up:

rigidBody.activate();

Common Pitfalls to Avoid

To ensure sleeping states optimize your performance without breaking gameplay mechanics, keep the following practices in mind: