Understanding ammo.js stepSimulation and Accuracy

This article explains how the stepSimulation method functions within the ammo.js physics engine and explores how its three primary parameters control the accuracy, stability, and performance of 3D physics. By understanding how to configure these parameters, developers can prevent issues like object tunneling, jittery movement, and physics lag in their web-based games and simulations.

What is the stepSimulation Method?

In ammo.js (a JavaScript port of the Bullet physics engine), the stepSimulation method is called within the main animation loop to advance the physics world forward in time. Rather than moving objects manually, you delegate the movement, collision detection, and gravity calculations to ammo.js.

The method signature is defined as:

dynamicsWorld.stepSimulation(timeStep, maxSubSteps, fixedTimeStep);

Each of these three parameters plays a critical role in balancing calculation accuracy with CPU performance.


Parameter 1: timeStep

The timeStep parameter represents the amount of real-world time (in seconds) that has passed since the last time stepSimulation was called. This is typically calculated as the delta time between animation frames.


Parameter 2: maxSubSteps

Because rendering frame rates can fluctuate, ammo.js does not calculate physics in one giant leap. Instead, it breaks the elapsed timeStep down into smaller, fixed increments. The maxSubSteps parameter defines the maximum number of these smaller increments (substeps) the engine is allowed to take during a single frame.


Parameter 3: fixedTimeStep

The fixedTimeStep parameter determines the exact duration (in seconds) of each internal substep. This is the actual resolution of your physics simulation.


The Core Equation for Stability

For your simulation to run in consistent real-time without losing accuracy or lagging, your parameters must satisfy the following inequality:

\[\text{maxSubSteps} \times \text{fixedTimeStep} \ge \text{timeStep}\]

If the elapsed frame time (timeStep) is larger than the maximum time the engine is allowed to simulate in one go (\(\text{maxSubSteps} \times \text{fixedTimeStep}\)), the simulation will lose synchronization with real time.

For high-precision simulations (e.g., fast-moving projectiles or complex mechanical joints), it is best practice to lower the fixedTimeStep to 1/120 or lower and scale up the maxSubSteps accordingly to maintain a smooth, accurate experience.