Merge Multiple Geometries in Three.js
In Three.js, rendering hundreds of individual 3D objects can severely
degrade performance due to excessive draw calls. This article explains
how to optimize your WebGL scenes by efficiently merging multiple static
geometries into a single geometry using the
BufferGeometryUtils module, significantly reducing draw
calls and boosting your application’s frame rate.
Why Merge Geometries?
Every individual mesh in Three.js requires a separate “draw call” to the GPU. When rendering thousands of static objects—like a forest of trees or a city of buildings—the CPU becomes bottlenecked by managing these calls.
By merging separate geometries into one, the GPU can render all the combined shapes in a single draw call. This optimization is ideal for static scenes where individual objects do not need to move, rotate, or scale independently after creation.
Step 1: Import BufferGeometryUtils
Three.js provides a dedicated utility for combining geometries. To
use it, you must import BufferGeometryUtils from the
examples folder.
import * as THREE from 'three';
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js';Step 2: Prepare and Transform Geometries
Because merged geometries will share a single origin, you must apply any position, rotation, or scale transformations directly to the geometry objects before merging them. If you do not do this, all merged shapes will overlap at the center of the scene.
const geometries = [];
// Create multiple geometries and apply transformations
for (let i = 0; i < 1000; i++) {
const geometry = new THREE.BoxGeometry(1, 1, 1);
// Translate, rotate, or scale the geometry directly
geometry.translate(
Math.random() * 100 - 50,
Math.random() * 100 - 50,
Math.random() * 100 - 50
);
geometries.push(geometry);
}Step 3: Merge and Create the Mesh
Once you have gathered all transformed geometries in an array, pass
them to BufferGeometryUtils.mergeGeometries(). This
function returns a single, optimized BufferGeometry.
// Merge all geometries into a single BufferGeometry
const mergedGeometry = BufferGeometryUtils.mergeGeometries(geometries, true);
// Create a single material
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
// Create the final single mesh and add it to the scene
const mergedMesh = new THREE.Mesh(mergedGeometry, material);
scene.add(mergedMesh);
// Optional: Clean up memory of original geometries
geometries.forEach(geometry => geometry.dispose());Handling Multiple Materials
By default, merging geometries works best when they all share a single material. If your geometries require different materials, you have two options:
- Merge by Material: Group your geometries by material, and perform a separate merge for each group. This results in one draw call per material, which is still highly efficient.
- Use Material Groups: If you pass
trueas the second argument tomergeGeometries(as shown in the code above), Three.js creates groups within the merged geometry. You can then apply an array of materials to the final mesh. However, this will still result in multiple draw calls internally (one per material group).