Skip to content

Raycasting & Object Picking

Purpose and Scope

This document explains the raycasting system in Three.js, which enables spatial queries by casting rays through the 3D scene to detect intersections with objects. Raycasting is the foundation for mouse picking, collision detection, line-of-sight queries, and other spatial interaction mechanisms. The system consists of the Raycaster class, mathematical ray primitives, and object-specific intersection algorithms that leverage bounding volume optimizations.

For skeletal animation and mesh skinning topics, see 5.2.

System Architecture

The raycasting system follows a delegation pattern where Raycaster orchestrates the intersection testing process, but individual objects implement their own raycast() methods to compute precise intersections based on their geometry type.

SVG
100%

Raycasting System Architecture

The architecture separates concerns: Raycaster handles ray setup, scene traversal, and result sorting, while individual object types implement optimized intersection tests. Bounding volumes provide early rejection to avoid expensive per-triangle tests.

Raycaster Class

Construction and Configuration

The Raycaster class is defined in src/core/Raycaster.js13-228 and provides the main API for performing ray-based spatial queries.

SVG
100%

Raycaster Class Structure

Parameters Configuration

The params object allows per-object-type intersection configuration:

Object TypeParameterDefaultPurpose
Mesh-{}No configurable parameters
Linethreshold1Maximum distance in world units from line to ray
Pointsthreshold1Maximum distance in world units from point to ray
Sprite-{}No configurable parameters
LOD-{}No configurable parameters

The threshold values enable tolerance-based intersection for thin objects like lines and points that would otherwise be difficult to pick precisely.

Ray Initialization Methods

setFromCamera()

Converts 2D screen coordinates to a 3D ray for mouse picking:

SVG
100%

Camera-Based Ray Setup

For perspective cameras, the ray originates at the camera position and points toward the unprojected screen coordinate. For orthographic cameras, all rays are parallel, so the origin is on the near plane and the direction is the camera's forward vector.

setFromXRController()

Sets up the ray from a WebXR controller's world-space position and forward direction:

Ray Mathematics

The Ray class (src/math/Ray.js18-472) encapsulates ray-geometry intersection algorithms. A ray is defined by an origin point and a normalized direction vector.

Core Intersection Methods

SVG
100%

Ray Intersection API

Sources: src/math/Ray.js18-472

Triangle Intersection Algorithm

The core mesh intersection uses the Möller-Trumbore algorithm implemented in src/math/Ray.js297-380 This algorithm directly computes the barycentric coordinates and distance without explicitly constructing the plane equation.

The algorithm:

  1. Computes edge vectors edge1 = b - a and edge2 = c - a
  2. Calculates determinant from cross product to check if ray is parallel to triangle
  3. Computes barycentric coordinates u and v
  4. Validates that point is inside triangle (u >= 0, v >= 0, u + v <= 1)
  5. Computes distance t along ray
  6. Returns intersection point if valid

Object-Specific Intersection Algorithms

Each renderable object type implements a raycast(raycaster, intersects) method that computes intersections and appends results to the intersects array.

Mesh Raycasting

Mesh intersection (src/objects/Mesh.js226-405) uses a multi-stage optimization strategy:

SVG
100%

Mesh Raycasting Pipeline

The two-stage bounding volume test (sphere in world space, then box in local space) provides early rejection before the expensive per-triangle tests. For meshes with multiple materials, the algorithm respects geometry groups to test only relevant triangles against the appropriate material.

Bounding Volume Optimization

The bounding sphere test in world space (src/objects/Mesh.js236-251):

  1. Computes or retrieves cached bounding sphere from geometry
  2. Transforms sphere to world space using matrixWorld
  3. Tests if ray origin is inside sphere or if ray intersects sphere
  4. Early exits if no intersection

The bounding box test in local space (src/objects/Mesh.js260-264):

  1. Transforms ray from world to local space
  2. Tests ray-box intersection using separating axis theorem
  3. Provides tighter bounds than sphere for elongated meshes

Triangle Intersection Details

