How to Use Three.js Ray Without Raycaster
In Three.js, while the Raycaster class is the standard
tool for mouse picking and object collision, you can perform
lower-level, high-performance manual intersection calculations using the
lightweight Ray class. This article explains how to
instantiate a THREE.Ray object with an origin and a
direction, and demonstrates how to manually calculate intersection
points with geometric primitives like planes, spheres, and
triangles.
Creating a THREE.Ray Object
To manually calculate intersections, you must first construct a
THREE.Ray. The Ray constructor requires two
parameters: an origin point and a direction vector. Both must be
instances of THREE.Vector3. Crucially, the direction vector
must be normalized (have a length of 1) for the mathematical
calculations to work correctly.
import * as THREE from 'three';
// Define the starting point of the ray
const origin = new THREE.Vector3(0, 5, 0);
// Define the direction (e.g., pointing straight down the Y-axis)
const direction = new THREE.Vector3(0, -1, 0).normalize();
// Construct the Ray
const ray = new THREE.Ray(origin, direction);Calculating Intersections manually
Once your Ray is defined, you can use its built-in
methods to check for intersections against various mathematical shapes.
To prevent garbage collection overhead, these methods require a “target”
Vector3 variable where the resulting intersection
coordinates will be stored.
1. Intersecting with a Plane
To find where a ray intersects an infinite flat surface, use
THREE.Plane and the intersectPlane method.
// Create a plane facing upwards, positioned at y = 0
const planeNormal = new THREE.Vector3(0, 1, 0);
const plane = new THREE.Plane(planeNormal, 0);
// Create a target vector to store the result
const intersectionPoint = new THREE.Vector3();
// Calculate the intersection
const result = ray.intersectPlane(plane, intersectionPoint);
if (result !== null) {
console.log("Intersection point:", intersectionPoint);
// Output: Vector3 {x: 0, y: 0, z: 0}
} else {
console.log("The ray does not intersect the plane.");
}2. Intersecting with a Sphere
To detect if and where a ray hits a bounding sphere, use
THREE.Sphere and the intersectSphere
method.
// Create a sphere at center (0, 0, 0) with a radius of 2
const sphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0), 2);
const intersectionPoint = new THREE.Vector3();
const result = ray.intersectSphere(sphere, intersectionPoint);
if (result !== null) {
console.log("Sphere intersection point:", intersectionPoint);
// Output: Vector3 {x: 0, y: 2, z: 0} (where the ray hits the top of the sphere)
}3. Intersecting with a Triangle
For polygon-level precision (such as manual terrain clamping or
custom mesh collisions), you can check intersections against individual
triangles using intersectTriangle.
// Define the three vertices of a triangle
const vA = new THREE.Vector3(-1, 0, -1);
const vB = new THREE.Vector3(1, 0, -1);
const vC = new THREE.Vector3(0, 0, 1);
const backfaceCulling = true;
const intersectionPoint = new THREE.Vector3();
const result = ray.intersectTriangle(vA, vB, vC, backfaceCulling, intersectionPoint);
if (result !== null) {
console.log("Triangle intersection point:", intersectionPoint);
}By using the THREE.Ray class directly, you bypass the
overhead of traversing the entire 3D scene graph, making it an ideal
choice for physics engines, custom pathfinding, and fast-running
gameplay calculations.