javascriptroom blog

How to Get Bounding Box for Groups in Three.js: Calculate Height & Width with Box3

Three.js is a powerful JavaScript library for creating 3D graphics in the browser, enabling developers to build immersive 3D scenes, games, and interactive applications. A common requirement in 3D development is understanding the spatial dimensions of objects—specifically, their bounding boxes. Bounding boxes help with collision detection, object positioning, UI alignment, and optimizing rendering (e.g., frustum culling).

While calculating bounding boxes for individual meshes is straightforward, groups (collections of meshes or other objects) require special consideration. A THREE.Group in Three.js acts as a container for multiple objects, and its bounding box represents the combined spatial extent of all its children. In this guide, we’ll explore how to use THREE.Box3 to compute the bounding box of a group, extract its height, width, and depth, and handle edge cases like empty groups or dynamic updates.

2026-02

Table of Contents#

  1. What is a Bounding Box in Three.js?
  2. Why Groups Matter: Understanding THREE.Group
  3. Prerequisites
  4. Step-by-Step Guide: Calculate Bounding Box for a Group
  5. Handling Edge Cases
  6. Practical Examples
  7. References

1. What is a Bounding Box in Three.js?#

A bounding box is an axis-aligned rectangular prism (or "box") that encloses a 3D object, representing its minimum and maximum spatial extent along the X, Y, and Z axes. In Three.js, the THREE.Box3 class is used to define such boxes.

Key Properties of THREE.Box3:#

  • min: A THREE.Vector3 representing the smallest (minimum) X, Y, Z coordinates of the box.
  • max: A THREE.Vector3 representing the largest (maximum) X, Y, Z coordinates of the box.

By default, a Box3 is initialized with min set to (Infinity, Infinity, Infinity) and max set to (-Infinity, -Infinity, -Infinity) (an "empty" box). To compute the bounding box for an object, we use methods like setFromObject(), which traverses the object and its children to calculate the combined min and max values.

2. Why Groups Matter: Understanding THREE.Group#

A THREE.Group is a lightweight container object in Three.js. It does not render anything itself but allows you to group multiple 3D objects (meshes, sprites, or even other groups) into a single logical unit. This is useful for:

  • Organizing complex scenes (e.g., grouping all parts of a car into a "carGroup").
  • Applying transformations (position, rotation, scale) to multiple objects simultaneously.

To get the bounding box of a group, we need to compute the combined spatial extent of all its children. This is where Box3 shines, as it can traverse the group’s hierarchy and merge the bounds of all nested objects.

3. Prerequisites#

Before diving in, ensure you have:

  • Basic familiarity with Three.js (e.g., scene, camera, renderer setup).
  • Three.js library included in your project (via CDN or npm).
  • A code editor (e.g., VS Code) and browser for testing.

Quick Setup via CDN:
Add this to your HTML file to include Three.js:

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r132/three.min.js"></script>  

4. Step-by-Step Guide: Calculate Bounding Box for a Group#

Let’s walk through creating a group, adding objects, and computing its bounding box.

4.1 Set Up a Basic Three.js Scene#

First, we’ll set up a minimal Three.js scene with a camera, renderer, and lighting. This ensures we can visualize our group and its bounding box.

// Scene setup  
const scene = new THREE.Scene();  
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);  
const renderer = new THREE.WebGLRenderer();  
renderer.setSize(window.innerWidth, window.innerHeight);  
document.body.appendChild(renderer.domElement);  
 
// Add lighting (to see objects)  
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);  
scene.add(ambientLight);  
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);  
directionalLight.position.set(5, 5, 5);  
scene.add(directionalLight);  
 
// Camera position  
camera.position.z = 15;  

4.2 Create a Group and Add Objects#

Next, create a group and add 3D objects (e.g., cubes, spheres) to it. We’ll position the objects at different coordinates to demonstrate how Box3 merges their bounds.

// Create a group  
const myGroup = new THREE.Group();  
scene.add(myGroup); // Add group to the scene  
 
// Add objects to the group  
const geometry1 = new THREE.BoxGeometry(2, 2, 2); // Cube 1: size 2x2x2  
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });  
const cube1 = new THREE.Mesh(geometry1, material);  
cube1.position.set(-3, 0, 0); // Position left of center  
myGroup.add(cube1);  
 
const geometry2 = new THREE.SphereGeometry(1.5, 32, 32); // Sphere: radius 1.5  
const sphere = new THREE.Mesh(geometry2, material);  
sphere.position.set(3, 2, 0); // Position right and above center  
myGroup.add(sphere);  
 
const geometry3 = new THREE.BoxGeometry(1, 4, 1); // Cube 2: tall and thin  
const cube2 = new THREE.Mesh(geometry3, material);  
cube2.position.set(0, -2, 0); // Position below center  
myGroup.add(cube2);  

Now, myGroup contains three objects with varying positions and sizes.

4.3 Compute the Bounding Box with Box3#

To calculate the group’s bounding box, use THREE.Box3 and its setFromObject() method. This method recursively traverses the group and all its children to compute the combined min and max bounds.

