Skip to content

⬅️ Back to Table of Contents

📄 Ray.js

📊 Analysis Summary

Metric Count
🔧 Functions 20
🧱 Classes 1
📦 Imports 1
📊 Variables & Constants 34

📚 Table of Contents

🛠️ File Location:

📂 src/math/Ray.js

📦 Imports

Name Source
Vector3 ./Vector3.js

Variables & Constants

Name Type Kind Value Exported
_vector Vector3 let/var new Vector3()
_segCenter Vector3 let/var new Vector3()
_segDir Vector3 let/var new Vector3()
_diff Vector3 let/var new Vector3()
_edge1 Vector3 let/var new Vector3()
_edge2 Vector3 let/var new Vector3()
_normal Vector3 let/var new Vector3()
segExtent number let/var v0.distanceTo( v1 ) * 0.5
a01 number let/var - this.direction.dot( _segDir )
b1 number let/var - _diff.dot( _segDir )
s0 any let/var *not shown*
s1 any let/var *not shown*
sqrDist any let/var *not shown*
extDet any let/var *not shown*
invDet number let/var 1 / det
d2 number let/var _vector.dot( _vector ) - tca * tca
radius2 number let/var sphere.radius * sphere.radius
t0 number let/var tca - thc
t1 number let/var tca + thc
t number let/var - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator
tmin any let/var *not shown*
tmax any let/var *not shown*
tymin any let/var *not shown*
tymax any let/var *not shown*
tzmin any let/var *not shown*
tzmax any let/var *not shown*
invdirx number let/var 1 / this.direction.x
invdiry number let/var 1 / this.direction.y
invdirz number let/var 1 / this.direction.z
origin Vector3 let/var this.origin
sign any let/var *not shown*
DdQxE2 number let/var sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) )
DdE1xQ number let/var sign * this.direction.dot( _edge1.cross( _diff ) )
QdN number let/var - sign * _diff.dot( _normal )

Functions

Ray.set(origin: Vector3, direction: Vector3): Ray

JSDoc:

/**
     * Sets the ray's components by copying the given values.
     *
     * @param {Vector3} origin - The origin.
     * @param {Vector3} direction - The direction.
     * @return {Ray} A reference to this ray.
     */

Parameters:

  • origin Vector3
  • direction Vector3

Returns: Ray

Calls:

  • this.origin.copy
  • this.direction.copy
Code
set( origin, direction ) {

        this.origin.copy( origin );
        this.direction.copy( direction );

        return this;

    }

Ray.copy(ray: Ray): Ray

JSDoc:

/**
     * Copies the values of the given ray to this instance.
     *
     * @param {Ray} ray - The ray to copy.
     * @return {Ray} A reference to this ray.
     */

Parameters:

  • ray Ray

Returns: Ray

Calls:

  • this.origin.copy
  • this.direction.copy
Code
copy( ray ) {

        this.origin.copy( ray.origin );
        this.direction.copy( ray.direction );

        return this;

    }

Ray.at(t: number, target: Vector3): Vector3

JSDoc:

/**
     * Returns a vector that is located at a given distance along this ray.
     *
     * @param {number} t - The distance along the ray to retrieve a position for.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} A position on the ray.
     */

Parameters:

  • t number
  • target Vector3

Returns: Vector3

Calls:

  • target.copy( this.origin ).addScaledVector
Code
at( t, target ) {

        return target.copy( this.origin ).addScaledVector( this.direction, t );

    }

Ray.lookAt(v: Vector3): Ray

JSDoc:

/**
     * Adjusts the direction of the ray to point at the given vector in world space.
     *
     * @param {Vector3} v - The target position.
     * @return {Ray} A reference to this ray.
     */

Parameters:

  • v Vector3

Returns: Ray

Calls:

  • this.direction.copy( v ).sub( this.origin ).normalize
Code
lookAt( v ) {

        this.direction.copy( v ).sub( this.origin ).normalize();

        return this;

    }

Ray.recast(t: number): Ray

JSDoc:

/**
     * Shift the origin of this ray along its direction by the given distance.
     *
     * @param {number} t - The distance along the ray to interpolate.
     * @return {Ray} A reference to this ray.
     */

Parameters:

  • t number

Returns: Ray

Calls:

  • this.origin.copy
  • this.at
Code
recast( t ) {

        this.origin.copy( this.at( t, _vector ) );

        return this;

    }

Ray.closestPointToPoint(point: Vector3, target: Vector3): Vector3

JSDoc:

/**
     * Returns the point along this ray that is closest to the given point.
     *
     * @param {Vector3} point - A point in 3D space to get the closet location on the ray for.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} The closest point on this ray.
     */

Parameters:

  • point Vector3
  • target Vector3

Returns: Vector3

Calls:

  • target.subVectors
  • target.dot
  • target.copy
  • target.copy( this.origin ).addScaledVector
Code
closestPointToPoint( point, target ) {

        target.subVectors( point, this.origin );

        const directionDistance = target.dot( this.direction );

        if ( directionDistance < 0 ) {

            return target.copy( this.origin );

        }

        return target.copy( this.origin ).addScaledVector( this.direction, directionDistance );

    }

Ray.distanceToPoint(point: Vector3): number

JSDoc:

/**
     * Returns the distance of the closest approach between this ray and the given point.
     *
     * @param {Vector3} point - A point in 3D space to compute the distance to.
     * @return {number} The distance.
     */

Parameters:

  • point Vector3

Returns: number

Calls:

  • Math.sqrt
  • this.distanceSqToPoint
Code
distanceToPoint( point ) {

        return Math.sqrt( this.distanceSqToPoint( point ) );

    }

Ray.distanceSqToPoint(point: Vector3): number

JSDoc:

/**
     * Returns the squared distance of the closest approach between this ray and the given point.
     *
     * @param {Vector3} point - A point in 3D space to compute the distance to.
     * @return {number} The squared distance.
     */

Parameters:

  • point Vector3

Returns: number

Calls:

  • _vector.subVectors( point, this.origin ).dot
  • this.origin.distanceToSquared
  • _vector.copy( this.origin ).addScaledVector
  • _vector.distanceToSquared

Internal Comments:

// point behind the ray

Code
distanceSqToPoint( point ) {

        const directionDistance = _vector.subVectors( point, this.origin ).dot( this.direction );

        // point behind the ray

        if ( directionDistance < 0 ) {

            return this.origin.distanceToSquared( point );

        }

        _vector.copy( this.origin ).addScaledVector( this.direction, directionDistance );

        return _vector.distanceToSquared( point );

    }

Ray.distanceSqToSegment(v0: Vector3, v1: Vector3, optionalPointOnRay: Vector3, optionalPointOnSegment: Vector3): number

JSDoc:

/**
     * Returns the squared distance between this ray and the given line segment.
     *
     * @param {Vector3} v0 - The start point of the line segment.
     * @param {Vector3} v1 - The end point of the line segment.
     * @param {Vector3} [optionalPointOnRay] - When provided, it receives the point on this ray that is closest to the segment.
     * @param {Vector3} [optionalPointOnSegment] - When provided, it receives the point on the line segment that is closest to this ray.
     * @return {number} The squared distance.
     */

Parameters:

  • v0 Vector3
  • v1 Vector3
  • optionalPointOnRay Vector3
  • optionalPointOnSegment Vector3

Returns: number

Calls:

  • _segCenter.copy( v0 ).add( v1 ).multiplyScalar
  • _segDir.copy( v1 ).sub( v0 ).normalize
  • _diff.copy( this.origin ).sub
  • v0.distanceTo
  • this.direction.dot
  • _diff.dot
  • _diff.lengthSq
  • Math.abs
  • Math.max
  • Math.min
  • optionalPointOnRay.copy( this.origin ).addScaledVector
  • optionalPointOnSegment.copy( _segCenter ).addScaledVector

Internal Comments:

// from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h (x8)
// It returns the min distance between the ray and the segment (x8)
// defined by v0 and v1 (x8)
// It can also set two optional targets : (x8)
// - The closest point on the ray (x8)
// - The closest point on the segment (x8)
// The ray and segment are not parallel. (x3)
// region 0 (x2)
// Minimum at interior points of ray and segment. (x2)
// region 1 (x3)
// region 5 (x3)
// region 4 (x3)
// region 3 (x3)
// region 2 (x3)
// Ray and segment are parallel. (x3)

Code
distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {

        // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h
        // It returns the min distance between the ray and the segment
        // defined by v0 and v1
        // It can also set two optional targets :
        // - The closest point on the ray
        // - The closest point on the segment

        _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
        _segDir.copy( v1 ).sub( v0 ).normalize();
        _diff.copy( this.origin ).sub( _segCenter );

        const segExtent = v0.distanceTo( v1 ) * 0.5;
        const a01 = - this.direction.dot( _segDir );
        const b0 = _diff.dot( this.direction );
        const b1 = - _diff.dot( _segDir );
        const c = _diff.lengthSq();
        const det = Math.abs( 1 - a01 * a01 );
        let s0, s1, sqrDist, extDet;

        if ( det > 0 ) {

            // The ray and segment are not parallel.

            s0 = a01 * b1 - b0;
            s1 = a01 * b0 - b1;
            extDet = segExtent * det;

            if ( s0 >= 0 ) {

                if ( s1 >= - extDet ) {

                    if ( s1 <= extDet ) {

                        // region 0
                        // Minimum at interior points of ray and segment.

                        const invDet = 1 / det;
                        s0 *= invDet;
                        s1 *= invDet;
                        sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;

                    } else {

                        // region 1

                        s1 = segExtent;
                        s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
                        sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

                    }

                } else {

                    // region 5

                    s1 = - segExtent;
                    s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
                    sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

                }

            } else {

                if ( s1 <= - extDet ) {

                    // region 4

                    s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
                    s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
                    sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

                } else if ( s1 <= extDet ) {

                    // region 3

                    s0 = 0;
                    s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
                    sqrDist = s1 * ( s1 + 2 * b1 ) + c;

                } else {

                    // region 2

                    s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
                    s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
                    sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

                }

            }

        } else {

            // Ray and segment are parallel.

            s1 = ( a01 > 0 ) ? - segExtent : segExtent;
            s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
            sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

        }

        if ( optionalPointOnRay ) {

            optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 );

        }

        if ( optionalPointOnSegment ) {

            optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 );

        }

        return sqrDist;

    }

Ray.intersectSphere(sphere: Sphere, target: Vector3): Vector3

JSDoc:

/**
     * Intersects this ray with the given sphere, returning the intersection
     * point or `null` if there is no intersection.
     *
     * @param {Sphere} sphere - The sphere to intersect.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {?Vector3} The intersection point.
     */

Parameters:

  • sphere Sphere
  • target Vector3

Returns: Vector3

Calls:

  • _vector.subVectors
  • _vector.dot
  • Math.sqrt
  • this.at

Internal Comments:

// t0 = first intersect point - entrance on front of sphere (x2)
// t1 = second intersect point - exit point on back of sphere (x2)
// test to see if t1 is behind the ray - if so, return null
// test to see if t0 is behind the ray:
// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
// in order to always return an intersect point that is in front of the ray.
// else t0 is in front of the ray, so return the first collision point scaled by t0

Code
intersectSphere( sphere, target ) {

        _vector.subVectors( sphere.center, this.origin );
        const tca = _vector.dot( this.direction );
        const d2 = _vector.dot( _vector ) - tca * tca;
        const radius2 = sphere.radius * sphere.radius;

        if ( d2 > radius2 ) return null;

        const thc = Math.sqrt( radius2 - d2 );

        // t0 = first intersect point - entrance on front of sphere
        const t0 = tca - thc;

        // t1 = second intersect point - exit point on back of sphere
        const t1 = tca + thc;

        // test to see if t1 is behind the ray - if so, return null
        if ( t1 < 0 ) return null;

        // test to see if t0 is behind the ray:
        // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
        // in order to always return an intersect point that is in front of the ray.
        if ( t0 < 0 ) return this.at( t1, target );

        // else t0 is in front of the ray, so return the first collision point scaled by t0
        return this.at( t0, target );

    }

Ray.intersectsSphere(sphere: Sphere): boolean

JSDoc:

/**
     * Returns `true` if this ray intersects with the given sphere.
     *
     * @param {Sphere} sphere - The sphere to intersect.
     * @return {boolean} Whether this ray intersects with the given sphere or not.
     */

Parameters:

  • sphere Sphere

Returns: boolean

Calls:

  • this.distanceSqToPoint
Code
intersectsSphere( sphere ) {

        if ( sphere.radius < 0 ) return false; // handle empty spheres, see #31187

        return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );

    }

Ray.distanceToPlane(plane: Plane): number

JSDoc:

/**
     * Computes the distance from the ray's origin to the given plane. Returns `null` if the ray
     * does not intersect with the plane.
     *
     * @param {Plane} plane - The plane to compute the distance to.
     * @return {?number} Whether this ray intersects with the given sphere or not.
     */

Parameters:

  • plane Plane

Returns: number

Calls:

  • plane.normal.dot
  • plane.distanceToPoint
  • this.origin.dot

Internal Comments:

// line is coplanar, return origin
// Null is preferable to undefined since undefined means.... it is undefined
// Return if the ray never intersects the plane

Code
distanceToPlane( plane ) {

        const denominator = plane.normal.dot( this.direction );

        if ( denominator === 0 ) {

            // line is coplanar, return origin
            if ( plane.distanceToPoint( this.origin ) === 0 ) {

                return 0;

            }

            // Null is preferable to undefined since undefined means.... it is undefined

            return null;

        }

        const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;

        // Return if the ray never intersects the plane

        return t >= 0 ? t : null;

    }

Ray.intersectPlane(plane: Plane, target: Vector3): Vector3

JSDoc:

/**
     * Intersects this ray with the given plane, returning the intersection
     * point or `null` if there is no intersection.
     *
     * @param {Plane} plane - The plane to intersect.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {?Vector3} The intersection point.
     */

Parameters:

  • plane Plane
  • target Vector3

Returns: Vector3

Calls:

  • this.distanceToPlane
  • this.at
Code
intersectPlane( plane, target ) {

        const t = this.distanceToPlane( plane );

        if ( t === null ) {

            return null;

        }

        return this.at( t, target );

    }

Ray.intersectsPlane(plane: Plane): boolean

JSDoc:

/**
     * Returns `true` if this ray intersects with the given plane.
     *
     * @param {Plane} plane - The plane to intersect.
     * @return {boolean} Whether this ray intersects with the given plane or not.
     */

Parameters:

  • plane Plane

Returns: boolean

Calls:

  • plane.distanceToPoint
  • plane.normal.dot

Internal Comments:

// check if the ray lies on the plane first (x2)
// ray origin is behind the plane (and is pointing behind it)

Code
intersectsPlane( plane ) {

        // check if the ray lies on the plane first

        const distToPoint = plane.distanceToPoint( this.origin );

        if ( distToPoint === 0 ) {

            return true;

        }

        const denominator = plane.normal.dot( this.direction );

        if ( denominator * distToPoint < 0 ) {

            return true;

        }

        // ray origin is behind the plane (and is pointing behind it)

        return false;

    }

Ray.intersectBox(box: Box3, target: Vector3): Vector3

JSDoc:

/**
     * Intersects this ray with the given bounding box, returning the intersection
     * point or `null` if there is no intersection.
     *
     * @param {Box3} box - The box to intersect.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {?Vector3} The intersection point.
     */

Parameters:

  • box Box3
  • target Vector3

Returns: Vector3

Calls:

  • isNaN
  • this.at

Internal Comments:

//return point closest to the ray (positive side)

Code
intersectBox( box, target ) {

        let tmin, tmax, tymin, tymax, tzmin, tzmax;

        const invdirx = 1 / this.direction.x,
            invdiry = 1 / this.direction.y,
            invdirz = 1 / this.direction.z;

        const origin = this.origin;

        if ( invdirx >= 0 ) {

            tmin = ( box.min.x - origin.x ) * invdirx;
            tmax = ( box.max.x - origin.x ) * invdirx;

        } else {

            tmin = ( box.max.x - origin.x ) * invdirx;
            tmax = ( box.min.x - origin.x ) * invdirx;

        }

        if ( invdiry >= 0 ) {

            tymin = ( box.min.y - origin.y ) * invdiry;
            tymax = ( box.max.y - origin.y ) * invdiry;

        } else {

            tymin = ( box.max.y - origin.y ) * invdiry;
            tymax = ( box.min.y - origin.y ) * invdiry;

        }

        if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;

        if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin;

        if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax;

        if ( invdirz >= 0 ) {

            tzmin = ( box.min.z - origin.z ) * invdirz;
            tzmax = ( box.max.z - origin.z ) * invdirz;

        } else {

            tzmin = ( box.max.z - origin.z ) * invdirz;
            tzmax = ( box.min.z - origin.z ) * invdirz;

        }

        if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;

        if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;

        if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;

        //return point closest to the ray (positive side)

        if ( tmax < 0 ) return null;

        return this.at( tmin >= 0 ? tmin : tmax, target );

    }

