Box3D Continuous Collision Detection: How It Prevents Tunneling for Fast-Moving Objects

Box3D prevents tunneling by computing the exact time-of-impact (TOI) for fast-moving bodies, then advancing the simulation only up to that collision fraction before applying impulses, ensuring high-velocity objects never pass through obstacles.

Box3D, Erin Catto's open-source 3D physics engine, implements a robust continuous collision detection (CCD) system to handle fast-moving projectiles and high-velocity rigid bodies. Unlike discrete collision detection which only checks positions at frame boundaries, this pipeline calculates precise collision moments along a body's swept path, eliminating the tunneling artifacts common in bullet-physics simulations.

Identifying Fast Bodies for CCD

Before the solver runs, Box3D flags bodies that require continuous collision detection. A body is marked with the b3_isFast or b3_isBullet flag either explicitly by the user or automatically when its linear velocity exceeds a threshold (typically b3_LINEAR_SLOP * 20).

In src/physics_world.c (lines 1400-1415), the simulation step iterates through bodies and sets these flags based on velocity magnitude. The CCD stage then processes only bodies carrying these flags, ensuring computational overhead is spent only on objects that actually need swept collision tests.

The CCD Pipeline Architecture

The continuous collision detection system runs after the broad-phase but before the discrete impulse solver. It operates through the b3SolveContinuous function in src/solver.c, which orchestrates the following stages:

Sweep Construction with b3Sweep

For each flagged body, Box3D constructs a b3Sweep structure that captures the body's transform at the start and end of the time step. As implemented in src/solver.c (lines 886-894), the sweep is re-centered on the body's initial position (base) to maintain floating-point precision during calculations. This structure stores the linear and angular displacement, enabling accurate motion interpolation.

Broad-Phase Query and Collision Filtering

The system calculates an axis-aligned bounding box (AABB) that encompasses the entire sweep path, then queries the dynamic tree for potential colliders. The callback function b3ContinuousQueryCallback (defined in src/solver.c, lines 52-80) performs aggressive filtering to eliminate false positives:

  • Self-collision rejection: Ignores shapes belonging to the fast body itself
  • Same-body elimination: Discards shapes attached to the same rigid body
  • Sensor masking: Filters sensor shapes unless both bodies are sensors
  • Layer masking: Applies collision filter masks from b3Filter

Time-of-Impact Computation

For each valid shape pair, Box3D invokes b3ShapeTimeOfImpact in src/shape.c (lines 2235-2260). This function dispatches to shape-specific swept collision algorithms (supporting spheres, capsules, convex hulls, and meshes) and returns a b3TOIOutput structure containing:

  • fraction: The normalized time [0,1] when collision occurs
  • point: The contact point in world coordinates
  • normal: The collision normal vector
  • Iteration counters: Statistics for distance, push-back, and root-finding iterations

Contact Resolution with Reduced Time Steps

Once the earliest TOI is found, the solver clears the b3_isFast flag and records the hit fraction in the b3ContinuousContext (defined in src/solver.c, lines 317-336). The simulation then re-integrates the fast body only up to the collision fraction, inserts the contact, and proceeds with impulse resolution. This guarantees that bodies never penetrate, as the discrete solver handles the collision at the exact sub-step where contact first occurs.

Core Data Structures

The CCD system relies on three primary structures defined in the solver and shape modules:

  • b3ContinuousContext: Holds the world reference, fast body pointer, current best TOI fraction, sensor hit buffers (up to B2_MAX_CONTINUOUS_SENSOR_HITS), and iteration statistics (lines 317-336 in src/solver.c)
  • b3Sweep: Represents the linear-angular interpolation of a body's motion, storing initial and final transforms plus the local center offset
  • b3TOIOutput: The standardized result format containing fractional time, contact point, normal, and algorithm-specific iteration counts

Implementing CCD in Your Project

Enabling Continuous Collision Detection

To force CCD on a specific body, set the fast body flag manually:

// In src/physics_world.c, bodies are flagged automatically based on velocity,
// or you can manually enable CCD:
b3BodySim* bodySim = b3GetBodySim(world, body);
bodySim->flags |= b3_isFast;  // or b3_isBullet for bullet-style detection

The solver asserts that flagged bodies are processed in b3SolveContinuous via B3_ASSERT(fastBodySim->flags & b3_isFast).

Automatic Velocity-Based Triggering

Box3D automatically flags bodies when velocity exceeds safety thresholds:

b3Vec3 highVelocity = {50.0f, 0.0f, 0.0f};  // Fast-moving projectile
b3SetLinearVelocity(world, bodyId, highVelocity);
// Automatically triggers CCD in physics_world.c if |v| > b3_LINEAR_SLOP * 20

Retrieving Sensor Hits

CCD supports sensor detection for triggers and detectors:

// After b3World_Step:
b3ContinuousContext* ctx = &fastBodySim->continuousContext;
for (int i = 0; i < ctx->sensorCount; ++i) {
    b3SensorHit* hit = &ctx->sensorHits[i];
    float fraction = ctx->sensorFractions[i];
    // Process sensor trigger at time fraction
}

Key Source Files

The CCD implementation spans these critical files in the erincatto/box3d repository:

File Function Role
src/solver.c b3SolveContinuous, b3ContinuousQueryCallback Main CCD pipeline and context management
src/shape.c b3ShapeTimeOfImpact Shape-specific swept collision algorithms
src/physics_world.c Body flagging logic Velocity threshold checking and CCD integration
src/dynamic_tree.c Tree queries Broad-phase AABB queries for sweep paths

Summary

  • Box3D CCD runs between broad-phase and discrete solving, computing exact collision times for fast-moving bodies
  • b3_isFast/b3_isBullet flags trigger the sweep-based collision detection pipeline
  • b3Sweep structures capture motion paths with precision-safe re-centering
  • Time-of-impact calculations determine the exact fractional time when shapes first contact
  • Sub-step integration advances bodies only to the collision point, preventing tunneling completely
  • Sensor support allows CCD to capture trigger events without generating contact impulses

Frequently Asked Questions

What is the difference between b3_isFast and b3_isBullet in Box3D?

Both flags trigger continuous collision detection, but b3_isBullet typically indicates extremely high-velocity projectiles that require special handling, while b3_isFast marks general high-velocity bodies. The CCD pipeline processes both identically in b3SolveContinuous, but bullet bodies may have different default thresholds or filtering behaviors depending on the specific simulation configuration in physics_world.c.

How does Box3D handle CCD for sensor shapes versus solid bodies?

The b3ContinuousQueryCallback stores sensor hits separately from solid contacts in the b3ContinuousContext structure. While solid hits immediately reduce the simulation time step and generate contact constraints, sensor hits populate a dedicated buffer (up to B2_MAX_CONTINUOUS_SENSOR_HITS) that developers can query after the step. This allows triggers to fire without affecting the physics resolution of the fast body.

Can Box3D CCD handle collisions between two fast-moving dynamic bodies?

Yes. The pipeline queries all dynamic tree proxies, including other fast bodies. When two flagged bodies approach each other, each runs its own CCD sweep against the other. The solver computes TOI for both perspectives and handles the earliest collision first, then potentially re-runs CCD for the remaining time step if additional collisions occur.

Why does Box3D re-center sweeps on the body's base position?

Floating-point precision degrades when calculating swept collisions far from the origin. By re-centering the b3Sweep on the body's initial position (base) as seen in src/solver.c (lines 886-894), Box3D ensures that relative motion calculations maintain numerical stability, particularly important for small objects moving at high speeds across large world coordinates.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →