Skip to content

Math Primitives

Purpose and Scope

This document describes the mathematical primitive classes that form the foundational layer of Three.js. These classes provide essential data structures and operations for 3D graphics computations including vectors, matrices, quaternions, bounding volumes, and spatial queries. Math primitives are used throughout the library for transformations, raycasting, collision detection, and geometric calculations.

For information about how these primitives integrate with scene graph objects, see Scene Graph & Object3D. For their use in raycasting systems, see Raycasting & Object Picking.

Architecture Overview

Math primitives serve as the lowest-level computational layer in Three.js, providing immutable mathematical operations that higher-level systems depend upon. All math primitive classes follow a consistent API pattern: component-wise construction, chainable mutation methods returning this, and separate output parameters for read-only operations.

SVG
100%

Vector Classes

Vector2

Vector2 represents a 2D vector with x and y components, used for UV coordinates, screen positions, and 2D geometric operations. The class provides aliases width and height for x and y respectively.

Key Operations:

OperationMethodDescription
Arithmeticadd(), sub(), multiply(), divide()Component-wise operations
ScalaraddScalar(), multiplyScalar(), divideScalar()Uniform scaling
Lengthlength(), lengthSq(), normalize()Magnitude operations
DistancedistanceTo(), distanceToSquared()Euclidean distance
Interpolationlerp(), lerpVectors()Linear interpolation
Clampingclamp(), clampScalar(), clampLength()Constraint operations

Vector3

Vector3 is the most frequently used vector class, representing 3D points, directions, and displacements. It supports comprehensive operations for 3D geometry including cross products, projections, and transformations by matrices and quaternions.

Transformation Methods:

applyMatrix3(m)          - Multiply by 3x3 matrix
applyMatrix4(m)          - Multiply by 4x4 matrix with perspective division
applyQuaternion(q)       - Rotate by quaternion
applyEuler(euler)        - Rotate by Euler angles
applyAxisAngle(axis, angle) - Rotate around axis

Coordinate System Conversions:

setFromSpherical(s)              - From spherical coordinates (radius, phi, theta)
setFromSphericalCoords(r, φ, θ)  - Direct spherical conversion
setFromCylindrical(c)            - From cylindrical coordinates
setFromCylindricalCoords(r, θ, y) - Direct cylindrical conversion

Matrix Extraction:

setFromMatrixPosition(m)  - Extract translation from Matrix4
setFromMatrixScale(m)     - Extract scale from Matrix4
setFromMatrixColumn(m, i) - Extract column i from Matrix4

The implementation uses a reusable _quaternion instance src/math/Vector3.js1257 to avoid allocations during transformations like applyEuler() src/math/Vector3.js388-392

Vector4

Vector4 represents homogeneous coordinates (x, y, z, w) used for 4D transformations and shader operations. The w component defaults to 1, enabling proper perspective division. Like Vector2, it provides width and height aliases for the z and w components.

Transformation Classes

Matrix4

Matrix4 represents 4x4 transformation matrices stored in column-major order in the elements array src/math/Matrix4.js82-89 The constructor and set() method accept row-major arguments for convenience, but internal storage is column-major for GPU compatibility.

Decomposition Diagram:

SVG
100%

Key Transformation Factories:

MethodPurpose
makeTranslation(x, y, z)Pure translation matrix
makeRotationX/Y/Z(θ)Axis-aligned rotation
makeRotationAxis(axis, angle)Arbitrary axis rotation
makeRotationFromEuler(euler)Rotation from Euler angles (6 orders)
makeRotationFromQuaternion(q)Rotation from quaternion
makeScale(x, y, z)Non-uniform scaling
makeShear(xy, xz, yx, yz, zx, zy)Shear transformation
makePerspective(...)Perspective projection matrix
makeOrthographic(...)Orthographic projection matrix

Composition and Decomposition:

compose(position, quaternion, scale)     - Build TRS matrix
decompose(position, quaternion, scale)   - Extract TRS components

The compose() method src/math/Matrix4.js1000-1034 directly computes the matrix elements from quaternion components, avoiding intermediate matrix multiplications for performance.

Matrix3