Ray.intersectsBox(box: Box3): boolean

JSDoc:

/**
     * Returns `true` if this ray intersects with the given box.
     *
     * @param {Box3} box - The box to intersect.
     * @return {boolean} Whether this ray intersects with the given box or not.
     */

Parameters:

  • box Box3

Returns: boolean

Calls:

  • this.intersectBox
Code
intersectsBox( box ) {

        return this.intersectBox( box, _vector ) !== null;

    }

Ray.intersectTriangle(a: Vector3, b: Vector3, c: Vector3, backfaceCulling: boolean, target: Vector3): Vector3

JSDoc:

/**
     * Intersects this ray with the given triangle, returning the intersection
     * point or `null` if there is no intersection.
     *
     * @param {Vector3} a - The first vertex of the triangle.
     * @param {Vector3} b - The second vertex of the triangle.
     * @param {Vector3} c - The third vertex of the triangle.
     * @param {boolean} backfaceCulling - Whether to use backface culling or not.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {?Vector3} The intersection point.
     */

Parameters:

  • a Vector3
  • b Vector3
  • c Vector3
  • backfaceCulling boolean
  • target Vector3

Returns: Vector3

Calls:

  • _edge1.subVectors
  • _edge2.subVectors
  • _normal.crossVectors
  • this.direction.dot
  • _diff.subVectors
  • _edge2.crossVectors
  • _edge1.cross
  • _diff.dot
  • this.at

Internal Comments:

// Compute the offset origin, edges, and normal. (x4)
// from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h (x4)
// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, (x2)
// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by (x2)
//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) (x2)
//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) (x2)
//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) (x2)
// b1 < 0, no intersection
// b2 < 0, no intersection
// b1+b2 > 1, no intersection
// Line intersects triangle, check if ray does. (x2)
// t < 0, no intersection
// Ray intersects triangle.

Code
intersectTriangle( a, b, c, backfaceCulling, target ) {

        // Compute the offset origin, edges, and normal.

        // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h

        _edge1.subVectors( b, a );
        _edge2.subVectors( c, a );
        _normal.crossVectors( _edge1, _edge2 );

        // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
        // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
        //   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
        //   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
        //   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
        let DdN = this.direction.dot( _normal );
        let sign;

        if ( DdN > 0 ) {

            if ( backfaceCulling ) return null;
            sign = 1;

        } else if ( DdN < 0 ) {

            sign = - 1;
            DdN = - DdN;

        } else {

            return null;

        }

        _diff.subVectors( this.origin, a );
        const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );

        // b1 < 0, no intersection
        if ( DdQxE2 < 0 ) {

            return null;

        }

        const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );

        // b2 < 0, no intersection
        if ( DdE1xQ < 0 ) {

            return null;

        }

        // b1+b2 > 1, no intersection
        if ( DdQxE2 + DdE1xQ > DdN ) {

            return null;

        }

        // Line intersects triangle, check if ray does.
        const QdN = - sign * _diff.dot( _normal );

        // t < 0, no intersection
        if ( QdN < 0 ) {

            return null;

        }

        // Ray intersects triangle.
        return this.at( QdN / DdN, target );

    }

Ray.applyMatrix4(matrix4: Matrix4): Ray

JSDoc:

/**
     * Transforms this ray with the given 4x4 transformation matrix.
     *
     * @param {Matrix4} matrix4 - The transformation matrix.
     * @return {Ray} A reference to this ray.
     */

Parameters:

  • matrix4 Matrix4

Returns: Ray

Calls:

  • this.origin.applyMatrix4
  • this.direction.transformDirection
Code
applyMatrix4( matrix4 ) {

        this.origin.applyMatrix4( matrix4 );
        this.direction.transformDirection( matrix4 );

        return this;

    }

Ray.equals(ray: Ray): boolean

JSDoc:

/**
     * Returns `true` if this ray is equal with the given one.
     *
     * @param {Ray} ray - The ray to test for equality.
     * @return {boolean} Whether this ray is equal with the given one.
     */

Parameters:

  • ray Ray

Returns: boolean

Calls:

  • ray.origin.equals
  • ray.direction.equals
Code
equals( ray ) {

        return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );

    }

Ray.clone(): Ray

JSDoc:

/**
     * Returns a new ray with copied values from this instance.
     *
     * @return {Ray} A clone of this instance.
     */

Returns: Ray

Calls:

  • new this.constructor().copy
Code
clone() {

        return new this.constructor().copy( this );

    }

Classes

Ray

Class Code
class Ray {

