Ammo.js Heightfield vs Static Triangle Mesh Performance
This article compares the performance differences between
btHeightfieldTerrainShape and static triangle meshes
(btBvhTriangleMeshShape) in ammo.js. When building physics
for 3D web applications, choosing the right shape for terrain and
environment collision is critical for maintaining high frame rates. We
will examine memory consumption, CPU collision detection efficiency,
initialization overhead, and functional limitations to help you make an
informed architectural decision.
Memory Consumption
The btHeightfieldTerrainShape is highly optimized for
memory efficiency. It represents terrain using a regular grid of
elevation data, storing only a single height value per grid intersection
(typically as a flat array of floats or integers).
In contrast, a static triangle mesh
(btBvhTriangleMeshShape) requires storing three-dimensional
coordinate data for every vertex, an index buffer to define the
triangles, and a Bounding Volume Hierarchy (BVH) tree structure to
accelerate collision queries. For large-scale maps, a static triangle
mesh can easily consume several times more memory than a heightfield of
equivalent resolution, which can quickly lead to browser tab crashes on
mobile devices with limited RAM.
Collision Detection Speed
During the physics simulation, ammo.js must perform collision detection between dynamic rigid bodies and the terrain.
- Heightfields: Because the data is structured as a regular 2D grid, the physics engine can project a colliding body’s bounding box directly onto the grid. This allows for \(O(1)\) constant-time lookup to locate the exact terrain cells involved in the collision, leading to extremely fast narrow-phase collision calculations.
- Static Triangle Meshes: To find collisions, the engine must traverse the AABB (Axis-Aligned Bounding Box) tree structure of the BVH. This traversal operates at \(O(\log N)\) logarithmic time relative to the number of triangles. While highly optimized, tree traversal still introduces more CPU overhead and cache misses than direct grid indexing, resulting in slower collision resolution as the complexity of the scene increases.
Initialization and Loading Times
Initializing a btBvhTriangleMeshShape requires ammo.js
to build the BVH tree out of your mesh data. For detailed meshes with
tens of thousands of triangles, this calculation is computationally
expensive and runs on the main browser thread (unless offloaded to a Web
Worker). This can cause noticeable stuttering, frame drops, or long
loading screens during scene initialization.
Creating a btHeightfieldTerrainShape is nearly
instantaneous. The engine simply references the existing array of height
values, requiring no complex tree construction during startup.
Functional Differences and When to Use Which
While btHeightfieldTerrainShape is superior in
performance, it has strict geometric limitations: * Heightfield
Limitations: It only supports 2.5D surfaces. It cannot
represent overhangs, caves, tunnels, or vertical walls that overlap on
the vertical axis. * Static Mesh Flexibility: A static
triangle mesh supports arbitrary 3D geometry, making it necessary for
complex environments containing arches, indoor structures, cliffs, and
vertical obstacles.
Summary
For standard outdoor terrains,
btHeightfieldTerrainShape is the superior
choice, offering drastically faster initialization, lower
memory usage, and better CPU performance. Use
btBvhTriangleMeshShape only for complex, arbitrary
static geometry like buildings, caves, or indoor levels where
overlapping 3D structures are functionally required.