Get Bounding Box of Three.js InstancedMesh Instance
Working with InstancedMesh in Three.js is highly
efficient for rendering thousands of identical objects, but retrieving
the bounding box of a single instance requires a specific approach. This
article explains how to calculate the precise world-space bounding box
of an individual instance within an InstancedMesh by
combining the base geometry’s bounding box with the instance’s
transformation matrix.
The Challenge with InstancedMesh Bounding Boxes
In Three.js, an InstancedMesh shares a single
BufferGeometry across all instances. Calling
instancedMesh.geometry.computeBoundingBox() only calculates
the bounding box for the base geometry at the origin
(0, 0, 0) in local space. It does not account for the
position, rotation, or scale of individual instances.
To find the bounding box of a specific instance, you must retrieve
that instance’s transformation matrix, apply the
InstancedMesh’s world matrix to it, and then use that
combined matrix to transform the base geometry’s bounding box.
Step-by-Step Implementation
Here is the step-by-step process to calculate the world-space bounding box of a specific instance:
- Compute the base geometry’s bounding box if it has not been calculated yet.
- Retrieve the instance’s local matrix using
.getMatrixAt(). - Multiply by the world matrix of the
InstancedMeshto get the instance’s world-space transformation matrix. - Clone the base bounding box and apply the combined
matrix using
.applyMatrix4().
Code Example
The following utility function extracts the bounding box for a specific instance index:
import * as THREE from 'three';
/**
* Retrieves the world-space bounding box of a specific instance within an InstancedMesh.
*
* @param {THREE.InstancedMesh} instancedMesh - The InstancedMesh containing the instance.
* @param {number} index - The index of the specific instance.
* @returns {THREE.Box3} The computed bounding box in world space.
*/
function getInstanceWorldBoundingBox(instancedMesh, index) {
// 1. Ensure the base geometry has a bounding box
const geometry = instancedMesh.geometry;
if (!geometry.boundingBox) {
geometry.computeBoundingBox();
}
// 2. Clone the base geometry's local bounding box
const instanceBox = geometry.boundingBox.clone();
// 3. Get the local transformation matrix of the specific instance
const instanceMatrix = new THREE.Matrix4();
instancedMesh.getMatrixAt(index, instanceMatrix);
// 4. Convert the local instance matrix to world space
instancedMesh.updateMatrixWorld(true); // Ensure world matrix is up to date
instanceMatrix.premultiply(instancedMesh.matrixWorld);
// 5. Apply the combined matrix to the bounding box
instanceBox.applyMatrix4(instanceMatrix);
return instanceBox;
}Explanation of Key Methods
instancedMesh.getMatrixAt(index, matrix): This copies the 4x4 transformation matrix of the instance at the specified index into the passedMatrix4object.instanceMatrix.premultiply(instancedMesh.matrixWorld): This multiplies the instance’s local matrix by the parentInstancedMesh’s world matrix. This step is necessary if theInstancedMeshitself is translated, rotated, scaled, or nested inside other 3D objects.box3.applyMatrix4(matrix): This transforms the bounding box boundaries to fit the minimum and maximum coordinates of the newly transformed space, resulting in an axis-aligned bounding box (AABB) that encapsulates the instance.