    /**
     * Constructs a new ray.
     *
     * @param {Vector3} [origin=(0,0,0)] - The origin of the ray.
     * @param {Vector3} [direction=(0,0,-1)] - The (normalized) direction of the ray.
     */
    constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) {

        /**
         * The origin of the ray.
         *
         * @type {Vector3}
         */
        this.origin = origin;

        /**
         * The (normalized) direction of the ray.
         *
         * @type {Vector3}
         */
        this.direction = direction;

    }

    /**
     * Sets the ray's components by copying the given values.
     *
     * @param {Vector3} origin - The origin.
     * @param {Vector3} direction - The direction.
     * @return {Ray} A reference to this ray.
     */
    set( origin, direction ) {

        this.origin.copy( origin );
        this.direction.copy( direction );

        return this;

    }

    /**
     * Copies the values of the given ray to this instance.
     *
     * @param {Ray} ray - The ray to copy.
     * @return {Ray} A reference to this ray.
     */
    copy( ray ) {

        this.origin.copy( ray.origin );
        this.direction.copy( ray.direction );

        return this;

    }

    /**
     * Returns a vector that is located at a given distance along this ray.
     *
     * @param {number} t - The distance along the ray to retrieve a position for.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} A position on the ray.
     */
    at( t, target ) {

        return target.copy( this.origin ).addScaledVector( this.direction, t );

    }

    /**
     * Adjusts the direction of the ray to point at the given vector in world space.
     *
     * @param {Vector3} v - The target position.
     * @return {Ray} A reference to this ray.
     */
    lookAt( v ) {

        this.direction.copy( v ).sub( this.origin ).normalize();

        return this;

    }

    /**
     * Shift the origin of this ray along its direction by the given distance.
     *
     * @param {number} t - The distance along the ray to interpolate.
     * @return {Ray} A reference to this ray.
     */
    recast( t ) {

        this.origin.copy( this.at( t, _vector ) );

        return this;

    }

    /**
     * Returns the point along this ray that is closest to the given point.
     *
     * @param {Vector3} point - A point in 3D space to get the closet location on the ray for.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} The closest point on this ray.
     */
    closestPointToPoint( point, target ) {

        target.subVectors( point, this.origin );

        const directionDistance = target.dot( this.direction );

        if ( directionDistance < 0 ) {

            return target.copy( this.origin );

        }

        return target.copy( this.origin ).addScaledVector( this.direction, directionDistance );

    }

    /**
     * Returns the distance of the closest approach between this ray and the given point.
     *
     * @param {Vector3} point - A point in 3D space to compute the distance to.
     * @return {number} The distance.
     */
    distanceToPoint( point ) {

        return Math.sqrt( this.distanceSqToPoint( point ) );

    }

    /**
     * Returns the squared distance of the closest approach between this ray and the given point.
     *
     * @param {Vector3} point - A point in 3D space to compute the distance to.
     * @return {number} The squared distance.
     */
    distanceSqToPoint( point ) {

        const directionDistance = _vector.subVectors( point, this.origin ).dot( this.direction );

        // point behind the ray

        if ( directionDistance < 0 ) {

            return this.origin.distanceToSquared( point );

        }

        _vector.copy( this.origin ).addScaledVector( this.direction, directionDistance );

        return _vector.distanceToSquared( point );

    }

    /**
     * Returns the squared distance between this ray and the given line segment.
     *
     * @param {Vector3} v0 - The start point of the line segment.
     * @param {Vector3} v1 - The end point of the line segment.
     * @param {Vector3} [optionalPointOnRay] - When provided, it receives the point on this ray that is closest to the segment.
     * @param {Vector3} [optionalPointOnSegment] - When provided, it receives the point on the line segment that is closest to this ray.
     * @return {number} The squared distance.
     */
    distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {

        // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h
        // It returns the min distance between the ray and the segment
        // defined by v0 and v1
        // It can also set two optional targets :
        // - The closest point on the ray
        // - The closest point on the segment

        _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
        _segDir.copy( v1 ).sub( v0 ).normalize();
        _diff.copy( this.origin ).sub( _segCenter );

        const segExtent = v0.distanceTo( v1 ) * 0.5;
        const a01 = - this.direction.dot( _segDir );
        const b0 = _diff.dot( this.direction );
        const b1 = - _diff.dot( _segDir );
        const c = _diff.lengthSq();
        const det = Math.abs( 1 - a01 * a01 );
        let s0, s1, sqrDist, extDet;

        if ( det > 0 ) {

            // The ray and segment are not parallel.

            s0 = a01 * b1 - b0;
            s1 = a01 * b0 - b1;
            extDet = segExtent * det;

            if ( s0 >= 0 ) {

                if ( s1 >= - extDet ) {

                    if ( s1 <= extDet ) {

                        // region 0
                        // Minimum at interior points of ray and segment.

                        const invDet = 1 / det;
                        s0 *= invDet;
                        s1 *= invDet;
                        sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;

                    } else {

                        // region 1

                        s1 = segExtent;
                        s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
                        sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

                    }

                } else {

                    // region 5

                    s1 = - segExtent;
                    s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
                    sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

                }

            } else {

                if ( s1 <= - extDet ) {

                    // region 4

                    s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
                    s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
                    sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

                } else if ( s1 <= extDet ) {

                    // region 3

                    s0 = 0;
                    s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
                    sqrDist = s1 * ( s1 + 2 * b1 ) + c;

                } else {

                    // region 2

                    s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
                    s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
                    sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

                }

            }

        } else {

            // Ray and segment are parallel.

            s1 = ( a01 > 0 ) ? - segExtent : segExtent;
            s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
            sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

        }

        if ( optionalPointOnRay ) {

            optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 );

        }

        if ( optionalPointOnSegment ) {

            optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 );

        }

        return sqrDist;

    }

    /**
     * Intersects this ray with the given sphere, returning the intersection
     * point or `null` if there is no intersection.
     *
     * @param {Sphere} sphere - The sphere to intersect.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {?Vector3} The intersection point.
     */
    intersectSphere( sphere, target ) {

        _vector.subVectors( sphere.center, this.origin );
        const tca = _vector.dot( this.direction );
        const d2 = _vector.dot( _vector ) - tca * tca;
        const radius2 = sphere.radius * sphere.radius;

        if ( d2 > radius2 ) return null;

        const thc = Math.sqrt( radius2 - d2 );

        // t0 = first intersect point - entrance on front of sphere
        const t0 = tca - thc;

        // t1 = second intersect point - exit point on back of sphere
        const t1 = tca + thc;

        // test to see if t1 is behind the ray - if so, return null
        if ( t1 < 0 ) return null;

        // test to see if t0 is behind the ray:
        // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
        // in order to always return an intersect point that is in front of the ray.
        if ( t0 < 0 ) return this.at( t1, target );

        // else t0 is in front of the ray, so return the first collision point scaled by t0
        return this.at( t0, target );

    }

    /**
     * Returns `true` if this ray intersects with the given sphere.
     *
     * @param {Sphere} sphere - The sphere to intersect.
     * @return {boolean} Whether this ray intersects with the given sphere or not.
     */
    intersectsSphere( sphere ) {

        if ( sphere.radius < 0 ) return false; // handle empty spheres, see #31187

        return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );

    }

    /**
     * Computes the distance from the ray's origin to the given plane. Returns `null` if the ray
     * does not intersect with the plane.
     *
     * @param {Plane} plane - The plane to compute the distance to.
     * @return {?number} Whether this ray intersects with the given sphere or not.
     */
    distanceToPlane( plane ) {

        const denominator = plane.normal.dot( this.direction );

        if ( denominator === 0 ) {

            // line is coplanar, return origin
            if ( plane.distanceToPoint( this.origin ) === 0 ) {

                return 0;

            }

            // Null is preferable to undefined since undefined means.... it is undefined

            return null;

        }

        const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;

        // Return if the ray never intersects the plane

        return t >= 0 ? t : null;

    }

    /**
     * Intersects this ray with the given plane, returning the intersection
     * point or `null` if there is no intersection.
     *
     * @param {Plane} plane - The plane to intersect.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {?Vector3} The intersection point.
     */
    intersectPlane( plane, target ) {

        const t = this.distanceToPlane( plane );

        if ( t === null ) {

            return null;

        }

        return this.at( t, target );

    }

    /**
     * Returns `true` if this ray intersects with the given plane.
     *
     * @param {Plane} plane - The plane to intersect.
     * @return {boolean} Whether this ray intersects with the given plane or not.
     */
    intersectsPlane( plane ) {

        // check if the ray lies on the plane first

        const distToPoint = plane.distanceToPoint( this.origin );

        if ( distToPoint === 0 ) {

            return true;

        }

        const denominator = plane.normal.dot( this.direction );

        if ( denominator * distToPoint < 0 ) {

            return true;

        }

        // ray origin is behind the plane (and is pointing behind it)

        return false;

    }

    /**
     * Intersects this ray with the given bounding box, returning the intersection
     * point or `null` if there is no intersection.
     *
     * @param {Box3} box - The box to intersect.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {?Vector3} The intersection point.
     */
    intersectBox( box, target ) {

        let tmin, tmax, tymin, tymax, tzmin, tzmax;

        const invdirx = 1 / this.direction.x,
            invdiry = 1 / this.direction.y,
            invdirz = 1 / this.direction.z;

        const origin = this.origin;

        if ( invdirx >= 0 ) {

            tmin = ( box.min.x - origin.x ) * invdirx;
            tmax = ( box.max.x - origin.x ) * invdirx;

        } else {

            tmin = ( box.max.x - origin.x ) * invdirx;
            tmax = ( box.min.x - origin.x ) * invdirx;

        }

        if ( invdiry >= 0 ) {

            tymin = ( box.min.y - origin.y ) * invdiry;
            tymax = ( box.max.y - origin.y ) * invdiry;

        } else {

            tymin = ( box.max.y - origin.y ) * invdiry;
            tymax = ( box.min.y - origin.y ) * invdiry;

        }

        if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;

        if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin;

        if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax;

        if ( invdirz >= 0 ) {

            tzmin = ( box.min.z - origin.z ) * invdirz;
            tzmax = ( box.max.z - origin.z ) * invdirz;

        } else {

            tzmin = ( box.max.z - origin.z ) * invdirz;
            tzmax = ( box.min.z - origin.z ) * invdirz;

        }

        if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;

        if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;

        if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;

        //return point closest to the ray (positive side)

        if ( tmax < 0 ) return null;

        return this.at( tmin >= 0 ? tmin : tmax, target );

    }

    /**
     * Returns `true` if this ray intersects with the given box.
     *
     * @param {Box3} box - The box to intersect.
     * @return {boolean} Whether this ray intersects with the given box or not.
     */
    intersectsBox( box ) {

        return this.intersectBox( box, _vector ) !== null;

    }

    /**
     * Intersects this ray with the given triangle, returning the intersection
     * point or `null` if there is no intersection.
     *
     * @param {Vector3} a - The first vertex of the triangle.
     * @param {Vector3} b - The second vertex of the triangle.
     * @param {Vector3} c - The third vertex of the triangle.
     * @param {boolean} backfaceCulling - Whether to use backface culling or not.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {?Vector3} The intersection point.
     */
    intersectTriangle( a, b, c, backfaceCulling, target ) {

        // Compute the offset origin, edges, and normal.

        // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h

        _edge1.subVectors( b, a );
        _edge2.subVectors( c, a );
        _normal.crossVectors( _edge1, _edge2 );

        // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
        // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
        //   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
        //   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
        //   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
        let DdN = this.direction.dot( _normal );
        let sign;

        if ( DdN > 0 ) {

            if ( backfaceCulling ) return null;
            sign = 1;

        } else if ( DdN < 0 ) {

            sign = - 1;
            DdN = - DdN;

        } else {

            return null;

        }

        _diff.subVectors( this.origin, a );
        const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );

        // b1 < 0, no intersection
        if ( DdQxE2 < 0 ) {

            return null;

        }

        const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );

        // b2 < 0, no intersection
        if ( DdE1xQ < 0 ) {

            return null;

        }

        // b1+b2 > 1, no intersection
        if ( DdQxE2 + DdE1xQ > DdN ) {

            return null;

        }

        // Line intersects triangle, check if ray does.
        const QdN = - sign * _diff.dot( _normal );

        // t < 0, no intersection
        if ( QdN < 0 ) {

            return null;

        }

        // Ray intersects triangle.
        return this.at( QdN / DdN, target );

    }

    /**
     * Transforms this ray with the given 4x4 transformation matrix.
     *
     * @param {Matrix4} matrix4 - The transformation matrix.
     * @return {Ray} A reference to this ray.
     */
    applyMatrix4( matrix4 ) {

        this.origin.applyMatrix4( matrix4 );
        this.direction.transformDirection( matrix4 );

        return this;

    }

    /**
     * Returns `true` if this ray is equal with the given one.
     *
     * @param {Ray} ray - The ray to test for equality.
     * @return {boolean} Whether this ray is equal with the given one.
     */
    equals( ray ) {

        return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );

    }

    /**
     * Returns a new ray with copied values from this instance.
     *
     * @return {Ray} A clone of this instance.
     */
    clone() {

        return new this.constructor().copy( this );

    }

}

