Ammo.js Collision Margin and Stacked Bodies
This article explains how the collision margin in ammo.js (the JavaScript port of the Bullet physics engine) impacts the stability, alignment, and resting contact of stacked rigid bodies. You will learn how the collision margin creates a virtual boundary around shapes, how it prevents interpenetration, and how to configure it to avoid visual gaps or physical jitter in your 3D physics simulations.
What is Collision Margin in Ammo.js?
In ammo.js, the collision margin is a small, protective buffer zone added around collision shapes. Instead of calculating collisions exactly at the polygon surface, the physics engine uses this margin to detect and resolve contacts before the core geometries actually intersect. By default, Bullet/ammo.js sets this margin to 0.04 units.
For some shapes, like spheres and capsules, the margin is “internal” (subtracted from the total size), meaning the physical dimensions match the graphical representation. For other shapes, like boxes and convex hulls, the margin is “external” (added to the exterior), expanding the physical collision boundary slightly beyond the original geometry dimensions.
Effect on Resting Contact and Visual Gaps
When rigid bodies are stacked, they rely on resting contact to remain stable. The collision margin directly dictates where this resting contact occurs:
- Floating Appearance (Visual Gaps): Because the collision boundary of an externally margined shape (like a box) is expanded, two stacked boxes will come to rest on their margin boundaries rather than their actual polygon faces. This creates a visible gap between the stacked objects.
- Mesh Penetration: If you attempt to completely remove the margin (setting it to 0) to eliminate the visual gap, you remove the engine’s buffer. The stacked bodies will likely penetrate each other’s actual geometry before a collision is registered, resulting in constant micro-collisions as the engine tries to push them apart.
Impact on Stack Stability and Jitter
Stacking multiple bodies increases the cumulative mass and force acting on the bottom-most contacts. The collision margin plays a vital role in maintaining stack stability:
- Preventing Explosive Separation: Without a sufficient collision margin, deep interpenetration occurs during heavy loads. When the engine detects deep penetration, it applies a large corrective force to separate the bodies. In a stack, this corrective force propagates upward, causing the entire stack to jitter, wobble, or violently explode.
- Smoother Constraint Resolution: The margin allows ammo.js to generate contact manifolds early. This predictive collision detection ensures that corrective forces are applied gradually, keeping resting contacts quiet and stable even under heavy stacking loads.
How to Optimize Margins for Stacking
To achieve stable stacks without unsightly visual gaps, you can apply the following techniques:
- Shrink the Graphical Mesh: If you must use a standard collision margin for stability, shrink your visual 3D mesh slightly so that it matches the inner boundary of the collision shape, masking the visual gap.
- Adjust the Margin Judiciously: For small-scale
objects, the default 0.04 margin might be too large. You can lower the
margin using
shape.setMargin(0.01), but avoid setting it to absolute zero. - Use Implicit Margin Shapes: Whenever possible, use spheres, capsules, or cylinders for stacked components. Because their margins are embedded internally, they transition into resting contact seamlessly without creating external visual gaps.