Three.js AABB Collision Detection with Box3

This article explains how to implement Axis-Aligned Bounding Box (AABB) collision detection in Three.js using the built-in Box3 class. You will learn how to create bounding boxes for 3D meshes, update them dynamically as objects move, and check for intersections to detect collisions in your 3D scenes.

Understanding Box3 and AABB

An Axis-Aligned Bounding Box (AABB) is a rectangular prism wrapped around a 3D object, aligned perfectly with the X, Y, and Z axes of the world space. In Three.js, the Box3 class represents this bounding box. Because these boxes do not rotate with the object, calculating their intersection is computationally cheap, making AABB ideal for real-time collision detection in games and interactive 3D applications.

Step 1: Create Bounding Boxes for Your Meshes

To perform collision detection, you first need to create a Box3 instance for each 3D object you want to track. You can generate a bounding box that perfectly fits a mesh using the setFromObject method.

import * as THREE from 'three';

// Create meshes
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });

const mesh1 = new THREE.Mesh(geometry, material);
const mesh2 = new THREE.Mesh(geometry, material);

// Create Box3 instances
const box1 = new THREE.Box3(new THREE.Vector3(), new THREE.Vector3());
const box2 = new THREE.Box3(new THREE.Vector3(), new THREE.Vector3());

// Calculate initial bounding boxes
box1.setFromObject(mesh1);
box2.setFromObject(mesh2);

Step 2: Update Bounding Boxes in the Animation Loop

If your meshes move, scale, or rotate, their world coordinates change. Therefore, you must recalculate the bounding boxes inside your animation loop before checking for collisions.

function animate() {
    requestAnimationFrame(animate);

    // Move mesh1 along the X-axis
    mesh1.position.x += 0.01;

    // Recalculate bounding boxes to match new positions
    box1.setFromObject(mesh1);
    box2.setFromObject(mesh2);

    // Check for collisions
    checkCollisions();

    renderer.render(scene, camera);
}

Step 3: Check for Collisions

To determine if two bounding boxes are colliding, use the intersectsBox method of the Box3 class. This method returns true if the two boxes overlap in 3D space.

function checkCollisions() {
    if (box1.intersectsBox(box2)) {
        console.log("Collision detected!");
        // Handle collision logic here (e.g., stop movement or change color)
        mesh1.material.color.setHex(0xff0000); 
    } else {
        mesh1.material.color.setHex(0x00ff00);
    }
}

Performance Optimization for Complex Geometries

Calling setFromObject every frame can be computationally expensive for complex geometries because it traverses all vertices of the mesh. If your objects only translate (move) and do not rotate or scale, you can optimize performance by copying the pre-computed geometry bounding box and applying the mesh’s world matrix:

// Define the bounding box once at start
mesh1.geometry.computeBoundingBox();
const localBox = mesh1.geometry.boundingBox;

// Inside the animation loop, apply the world matrix
const dynamicBox = localBox.clone().applyMatrix4(mesh1.matrixWorld);

This approach bypasses the need to traverse geometry vertices in every frame, significantly improving performance for high-poly models.