Methods

set(origin: Vector3, direction: Vector3): Ray
Code
set( origin, direction ) {

        this.origin.copy( origin );
        this.direction.copy( direction );

        return this;

    }
copy(ray: Ray): Ray
Code
copy( ray ) {

        this.origin.copy( ray.origin );
        this.direction.copy( ray.direction );

        return this;

    }
at(t: number, target: Vector3): Vector3
Code
at( t, target ) {

        return target.copy( this.origin ).addScaledVector( this.direction, t );

    }
lookAt(v: Vector3): Ray
Code
lookAt( v ) {

        this.direction.copy( v ).sub( this.origin ).normalize();

        return this;

    }
recast(t: number): Ray
Code
recast( t ) {

        this.origin.copy( this.at( t, _vector ) );

        return this;

    }
closestPointToPoint(point: Vector3, target: Vector3): Vector3
Code
closestPointToPoint( point, target ) {

        target.subVectors( point, this.origin );

        const directionDistance = target.dot( this.direction );

        if ( directionDistance < 0 ) {

            return target.copy( this.origin );

        }

        return target.copy( this.origin ).addScaledVector( this.direction, directionDistance );

    }
distanceToPoint(point: Vector3): number
Code
distanceToPoint( point ) {

        return Math.sqrt( this.distanceSqToPoint( point ) );

    }
