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:

  1. Compute the base geometry’s bounding box if it has not been calculated yet.
  2. Retrieve the instance’s local matrix using .getMatrixAt().
  3. Multiply by the world matrix of the InstancedMesh to get the instance’s world-space transformation matrix.
  4. 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