Prevent Tunneling in Ammo.js with setCcdMotionThreshold

This article explains how to configure the setCcdMotionThreshold method in ammo.js to prevent “tunneling”—a common physics simulation issue where fast-moving objects pass through solid barriers. You will learn the mechanics behind Continuous Collision Detection (CCD), how to determine the correct values for your rigid bodies, and how to implement the necessary code to ensure stable and accurate collision detection in your 3D projects.

Understanding Tunneling and Continuous Collision Detection (CCD)

In discrete physics simulations, object positions are updated at fixed time steps. If an object moves extremely fast, its displacement in a single physics step can be larger than the thickness of a wall it is heading toward. As a result, the object is on one side of the wall in one frame, and on the other side in the next frame. Because the object never actually intersects the wall at the exact moment of the physics step, the engine misses the collision. This phenomenon is known as tunneling.

To solve this, ammo.js (a JavaScript port of the Bullet physics engine) uses Continuous Collision Detection (CCD). CCD sweeps a sphere along the object’s movement path to test for collisions between frames.

How to Configure setCcdMotionThreshold

To enable CCD on an Ammo.btRigidBody, you must configure two parameters together: the motion threshold (setCcdMotionThreshold) and the swept sphere radius (setCcdSweptSphereRadius). Setting only one will not activate CCD.

1. Set the Motion Threshold

The setCcdMotionThreshold method determines the velocity limit at which the physics engine switches from discrete collision detection to continuous collision detection for a specific body.

If the distance an object travels in a single simulation step exceeds this threshold value, CCD is triggered.

2. Set the Swept Sphere Radius

The setCcdSweptSphereRadius method defines the radius of an invisible sphere embedded within your object. Ammo.js sweeps this sphere along the object’s travel path to test for continuous collisions.

Code Implementation

Here is how to apply these settings to a fast-moving rigid body, such as a projectile:

// Assuming 'body' is an instantiated Ammo.btRigidBody 
// and the object's physical radius or half-extent is 1.0 unit.
const objectSize = 1.0;

// 1. Configure the motion threshold.
// Trigger CCD if the object moves more than its own radius in a single step.
body.setCcdMotionThreshold(objectSize);

// 2. Configure the swept sphere radius.
// The swept sphere should be smaller than the actual object to avoid false collisions.
body.setCcdSweptSphereRadius(objectSize * 0.2);

Best Practices for Choosing Values