distanceSqToPoint(point: Vector3): number
Code
distanceSqToPoint( point ) {

        const directionDistance = _vector.subVectors( point, this.origin ).dot( this.direction );

        // point behind the ray

        if ( directionDistance < 0 ) {

            return this.origin.distanceToSquared( point );

        }

        _vector.copy( this.origin ).addScaledVector( this.direction, directionDistance );

        return _vector.distanceToSquared( point );

    }
distanceSqToSegment(v0: Vector3, v1: Vector3, optionalPointOnRay: Vector3, optionalPointOnSegment: Vector3): number
Code
distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {

        // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h
        // It returns the min distance between the ray and the segment
        // defined by v0 and v1
        // It can also set two optional targets :
        // - The closest point on the ray
        // - The closest point on the segment

        _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
        _segDir.copy( v1 ).sub( v0 ).normalize();
        _diff.copy( this.origin ).sub( _segCenter );

        const segExtent = v0.distanceTo( v1 ) * 0.5;
        const a01 = - this.direction.dot( _segDir );
        const b0 = _diff.dot( this.direction );
        const b1 = - _diff.dot( _segDir );
        const c = _diff.lengthSq();
        const det = Math.abs( 1 - a01 * a01 );
        let s0, s1, sqrDist, extDet;

        if ( det > 0 ) {

            // The ray and segment are not parallel.

            s0 = a01 * b1 - b0;
            s1 = a01 * b0 - b1;
            extDet = segExtent * det;

            if ( s0 >= 0 ) {

                if ( s1 >= - extDet ) {

                    if ( s1 <= extDet ) {

                        // region 0
                        // Minimum at interior points of ray and segment.

                        const invDet = 1 / det;
                        s0 *= invDet;
                        s1 *= invDet;
                        sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;

                    } else {

                        // region 1

                        s1 = segExtent;
                        s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
                        sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

                    }

                } else {

                    // region 5

                    s1 = - segExtent;
                    s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
                    sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

                }

            } else {

                if ( s1 <= - extDet ) {

                    // region 4

                    s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
                    s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
                    sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

                } else if ( s1 <= extDet ) {

                    // region 3

                    s0 = 0;
                    s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
                    sqrDist = s1 * ( s1 + 2 * b1 ) + c;

                } else {

                    // region 2

                    s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
                    s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
                    sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

                }

            }

        } else {

            // Ray and segment are parallel.

            s1 = ( a01 > 0 ) ? - segExtent : segExtent;
            s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
            sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;

        }

        if ( optionalPointOnRay ) {

            optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 );

        }

        if ( optionalPointOnSegment ) {

            optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 );

        }

        return sqrDist;

    }