Matrix3 represents 3x3 matrices, primarily used for normal transformations and texture coordinate transformations. Like Matrix4, it uses column-major storage src/math/Matrix3.js62-68 with row-major input.

The getNormalMatrix(matrix4) method src/math/Matrix3.js367-386 extracts the upper 3x3, transposes it, and inverts it to produce a normal transformation matrix that correctly transforms surface normals under non-uniform scaling.

Quaternion

Quaternion represents rotations as a 4-component unit vector (x, y, z, w) where w is the scalar component. Three.js expects quaternions to remain normalized for correct behavior. The class provides static methods slerpFlat() and multiplyQuaternionsFlat() src/math/Quaternion.js60-163 for operating on flat arrays without object allocation, used in animation systems.

Rotation Conversion Methods:

setFromEuler(euler)              - Convert from Euler angles
setFromAxisAngle(axis, angle)    - Convert from axis-angle
setFromRotationMatrix(m)         - Extract from Matrix4 upper 3x3
setFromUnitVectors(vFrom, vTo)   - Rotation between two directions

The setFromEuler() implementation src/math/Quaternion.js301-373 handles all six rotation orders (XYZ, YXZ, ZXY, ZYX, YZX, XZY) with optimized trigonometric calculations.

Interpolation:

slerp(q, t)        - Spherical linear interpolation
rotateTowards(q, step) - Rotation with angular step limit

Euler

Euler represents rotations as three angles (x, y, z) in radians with a specified rotation order. The default order is 'XYZ' src/math/Euler.js35 stored in the DEFAULT_ORDER static constant.

Rotation Orders: XYZ, YXZ, ZXY, ZYX, YZX, XZY

The class uses getter/setter properties src/math/Euler.js59-127 that invoke _onChangeCallback() on modification, enabling automatic updates when Euler angles are used in Object3D transformations.

Conversion Methods:

setFromRotationMatrix(m, order)   - Extract from Matrix4
setFromQuaternion(q, order)       - Convert from Quaternion

Spatial Query Classes

Bounding Volumes

SVG
100%

Box3

Box3 represents axis-aligned bounding boxes (AABB) with min and max Vector3 corners. Empty boxes are represented with min = (+∞, +∞, +∞) and max = (−∞, −∞, −∞) src/math/Box3.js14

Construction Methods:

MethodSource
setFromArray(array)Flat array of xyz coordinates
setFromBufferAttribute(attribute)BufferAttribute position data
setFromPoints(points)Array of Vector3
setFromObject(object, precise)Object3D hierarchy bounds
setFromCenterAndSize(center, size)Center point and dimensions

The expandByObject() method src/math/Box3.js298-380 handles two modes:

Intersection Tests:

containsPoint(point)         - Point containment
containsBox(box)            - Box containment
intersectsBox(box)          - Box-box intersection
intersectsSphere(sphere)    - Box-sphere intersection
intersectsPlane(plane)      - Box-plane intersection
intersectsTriangle(triangle) - Box-triangle intersection (SAT)

The triangle intersection src/math/Box3.js521-572 uses the Separating Axis Theorem (SAT) with 13 potential separating axes.

Sphere

Sphere represents bounding spheres defined by a center Vector3 and radius number. The default radius of -1 indicates an empty sphere src/math/Sphere.js20

Bounding Sphere Generation:

setFromPoints(points, optionalCenter) - Ritter's algorithm for approximate bounds

The Ritter algorithm implementation src/math/Sphere.js65-134 iteratively expands the sphere to encompass all points.

Intersection Tests:

containsPoint(point)         - Point containment
intersectsSphere(sphere)    - Sphere-sphere intersection
intersectsBox(box)          - Sphere-box intersection
intersectsPlane(plane)      - Sphere-plane intersection

Ray

Ray represents an infinite ray with an origin and normalized direction Vector3. Rays are used by the Raycaster class for picking and intersection tests.

Core Operations:

at(t, target)                            - Point at distance t
closestPointToPoint(point, target)       - Nearest point on ray
distanceToPoint(point)                   - Distance to point
distanceSqToSegment(v0, v1, ...)        - Distance to line segment