The checkGeometryIntersection() helper (src/objects/Mesh.js440-494):

  1. Vertex Retrieval: Calls getVertexPosition() which handles morph target blending (src/objects/Mesh.js176-218)
  2. Sidedness Check: Respects material.side (FrontSide, BackSide, DoubleSide) by testing triangle winding
  3. Barycentric Coordinates: Uses Triangle.getBarycoord() to compute point position within triangle
  4. Attribute Interpolation: Interpolates UV coordinates and normals using barycentric weights
  5. Normal Orientation: Flips interpolated normal if ray hits backface

Line Raycasting

Line intersection (src/objects/Line.js97-184) tests distance from ray to line segments:

SVG
100%

Line Raycasting Algorithm

Lines use a threshold-based approach since infinitely thin lines would be impossible to pick. The algorithm finds the closest point on each line segment to the ray and tests if it's within the threshold distance.

Points Raycasting

Points intersection (src/objects/Points.js60-160) tests distance from ray to each point:

The algorithm:

  1. Tests bounding sphere for early rejection
  2. Transforms ray to local space
  3. Retrieves threshold from raycaster.params.Points
  4. For each point in geometry:
    • Tests distance from ray to point
    • If within threshold, records intersection with distanceToRay property
  5. Returns all points within threshold, unsorted by default

Sprite Raycasting

Sprite intersection (src/objects/Sprite.js129-202) treats the sprite as two triangles forming a billboard quad:

SVG
100%

Sprite Raycasting Algorithm

Sprites require special handling because they're view-dependent billboards. The algorithm transforms the quad vertices based on the camera's view matrix and tests both triangles of the quad.

Intersection Result Structure

The intersectObject() and intersectObjects() methods return an array of intersection objects sorted by distance (closest first). Each intersection object has the following structure:

PropertyTypeDescription
distancenumberDistance from ray origin to intersection point
distanceToRaynumber?For Points: distance from point to ray (undefined for others)
pointVector3Intersection point in world coordinates
faceObject?Face definition:
faceIndexnumber?Index of the intersected face in the geometry
objectObject3DThe intersected 3D object
uvVector2?UV coordinates at intersection point
uv1Vector2?Secondary UV coordinates at intersection point
normalVector3?Interpolated normal vector at intersection point
instanceIdnumber?For InstancedMesh: index of the intersected instance
barycoordVector3?Barycentric coordinates of the intersection point

The properties marked with ? are only present for certain object types or configurations.

Scene Traversal and Layer Filtering

The intersectObject() method (src/core/Raycaster.js194-202) and intersectObjects() method (src/core/Raycaster.js214-226) handle scene graph traversal with optional recursion.

The internal intersect() function (src/core/Raycaster.js236-259) implements the traversal logic:

SVG
100%

Scene Traversal with Layer Filtering

The layer system allows selective raycasting. Each object has a Layers instance, and only objects whose layers overlap with raycaster.layers are tested. Objects can prevent traversal of their children by returning false from raycast().

Performance Characteristics

Optimization Strategies

StageComplexityOptimization
Bounding Sphere TestO(1)Early rejection in world space
Bounding Box TestO(1)Early rejection in local space
Per-Triangle TestO(n) where n = triangle countRequires bounding volume pass
Material GroupsO(m) where m = group countTests only relevant triangles
Vertex MorphingO(k) where k = morph targetsBlends positions on demand

The hierarchical bounding volume approach reduces the average case to O(log n) for well-distributed scenes, though worst case remains O(n) for dense geometry.

Memory Efficiency

Raycasting reuses temporary objects allocated at module scope to avoid garbage collection pressure:

This pattern is consistent across all raycastable object types.

Common Usage Patterns

Mouse Picking

// Setup (once)
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

// On mouse move
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

// Cast ray from camera
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);

if (intersects.length > 0) {
    const firstHit = intersects[0];
    console.log('Hit:', firstHit.object.name, 'at', firstHit.point);
}

Selective Layer Raycasting

// Setup picking layer
const pickingLayer = 1;
raycaster.layers.set(pickingLayer);

// Enable layer on interactive objects only
interactiveObject.layers.enable(pickingLayer);

Threshold-Based Line Picking

// Increase line pick tolerance
raycaster.params.Line.threshold = 5; // 5 world units
const intersects = raycaster.intersectObjects(lineObjects);