intersectSphere(sphere: Sphere, target: Vector3): Vector3
Code
intersectSphere( sphere, target ) {

        _vector.subVectors( sphere.center, this.origin );
        const tca = _vector.dot( this.direction );
        const d2 = _vector.dot( _vector ) - tca * tca;
        const radius2 = sphere.radius * sphere.radius;

        if ( d2 > radius2 ) return null;

        const thc = Math.sqrt( radius2 - d2 );

        // t0 = first intersect point - entrance on front of sphere
        const t0 = tca - thc;

        // t1 = second intersect point - exit point on back of sphere
        const t1 = tca + thc;

        // test to see if t1 is behind the ray - if so, return null
        if ( t1 < 0 ) return null;

        // test to see if t0 is behind the ray:
        // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
        // in order to always return an intersect point that is in front of the ray.
        if ( t0 < 0 ) return this.at( t1, target );

        // else t0 is in front of the ray, so return the first collision point scaled by t0
        return this.at( t0, target );

    }
intersectsSphere(sphere: Sphere): boolean
Code
intersectsSphere( sphere ) {

        if ( sphere.radius < 0 ) return false; // handle empty spheres, see #31187

        return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );

    }
distanceToPlane(plane: Plane): number
Code
distanceToPlane( plane ) {

        const denominator = plane.normal.dot( this.direction );

        if ( denominator === 0 ) {

            // line is coplanar, return origin
            if ( plane.distanceToPoint( this.origin ) === 0 ) {

                return 0;

            }

            // Null is preferable to undefined since undefined means.... it is undefined

            return null;

        }

        const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;

        // Return if the ray never intersects the plane

        return t >= 0 ? t : null;

    }
intersectPlane(plane: Plane, target: Vector3): Vector3
Code
intersectPlane( plane, target ) {

        const t = this.distanceToPlane( plane );

        if ( t === null ) {

            return null;

        }

        return this.at( t, target );

    }
intersectsPlane(plane: Plane): boolean
Code
intersectsPlane( plane ) {

        // check if the ray lies on the plane first

        const distToPoint = plane.distanceToPoint( this.origin );

        if ( distToPoint === 0 ) {

            return true;

        }

        const denominator = plane.normal.dot( this.direction );

        if ( denominator * distToPoint < 0 ) {

            return true;

        }

        // ray origin is behind the plane (and is pointing behind it)

        return false;

    }
intersectBox(box: Box3, target: Vector3): Vector3
Code
intersectBox( box, target ) {

        let tmin, tmax, tymin, tymax, tzmin, tzmax;

        const invdirx = 1 / this.direction.x,
            invdiry = 1 / this.direction.y,
            invdirz = 1 / this.direction.z;

        const origin = this.origin;

        if ( invdirx >= 0 ) {

            tmin = ( box.min.x - origin.x ) * invdirx;
            tmax = ( box.max.x - origin.x ) * invdirx;

        } else {

            tmin = ( box.max.x - origin.x ) * invdirx;
            tmax = ( box.min.x - origin.x ) * invdirx;

        }

        if ( invdiry >= 0 ) {

            tymin = ( box.min.y - origin.y ) * invdiry;
            tymax = ( box.max.y - origin.y ) * invdiry;

        } else {

            tymin = ( box.max.y - origin.y ) * invdiry;
            tymax = ( box.min.y - origin.y ) * invdiry;

        }

        if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;

        if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin;

        if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax;

        if ( invdirz >= 0 ) {

            tzmin = ( box.min.z - origin.z ) * invdirz;
            tzmax = ( box.max.z - origin.z ) * invdirz;

        } else {

            tzmin = ( box.max.z - origin.z ) * invdirz;
            tzmax = ( box.min.z - origin.z ) * invdirz;

        }

        if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;

        if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;

        if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;

        //return point closest to the ray (positive side)

        if ( tmax < 0 ) return null;

        return this.at( tmin >= 0 ? tmin : tmax, target );

    }
intersectsBox(box: Box3): boolean
Code
intersectsBox( box ) {

        return this.intersectBox( box, _vector ) !== null;

    }
intersectTriangle(a: Vector3, b: Vector3, c: Vector3, backfaceCulling: boolean, target: Vector3): Vector3
Code
intersectTriangle( a, b, c, backfaceCulling, target ) {

        // Compute the offset origin, edges, and normal.

        // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h

        _edge1.subVectors( b, a );
        _edge2.subVectors( c, a );
        _normal.crossVectors( _edge1, _edge2 );

        // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
        // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
        //   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
        //   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
        //   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
        let DdN = this.direction.dot( _normal );
        let sign;

        if ( DdN > 0 ) {

            if ( backfaceCulling ) return null;
            sign = 1;

        } else if ( DdN < 0 ) {

            sign = - 1;
            DdN = - DdN;

        } else {

            return null;

        }

        _diff.subVectors( this.origin, a );
        const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );

        // b1 < 0, no intersection
        if ( DdQxE2 < 0 ) {

            return null;

        }

        const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );

        // b2 < 0, no intersection
        if ( DdE1xQ < 0 ) {

            return null;

        }

        // b1+b2 > 1, no intersection
        if ( DdQxE2 + DdE1xQ > DdN ) {

            return null;

        }

        // Line intersects triangle, check if ray does.
        const QdN = - sign * _diff.dot( _normal );

        // t < 0, no intersection
        if ( QdN < 0 ) {

            return null;

        }

        // Ray intersects triangle.
        return this.at( QdN / DdN, target );

    }
applyMatrix4(matrix4: Matrix4): Ray
Code
applyMatrix4( matrix4 ) {

        this.origin.applyMatrix4( matrix4 );
        this.direction.transformDirection( matrix4 );

        return this;

    }
equals(ray: Ray): boolean
Code
equals( ray ) {

        return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );

    }
clone(): Ray
Code
clone() {

        return new this.constructor().copy( this );

    }