// Create a Box3 and compute bounds from the group  
const groupBoundingBox = new THREE.Box3().setFromObject(myGroup);  
 
// Optional: Visualize the bounding box with Box3Helper  
const boxHelper = new THREE.Box3Helper(groupBoundingBox, 0xff0000); // Red color  
scene.add(boxHelper); // Add helper to scene to see the box  

What setFromObject() Does:

  • Traverses all children of myGroup (including nested groups).
  • For each child, computes its individual bounding box.
  • Merges these boxes into a single min/max pair representing the group’s total extent.

4.4 Extract Height, Width, and Depth#

Once we have groupBoundingBox, we can extract dimensions using min and max:

  • Width: max.x - min.x (extent along X-axis).
  • Height: max.y - min.y (extent along Y-axis).
  • Depth: max.z - min.z (extent along Z-axis).

Code:

// Extract dimensions  
const width = groupBoundingBox.max.x - groupBoundingBox.min.x;  
const height = groupBoundingBox.max.y - groupBoundingBox.min.y;  
const depth = groupBoundingBox.max.z - groupBoundingBox.min.z;  
 
console.log("Group Dimensions:");  
console.log(`Width: ${width.toFixed(2)}`);   // e.g., 8.00  
console.log(`Height: ${height.toFixed(2)}`); // e.g., 8.00  
console.log(`Depth: ${depth.toFixed(2)}`);   // e.g., 4.00  

Output Explanation:

  • The cube on the left (position.x = -3) and sphere on the right (position.x = 3) give a width of 3 - (-3) + 2 (cube width) + 3 (sphere diameter)? Wait, no—setFromObject() accounts for object sizes and positions. For precise values, the code above will log the exact computed width/height/depth.

5. Handling Edge Cases#

5.1 Empty Groups#

If a group has no children, setFromObject() will leave min as (Infinity, Infinity, Infinity) and max as (-Infinity, -Infinity, -Infinity), resulting in negative dimensions. Always check if the box is valid first:

const groupBoundingBox = new THREE.Box3().setFromObject(myGroup);  
 
if (groupBoundingBox.isEmpty()) {  
  console.log("Group is empty—no bounding box.");  
} else {  
  // Extract dimensions  
}  

5.2 Nested Groups#

setFromObject() recursively traverses all children, including nested groups. For example:

const parentGroup = new THREE.Group();  
const childGroup = new THREE.Group();  
childGroup.add(new THREE.Mesh(new THREE.BoxGeometry(1,1,1)));  
parentGroup.add(childGroup);  
 
const box = new THREE.Box3().setFromObject(parentGroup); // Works! Includes childGroup's mesh.  

5.3 Dynamic Updates (Moving Objects in the Group)#

If objects in the group move, rotate, or scale, the bounding box will not update automatically. You must recompute it using setFromObject() after the change:

// Example: Move cube1 and update the bounding box  
cube1.position.x = 5; // Move cube1 to the right  
groupBoundingBox.setFromObject(myGroup); // Recompute bounds  
boxHelper.update(); // Update the visual helper  

6. Practical Examples#

6.1 Position a 2D Label Above a Group#

Use the group’s bounding box to position a DOM label (e.g., a "Name Tag") above the group in 3D space.

// Get the top-center of the group's bounding box  
const groupCenter = new THREE.Vector3();  
groupBoundingBox.getCenter(groupCenter); // Center of the box  
const labelPosition = new THREE.Vector3(  
  groupCenter.x,  
  groupBoundingBox.max.y + 1, // 1 unit above the top of the box  
  groupCenter.z  
);  
 
// Convert 3D position to 2D screen coordinates  
const screenPosition = labelPosition.project(camera);  
const x = (screenPosition.x * 0.5 + 0.5) * window.innerWidth;  
const y = -(screenPosition.y * 0.5 - 0.5) * window.innerHeight;  
 
// Create a DOM label  
const label = document.createElement("div");  
label.textContent = "My Group";  
label.style.position = "absolute";  
label.style.left = `${x}px`;  
label.style.top = `${y}px`;  
label.style.color = "white";  
document.body.appendChild(label);  

6.2 Collision Detection Between Groups#

Check if two groups intersect using Box3.intersectsBox():

// Create a second group  
const otherGroup = new THREE.Group();  
otherGroup.add(new THREE.Mesh(new THREE.BoxGeometry(3,3,3), material));  
otherGroup.position.set(5, 0, 0);  
scene.add(otherGroup);  
 
// Compute its bounding box  
const otherBoundingBox = new THREE.Box3().setFromObject(otherGroup);  
 
// Check for collision  
if (groupBoundingBox.intersectsBox(otherBoundingBox)) {  
  console.log("Groups are colliding!");  
} else {  
  console.log("No collision.");  
}  

7. References#

By following this guide, you can accurately compute the bounding box of groups in Three.js and use their dimensions for positioning, collision detection, and more. Experiment with different group configurations to master edge cases like dynamic updates and nested hierarchies!