Collision detection

Back to Modules

Collision Detection in Three.js

Three.js itself does not have a built-in, comprehensive collision detection system that handles complex physics interactions. Instead, it provides tools that allow developers to implement collision detection using various techniques. The most common approaches involve bounding volumes, raycasting, and integrating dedicated physics engines.

1. Bounding Volumes

This is the most common and performant method for basic collision detection in Three.js. It involves approximating the 3D objects with simpler geometric shapes (bounding volumes) and checking for intersections between these simpler shapes.

How to use Bounding Volumes:

  1. Create THREE.Box3 or THREE.Sphere instances for the objects you want to check for collisions.
  2. Update the bounding volumes' positions and sizes to match their corresponding 3D objects in each frame.
  3. Use the intersectsBox() or intersectsSphere() methods to check for overlaps between the bounding volumes.

2. Raycasting (THREE.Raycaster)

Raycasting involves casting a ray (a line with an origin and direction) into the scene and checking which objects it intersects. This is commonly used for mouse interaction/picking, line-of-sight checks, and simple collision detection by casting rays from an object's vertices in the direction of movement.

3. Physics Engines

For more realistic and complex collision detection, especially involving physics simulations like gravity, friction, and rigid body dynamics, it's highly recommended to integrate a dedicated JavaScript physics library. These libraries create a "physics world" where simplified representations of your Three.js objects interact, and then update the positions and rotations of your Three.js meshes based on the physics simulation.

Popular physics libraries for Three.js include:

Example: Bounding Box Collision Detection (Conceptual)

This example demonstrates a conceptual approach to checking for collisions between two cubes using bounding boxes. Note that this requires a Three.js setup.

import * as THREE from 'three';

// Scene, Camera, Renderer setup (assuming these are already defined)
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);

// Create two cubes
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material1 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const material2 = new THREE.MeshBasicMaterial({ color: 0x0000ff });

const cube1 = new THREE.Mesh(geometry, material1);
cube1.position.set(-1, 0, 0);
scene.add(cube1);

const cube2 = new THREE.Mesh(geometry, material2);
cube2.position.set(1, 0, 0);
scene.add(cube2);

camera.position.z = 5;

// Create bounding boxes for the cubes
const bbox1 = new THREE.Box3();
const bbox2 = new THREE.Box3();

function animate() {
    requestAnimationFrame(animate);

    // Move cube1 to demonstrate collision
    cube1.position.x = Math.sin(Date.now() * 0.001) * 2;

    // Update bounding boxes to current object positions
    bbox1.setFromObject(cube1);
    bbox2.setFromObject(cube2);

    // Check for collision
    if (bbox1.intersectsBox(bbox2)) {
        cube1.material.color.set(0xffa500); // Change color on collision
        cube2.material.color.set(0xffa500);
    } else {
        cube1.material.color.set(0xff0000); // Reset color
        cube2.material.color.set(0x0000ff);
    }

    renderer.render(scene, camera);
}
animate();

window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});