Intersection Methods:

intersectBox(box, target)               - Ray-box intersection
intersectSphere(sphere, target)         - Ray-sphere intersection
intersectPlane(plane, target)           - Ray-plane intersection
intersectTriangle(a, b, c, backfaceCulling, target) - Ray-triangle (Möller-Trumbore)

The triangle intersection src/math/Ray.js234-315 implements the Möller-Trumbore algorithm, computing barycentric coordinates for texture interpolation.

Plane

Plane represents an infinite plane in Hessian normal form with a unit normal Vector3 and scalar constant. The plane equation is: normal · point + constant = 0.

Operations:

distanceToPoint(point)           - Signed distance (negative = back)
distanceToSphere(sphere)         - Signed distance to sphere
projectPoint(point, target)      - Orthogonal projection
intersectLine(line, target)      - Line-plane intersection

The coplanarPoint() method src/math/Plane.js187-191 returns a point on the plane by scaling the normal by -constant.

Frustum

Frustum represents a view frustum as six Plane objects stored in the planes array src/math/Frustum.js23-30 The canonical plane order is: right, left, bottom, top, near, far.

Construction:

setFromProjectionMatrix(m, coordinateSystem)

This extracts the six frustum planes from a projection matrix src/math/Frustum.js44-124 with special handling for WebGL vs WebGPU coordinate systems.

Culling Tests:

intersectsObject(object)         - Object3D visibility
intersectsSprite(sprite)         - Sprite visibility
intersectsSphere(sphere)         - Sphere-frustum intersection
intersectsBox(box)               - Box-frustum intersection
containsPoint(point)             - Point containment

The intersectsObject() method src/math/Frustum.js126-165 first tests the bounding sphere, then optionally performs a more precise box test.

Triangle

Triangle represents a geometric triangle with three Vector3 corners (a, b, c). It provides static utility methods for triangle operations used throughout the library.

Static Utility Methods:

MethodPurpose
getNormal(a, b, c, target)Compute face normal
getBarycoord(point, a, b, c, target)Barycentric coordinates
containsPoint(point, a, b, c)Point-in-triangle test
getInterpolation(point, p1, p2, p3, v1, v2, v3, target)Barycentric interpolation
getInterpolatedAttribute(attr, i1, i2, i3, barycoord, target)Attribute interpolation
isFrontFacing(a, b, c, direction)Backface culling test

These static methods are used by raycasting src/objects/Mesh.js440-493 to compute intersection details including UV coordinates, normals, and face indices.

Instance Methods:

getArea()                    - Triangle area (half cross product magnitude)
getMidpoint(target)          - Centroid
getPlane(target)             - Plane containing triangle
closestPointToPoint(p, target) - Nearest point on triangle

Integration Patterns

Object3D Transformation Pipeline

SVG
100%

Object3D maintains synchronized Euler and Quaternion representations src/core/Object3D.js100-200 When rotation is modified, quaternion updates automatically via callbacks, and vice versa. The matrix is recomputed from position, quaternion, and scale during updateMatrix().

Raycasting Integration

SVG
100%

The raycasting system uses a multi-stage culling approach src/objects/Mesh.js226-270:

  1. Bounding sphere test in world space src/objects/Mesh.js236-251
  2. Bounding box test in local space src/objects/Mesh.js260-264
  3. Per-triangle intersection using Möller-Trumbore src/math/Ray.js234-315

Memory Management Pattern

All math primitive classes follow a consistent memory management pattern to minimize allocations:

Output Parameter Pattern:

// BAD: Creates new object on each call
const center = box.getCenter();

// GOOD: Reuses existing object
const center = new Vector3();
box.getCenter(center);

Methods that compute derived values accept a target parameter for output src/math/Box3.js219-222 This enables allocation-free operations in performance-critical paths like animation loops.

Singleton Reuse Pattern:

// Module-level reusable instances
const _vector = /*@__PURE__*/ new Vector3();
const _matrix = /*@__PURE__*/ new Matrix4();

Internal implementations use module-scoped temporary objects src/math/Vector3.js1256-1257 for intermediate calculations, avoiding repeated allocations within methods.