Using Three.js InstancedMesh for Efficient Rendering of Many Identical Objects
Learn how to use Three.js InstancedMesh to render thousands of identical objects with a single draw call, including setup, limits, and common pitfalls.
17 May 2026, 05:12 UTC

Useful Answer
Use InstancedMesh when you need to render many copies of the same geometry—such as trees, cubes, or particles—because it issues a single GPU draw call instead of one per object.
How InstancedMesh Works
The constructor new THREE.InstancedMesh(geometry, material, count) creates an object that shares one geometry and material across count instances. Each instance has its own 4×4 world matrix stored in an internal buffer. After setting a matrix with setMatrixAt(index, matrix) you must flag the buffer as dirty by setting instancedMesh.instanceMatrix.needsUpdate = true so Three.js uploads the changes to the GPU before the next render.
Worked Example
Below is a minimal setup that creates 1,000 boxes with random transforms and adds them as an InstancedMesh.
// geometry and material shared by all instances
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x44aa88 });
const count = 1000;
const instanced = new THREE.InstancedMesh(geometry, material, count);
// temporary Object3D to compute matrices without allocating each loop
const dummy = new THREE.Object3D();
for (let i = 0; i < count; i++) {
// random position, rotation, scale
dummy.position.set(
Math.random() * 200 - 100,
Math.random() * 200,
Math.random() * 200 - 100
);
dummy.quaternion.setFromEuler(
Math.random() * Math.PI,
Math.random() * Math.PI,
Math.random() * Math.PI
);
dummy.scale.setScalar(Math.random() * 2 + 0.5);
dummy.updateMatrix(); // compute world matrix
instanced.setMatrixAt(i, dummy.matrix);
}
// tell Three.js the matrix buffer changed
instanced.instanceMatrix.needsUpdate = true;
scene.add(instanced);
Reusing a single Object3D avoids per‑iteration allocations. updateMatrix() builds the matrix from position, quaternion, and scale, which setMatrixAt stores. The flag instanceMatrix.needsUpdate must be set after the loop so the GPU receives all matrices in one batch.
Limits
All instances share the same geometry and material, so visual variation beyond transform requires custom buffer attributes or shader changes. The instance matrix buffer consumes roughly 16 bytes per instance (four vec4s). Rendering tens of thousands of instances is usually fine, but hundreds of thousands may exceed GPU buffer limits or cause stalls. InstancedMesh also cannot animate each instance with independent curves without updating matrices each frame, which may negate the draw‑call benefit.
Common Mistakes
- Forgetting to set
instancedMesh.instanceMatrix.needsUpdate = trueafter callingsetMatrixAt. Without this flag the GPU retains the old matrices, so transforms appear unchanged. - Expecting raycasting to return one intersection per copy.
InstancedMeshreturns a single intersection object; the hit instance is identified by theinstanceIdproperty on that object. - Updating matrices every frame for static instances. If the transforms never change, compute them once outside the render loop.
Verification
Check the Three.js version (≥ r110) confirms InstancedMesh exists. Render a scene with 100 InstancedMesh cubes and compare renderer.info.render.calls before and after adding the mesh; the call count should increase by one regardless of instance count. Toggle instanceMatrix.needsUpdate after modifying a matrix and verify the instance moves only when the flag is true.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.