Skip to content

⬅️ Back to Table of Contents

📄 OBB.js

📊 Analysis Summary

Metric Count
🔧 Functions 15
🧱 Classes 1
📦 Imports 6
📊 Variables & Constants 26

📚 Table of Contents

🛠️ File Location:

📂 examples/jsm/math/OBB.js

📦 Imports

Name Source
Box3 three
MathUtils three
Matrix4 three
Matrix3 three
Ray three
Vector3 three

Variables & Constants

Name Type Kind Value Exported
a { c: any; u: any[]; e: any[]; } let/var { c: null, // center u: [ new Vector3(), new Vector3(), new Vector3() ], // b...
b { c: any; u: any[]; e: any[]; } let/var { c: null, // center u: [ new Vector3(), new Vector3(), new Vector3() ], // b...
R any[][] let/var [[], [], []]
AbsR any[][] let/var [[], [], []]
t any[] let/var []
xAxis any let/var new Vector3()
yAxis any let/var new Vector3()
zAxis any let/var new Vector3()
v1 any let/var new Vector3()
size any let/var new Vector3()
closestPoint any let/var new Vector3()
rotationMatrix any let/var new Matrix3()
aabb any let/var new Box3()
matrix any let/var new Matrix4()
inverse any let/var new Matrix4()
localRay any let/var new Ray()
halfSize Vector3 let/var this.halfSize
ra any let/var *not shown*
rb any let/var *not shown*
r number let/var this.halfSize.x * Math.abs( plane.normal.dot( xAxis ) ) + this.halfSize.y * M...
d number let/var plane.normal.dot( this.center ) - plane.constant
e any let/var matrix.elements
invSX number let/var 1 / sx
invSY number let/var 1 / sy
invSZ number let/var 1 / sz
obb OBB let/var new OBB()

Functions

OBB.set(center: Vector3, halfSize: Vector3, rotation: Matrix3): OBB

JSDoc:

/**
     * Sets the OBBs components to the given values.
     *
     * @param {Vector3} [center] - The center of the OBB.
     * @param {Vector3} [halfSize] - Positive halfwidth extents of the OBB along each axis.
     * @param {Matrix3} [rotation] - The rotation of the OBB.
     * @return {OBB} A reference to this OBB.
     */

Parameters:

  • center Vector3
  • halfSize Vector3
  • rotation Matrix3

Returns: OBB

Code
set( center, halfSize, rotation ) {

        this.center = center;
        this.halfSize = halfSize;
        this.rotation = rotation;

        return this;

    }

OBB.copy(obb: OBB): OBB

JSDoc:

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

Parameters:

  • obb OBB

Returns: OBB

Calls:

  • this.center.copy
  • this.halfSize.copy
  • this.rotation.copy
Code
copy( obb ) {

        this.center.copy( obb.center );
        this.halfSize.copy( obb.halfSize );
        this.rotation.copy( obb.rotation );

        return this;

    }

OBB.clone(): OBB

JSDoc:

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

Returns: OBB

Calls:

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

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

    }

OBB.getSize(target: Vector3): Vector3

JSDoc:

/**
     * Returns the size of this OBB.
     *
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} The size.
     */

Parameters:

  • target Vector3

Returns: Vector3

Calls:

  • target.copy( this.halfSize ).multiplyScalar
Code
getSize( target ) {

        return target.copy( this.halfSize ).multiplyScalar( 2 );

    }

OBB.clampPoint(point: Vector3, target: Vector3): Vector3

JSDoc:

/**
     * Clamps the given point within the bounds of this OBB.
     *
     * @param {Vector3} point - The point that should be clamped within the bounds of this OBB.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @returns {Vector3} - The clamped point.
     */

Parameters:

  • point Vector3
  • target Vector3

Returns: Vector3

Calls:

  • v1.subVectors
  • this.rotation.extractBasis
  • target.copy
  • MathUtils.clamp
  • v1.dot
  • target.add
  • xAxis.multiplyScalar
  • yAxis.multiplyScalar
  • zAxis.multiplyScalar

Internal Comments:

// Reference: Closest Point on OBB to Point in Real-Time Collision Detection (x2)
// by Christer Ericson (chapter 5.1.4) (x2)
// start at the center position of the OBB (x4)
// project the target onto the OBB axes and walk towards that point (x2)

Code
clampPoint( point, target ) {

        // Reference: Closest Point on OBB to Point in Real-Time Collision Detection
        // by Christer Ericson (chapter 5.1.4)

        const halfSize = this.halfSize;

        v1.subVectors( point, this.center );
        this.rotation.extractBasis( xAxis, yAxis, zAxis );

        // start at the center position of the OBB

        target.copy( this.center );

        // project the target onto the OBB axes and walk towards that point

        const x = MathUtils.clamp( v1.dot( xAxis ), - halfSize.x, halfSize.x );
        target.add( xAxis.multiplyScalar( x ) );

        const y = MathUtils.clamp( v1.dot( yAxis ), - halfSize.y, halfSize.y );
        target.add( yAxis.multiplyScalar( y ) );

        const z = MathUtils.clamp( v1.dot( zAxis ), - halfSize.z, halfSize.z );
        target.add( zAxis.multiplyScalar( z ) );

        return target;

    }

OBB.containsPoint(point: Vector3): boolean

JSDoc:

/**
     * Returns `true` if the given point lies within this OBB.
     *
     * @param {Vector3} point - The point to test.
     * @returns {boolean} - Whether the given point lies within this OBB or not.
     */

Parameters:

  • point Vector3

Returns: boolean

Calls:

  • v1.subVectors
  • this.rotation.extractBasis
  • Math.abs
  • v1.dot

Internal Comments:

// project v1 onto each axis and check if these points lie inside the OBB

Code
containsPoint( point ) {

        v1.subVectors( point, this.center );
        this.rotation.extractBasis( xAxis, yAxis, zAxis );

        // project v1 onto each axis and check if these points lie inside the OBB

        return Math.abs( v1.dot( xAxis ) ) <= this.halfSize.x &&
                Math.abs( v1.dot( yAxis ) ) <= this.halfSize.y &&
                Math.abs( v1.dot( zAxis ) ) <= this.halfSize.z;

    }

OBB.intersectsBox3(box3: Box3): boolean

JSDoc:

/**
     * Returns `true` if the given AABB intersects this OBB.
     *
     * @param {Box3} box3 - The AABB to test.
     * @returns {boolean} - Whether the given AABB intersects this OBB or not.
     */

Parameters:

  • box3 Box3

Returns: boolean

Calls:

  • this.intersectsOBB
  • obb.fromBox3
Code
intersectsBox3( box3 ) {

        return this.intersectsOBB( obb.fromBox3( box3 ) );

    }

OBB.intersectsSphere(sphere: Sphere): boolean

JSDoc:

/**
     * Returns `true` if the given bounding sphere intersects this OBB.
     *
     * @param {Sphere} sphere - The bounding sphere to test.
     * @returns {boolean} - Whether the given bounding sphere intersects this OBB or not.
     */

Parameters:

  • sphere Sphere

Returns: boolean

Calls:

  • this.clampPoint
  • closestPoint.distanceToSquared

Internal Comments:

// find the point on the OBB closest to the sphere center (x4)
// if that point is inside the sphere, the OBB and sphere intersect

Code
intersectsSphere( sphere ) {

        // find the point on the OBB closest to the sphere center

        this.clampPoint( sphere.center, closestPoint );

        // if that point is inside the sphere, the OBB and sphere intersect

        return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );

    }

OBB.intersectsOBB(obb: OBB, epsilon: number): boolean

JSDoc:

/**
     * Returns `true` if the given OBB intersects this OBB.
     *
     * @param {OBB} obb - The OBB to test.
     * @param {number} [epsilon=Number.EPSILON] - A small value to prevent arithmetic errors.
     * @returns {boolean} - Whether the given OBB intersects this OBB or not.
     */

Parameters:

  • obb OBB
  • epsilon number

Returns: boolean

Calls:

  • this.rotation.extractBasis
  • obb.rotation.extractBasis
  • a.u[ i ].dot
  • v1.subVectors
  • v1.dot
  • Math.abs

Internal Comments:

// Reference: OBB-OBB Intersection in Real-Time Collision Detection (x4)
// by Christer Ericson (chapter 4.4.1) (x4)
// prepare data structures (the code uses the same nomenclature like the reference) (x4)
// compute rotation matrix expressing b in a's coordinate frame
// compute translation vector (x4)
// bring translation into a's coordinate frame (x4)
// compute common subexpressions. Add in an epsilon term to
// counteract arithmetic errors when two edges are parallel and
// their cross product is (near) null
// test axes L = A0, L = A1, L = A2
// test axes L = B0, L = B1, L = B2
// test axis L = A0 x B0 (x3)
// test axis L = A0 x B1 (x3)
// test axis L = A0 x B2 (x3)
// test axis L = A1 x B0 (x3)
// test axis L = A1 x B1 (x3)
// test axis L = A1 x B2 (x3)
// test axis L = A2 x B0 (x3)
// test axis L = A2 x B1 (x3)
// test axis L = A2 x B2 (x3)
// since no separating axis is found, the OBBs must be intersecting

Code
intersectsOBB( obb, epsilon = Number.EPSILON ) {

        // Reference: OBB-OBB Intersection in Real-Time Collision Detection
        // by Christer Ericson (chapter 4.4.1)

        // prepare data structures (the code uses the same nomenclature like the reference)

        a.c = this.center;
        a.e[ 0 ] = this.halfSize.x;
        a.e[ 1 ] = this.halfSize.y;
        a.e[ 2 ] = this.halfSize.z;
        this.rotation.extractBasis( a.u[ 0 ], a.u[ 1 ], a.u[ 2 ] );

        b.c = obb.center;
        b.e[ 0 ] = obb.halfSize.x;
        b.e[ 1 ] = obb.halfSize.y;
        b.e[ 2 ] = obb.halfSize.z;
        obb.rotation.extractBasis( b.u[ 0 ], b.u[ 1 ], b.u[ 2 ] );

        // compute rotation matrix expressing b in a's coordinate frame

        for ( let i = 0; i < 3; i ++ ) {

            for ( let j = 0; j < 3; j ++ ) {

                R[ i ][ j ] = a.u[ i ].dot( b.u[ j ] );

            }

        }

        // compute translation vector

        v1.subVectors( b.c, a.c );

        // bring translation into a's coordinate frame

        t[ 0 ] = v1.dot( a.u[ 0 ] );
        t[ 1 ] = v1.dot( a.u[ 1 ] );
        t[ 2 ] = v1.dot( a.u[ 2 ] );

        // compute common subexpressions. Add in an epsilon term to
        // counteract arithmetic errors when two edges are parallel and
        // their cross product is (near) null

        for ( let i = 0; i < 3; i ++ ) {

            for ( let j = 0; j < 3; j ++ ) {

                AbsR[ i ][ j ] = Math.abs( R[ i ][ j ] ) + epsilon;

            }

        }

        let ra, rb;

        // test axes L = A0, L = A1, L = A2

        for ( let i = 0; i < 3; i ++ ) {

            ra = a.e[ i ];
            rb = b.e[ 0 ] * AbsR[ i ][ 0 ] + b.e[ 1 ] * AbsR[ i ][ 1 ] + b.e[ 2 ] * AbsR[ i ][ 2 ];
            if ( Math.abs( t[ i ] ) > ra + rb ) return false;


        }

        // test axes L = B0, L = B1, L = B2

        for ( let i = 0; i < 3; i ++ ) {

            ra = a.e[ 0 ] * AbsR[ 0 ][ i ] + a.e[ 1 ] * AbsR[ 1 ][ i ] + a.e[ 2 ] * AbsR[ 2 ][ i ];
            rb = b.e[ i ];
            if ( Math.abs( t[ 0 ] * R[ 0 ][ i ] + t[ 1 ] * R[ 1 ][ i ] + t[ 2 ] * R[ 2 ][ i ] ) > ra + rb ) return false;

        }

        // test axis L = A0 x B0

        ra = a.e[ 1 ] * AbsR[ 2 ][ 0 ] + a.e[ 2 ] * AbsR[ 1 ][ 0 ];
        rb = b.e[ 1 ] * AbsR[ 0 ][ 2 ] + b.e[ 2 ] * AbsR[ 0 ][ 1 ];
        if ( Math.abs( t[ 2 ] * R[ 1 ][ 0 ] - t[ 1 ] * R[ 2 ][ 0 ] ) > ra + rb ) return false;

        // test axis L = A0 x B1

        ra = a.e[ 1 ] * AbsR[ 2 ][ 1 ] + a.e[ 2 ] * AbsR[ 1 ][ 1 ];
        rb = b.e[ 0 ] * AbsR[ 0 ][ 2 ] + b.e[ 2 ] * AbsR[ 0 ][ 0 ];
        if ( Math.abs( t[ 2 ] * R[ 1 ][ 1 ] - t[ 1 ] * R[ 2 ][ 1 ] ) > ra + rb ) return false;

        // test axis L = A0 x B2

        ra = a.e[ 1 ] * AbsR[ 2 ][ 2 ] + a.e[ 2 ] * AbsR[ 1 ][ 2 ];
        rb = b.e[ 0 ] * AbsR[ 0 ][ 1 ] + b.e[ 1 ] * AbsR[ 0 ][ 0 ];
        if ( Math.abs( t[ 2 ] * R[ 1 ][ 2 ] - t[ 1 ] * R[ 2 ][ 2 ] ) > ra + rb ) return false;

        // test axis L = A1 x B0

        ra = a.e[ 0 ] * AbsR[ 2 ][ 0 ] + a.e[ 2 ] * AbsR[ 0 ][ 0 ];
        rb = b.e[ 1 ] * AbsR[ 1 ][ 2 ] + b.e[ 2 ] * AbsR[ 1 ][ 1 ];
        if ( Math.abs( t[ 0 ] * R[ 2 ][ 0 ] - t[ 2 ] * R[ 0 ][ 0 ] ) > ra + rb ) return false;

        // test axis L = A1 x B1

        ra = a.e[ 0 ] * AbsR[ 2 ][ 1 ] + a.e[ 2 ] * AbsR[ 0 ][ 1 ];
        rb = b.e[ 0 ] * AbsR[ 1 ][ 2 ] + b.e[ 2 ] * AbsR[ 1 ][ 0 ];
        if ( Math.abs( t[ 0 ] * R[ 2 ][ 1 ] - t[ 2 ] * R[ 0 ][ 1 ] ) > ra + rb ) return false;

        // test axis L = A1 x B2

        ra = a.e[ 0 ] * AbsR[ 2 ][ 2 ] + a.e[ 2 ] * AbsR[ 0 ][ 2 ];
        rb = b.e[ 0 ] * AbsR[ 1 ][ 1 ] + b.e[ 1 ] * AbsR[ 1 ][ 0 ];
        if ( Math.abs( t[ 0 ] * R[ 2 ][ 2 ] - t[ 2 ] * R[ 0 ][ 2 ] ) > ra + rb ) return false;

        // test axis L = A2 x B0

        ra = a.e[ 0 ] * AbsR[ 1 ][ 0 ] + a.e[ 1 ] * AbsR[ 0 ][ 0 ];
        rb = b.e[ 1 ] * AbsR[ 2 ][ 2 ] + b.e[ 2 ] * AbsR[ 2 ][ 1 ];
        if ( Math.abs( t[ 1 ] * R[ 0 ][ 0 ] - t[ 0 ] * R[ 1 ][ 0 ] ) > ra + rb ) return false;

        // test axis L = A2 x B1

        ra = a.e[ 0 ] * AbsR[ 1 ][ 1 ] + a.e[ 1 ] * AbsR[ 0 ][ 1 ];
        rb = b.e[ 0 ] * AbsR[ 2 ][ 2 ] + b.e[ 2 ] * AbsR[ 2 ][ 0 ];
        if ( Math.abs( t[ 1 ] * R[ 0 ][ 1 ] - t[ 0 ] * R[ 1 ][ 1 ] ) > ra + rb ) return false;

        // test axis L = A2 x B2

        ra = a.e[ 0 ] * AbsR[ 1 ][ 2 ] + a.e[ 1 ] * AbsR[ 0 ][ 2 ];
        rb = b.e[ 0 ] * AbsR[ 2 ][ 1 ] + b.e[ 1 ] * AbsR[ 2 ][ 0 ];
        if ( Math.abs( t[ 1 ] * R[ 0 ][ 2 ] - t[ 0 ] * R[ 1 ][ 2 ] ) > ra + rb ) return false;

        // since no separating axis is found, the OBBs must be intersecting

        return true;

    }

OBB.intersectsPlane(plane: Plane): boolean

JSDoc:

/**
     * Returns `true` if the given plane intersects this OBB.
     *
     * @param {Plane} plane - The plane to test.
     * @returns {boolean} Whether the given plane intersects this OBB or not.
     */

Parameters:

  • plane Plane

Returns: boolean

Calls:

  • this.rotation.extractBasis
  • Math.abs
  • plane.normal.dot

Internal Comments:

// Reference: Testing Box Against Plane in Real-Time Collision Detection (x5)
// by Christer Ericson (chapter 5.2.3) (x5)
// compute the projection interval radius of this OBB onto L(t) = this->center + t * p.normal; (x2)
// compute distance of the OBB's center from the plane (x2)
// Intersection occurs when distance d falls within [-r,+r] interval

Code
intersectsPlane( plane ) {

        // Reference: Testing Box Against Plane in Real-Time Collision Detection
        // by Christer Ericson (chapter 5.2.3)

        this.rotation.extractBasis( xAxis, yAxis, zAxis );

        // compute the projection interval radius of this OBB onto L(t) = this->center + t * p.normal;

        const r = this.halfSize.x * Math.abs( plane.normal.dot( xAxis ) ) +
                this.halfSize.y * Math.abs( plane.normal.dot( yAxis ) ) +
                this.halfSize.z * Math.abs( plane.normal.dot( zAxis ) );

        // compute distance of the OBB's center from the plane

        const d = plane.normal.dot( this.center ) - plane.constant;

        // Intersection occurs when distance d falls within [-r,+r] interval

        return Math.abs( d ) <= r;

    }

OBB.intersectRay(ray: Ray, target: Vector3): Vector3

JSDoc:

/**
     * Performs a ray/OBB intersection test and stores the intersection point
     * in the given 3D vector.
     *
     * @param {Ray} ray - The ray to test.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {?Vector3} The intersection point. If no intersection is detected, `null` is returned.
     */

Parameters:

  • ray Ray
  • target Vector3

Returns: Vector3

Calls:

  • this.getSize
  • aabb.setFromCenterAndSize
  • v1.set
  • matrix.setFromMatrix3
  • matrix.setPosition
  • inverse.copy( matrix ).invert
  • localRay.copy( ray ).applyMatrix4
  • localRay.intersectBox
  • target.applyMatrix4

Internal Comments:

// the idea is to perform the intersection test in the local space (x4)
// of the OBB. (x4)
// create a 4x4 transformation matrix (x4)
// transform ray to the local space of the OBB (x6)
// perform ray <-> AABB intersection test
// transform the intersection point back to world space

Code
intersectRay( ray, target ) {

        // the idea is to perform the intersection test in the local space
        // of the OBB.

        this.getSize( size );
        aabb.setFromCenterAndSize( v1.set( 0, 0, 0 ), size );

        // create a 4x4 transformation matrix

        matrix.setFromMatrix3( this.rotation );
        matrix.setPosition( this.center );

        // transform ray to the local space of the OBB

        inverse.copy( matrix ).invert();
        localRay.copy( ray ).applyMatrix4( inverse );

        // perform ray <-> AABB intersection test

        if ( localRay.intersectBox( aabb, target ) ) {

            // transform the intersection point back to world space

            return target.applyMatrix4( matrix );

        } else {

            return null;

        }

    }

OBB.intersectsRay(ray: Ray): boolean

JSDoc:

/**
     * Returns `true` if the given ray intersects this OBB.
     *
     * @param {Ray} ray - The ray to test.
     * @returns {boolean} Whether the given ray intersects this OBB or not.
     */

Parameters:

  • ray Ray

Returns: boolean

Calls:

  • this.intersectRay
Code
intersectsRay( ray ) {

        return this.intersectRay( ray, v1 ) !== null;

    }

OBB.fromBox3(box3: Box3): OBB

JSDoc:

/**
     * Defines an OBB based on the given AABB.
     *
     * @param {Box3} box3 - The AABB to setup the OBB from.
     * @return {OBB} A reference of this OBB.
     */

Parameters:

  • box3 Box3

Returns: OBB

Calls:

  • box3.getCenter
  • box3.getSize( this.halfSize ).multiplyScalar
  • this.rotation.identity
Code
fromBox3( box3 ) {

        box3.getCenter( this.center );

        box3.getSize( this.halfSize ).multiplyScalar( 0.5 );

        this.rotation.identity();

        return this;

    }

OBB.equals(obb: OBB): boolean

JSDoc:

/**
     * Returns `true` if the given OBB is equal to this OBB.
     *
     * @param {OBB} obb - The OBB to test.
     * @returns {boolean} Whether the given OBB is equal to this OBB or not.
     */

Parameters:

  • obb OBB

Returns: boolean

Calls:

  • obb.center.equals
  • obb.halfSize.equals
  • obb.rotation.equals
Code
equals( obb ) {

        return obb.center.equals( this.center ) &&
            obb.halfSize.equals( this.halfSize ) &&
            obb.rotation.equals( this.rotation );

    }

OBB.applyMatrix4(matrix: Matrix4): OBB

JSDoc:

/**
     * Applies the given transformation matrix to this OBB. This method can be
     * used to transform the bounding volume with the world matrix of a 3D object
     * in order to keep both entities in sync.
     *
     * @param {Matrix4} matrix - The matrix to apply.
     * @return {OBB} A reference of this OBB.
     */

Parameters:

  • matrix Matrix4

Returns: OBB

Calls:

  • v1.set( e[ 0 ], e[ 1 ], e[ 2 ] ).length
  • v1.set( e[ 4 ], e[ 5 ], e[ 6 ] ).length
  • v1.set( e[ 8 ], e[ 9 ], e[ 10 ] ).length
  • matrix.determinant
  • rotationMatrix.setFromMatrix4
  • this.rotation.multiply
  • v1.setFromMatrixPosition
  • this.center.add
Code
applyMatrix4( matrix ) {

        const e = matrix.elements;

        let sx = v1.set( e[ 0 ], e[ 1 ], e[ 2 ] ).length();
        const sy = v1.set( e[ 4 ], e[ 5 ], e[ 6 ] ).length();
        const sz = v1.set( e[ 8 ], e[ 9 ], e[ 10 ] ).length();

        const det = matrix.determinant();
        if ( det < 0 ) sx = - sx;

        rotationMatrix.setFromMatrix4( matrix );

        const invSX = 1 / sx;
        const invSY = 1 / sy;
        const invSZ = 1 / sz;

        rotationMatrix.elements[ 0 ] *= invSX;
        rotationMatrix.elements[ 1 ] *= invSX;
        rotationMatrix.elements[ 2 ] *= invSX;

        rotationMatrix.elements[ 3 ] *= invSY;
        rotationMatrix.elements[ 4 ] *= invSY;
        rotationMatrix.elements[ 5 ] *= invSY;

        rotationMatrix.elements[ 6 ] *= invSZ;
        rotationMatrix.elements[ 7 ] *= invSZ;
        rotationMatrix.elements[ 8 ] *= invSZ;

        this.rotation.multiply( rotationMatrix );

        this.halfSize.x *= sx;
        this.halfSize.y *= sy;
        this.halfSize.z *= sz;

        v1.setFromMatrixPosition( matrix );
        this.center.add( v1 );

        return this;

    }

Classes

OBB

Class Code
class OBB {

    /**
     * Constructs a new OBB.
     *
     * @param {Vector3} [center] - The center of the OBB.
     * @param {Vector3} [halfSize] - Positive halfwidth extents of the OBB along each axis.
     * @param {Matrix3} [rotation] - The rotation of the OBB.
     */
    constructor( center = new Vector3(), halfSize = new Vector3(), rotation = new Matrix3() ) {

        /**
         * The center of the OBB.
         *
         * @type {Vector3}
         */
        this.center = center;

        /**
         * Positive halfwidth extents of the OBB along each axis.
         *
         * @type {Vector3}
         */
        this.halfSize = halfSize;

        /**
         * The rotation of the OBB.
         *
         * @type {Matrix3}
         */
        this.rotation = rotation;

    }

    /**
     * Sets the OBBs components to the given values.
     *
     * @param {Vector3} [center] - The center of the OBB.
     * @param {Vector3} [halfSize] - Positive halfwidth extents of the OBB along each axis.
     * @param {Matrix3} [rotation] - The rotation of the OBB.
     * @return {OBB} A reference to this OBB.
     */
    set( center, halfSize, rotation ) {

        this.center = center;
        this.halfSize = halfSize;
        this.rotation = rotation;

        return this;

    }

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

        this.center.copy( obb.center );
        this.halfSize.copy( obb.halfSize );
        this.rotation.copy( obb.rotation );

        return this;

    }

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

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

    }

    /**
     * Returns the size of this OBB.
     *
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {Vector3} The size.
     */
    getSize( target ) {

        return target.copy( this.halfSize ).multiplyScalar( 2 );

    }

    /**
     * Clamps the given point within the bounds of this OBB.
     *
     * @param {Vector3} point - The point that should be clamped within the bounds of this OBB.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @returns {Vector3} - The clamped point.
     */
    clampPoint( point, target ) {

        // Reference: Closest Point on OBB to Point in Real-Time Collision Detection
        // by Christer Ericson (chapter 5.1.4)

        const halfSize = this.halfSize;

        v1.subVectors( point, this.center );
        this.rotation.extractBasis( xAxis, yAxis, zAxis );

        // start at the center position of the OBB

        target.copy( this.center );

        // project the target onto the OBB axes and walk towards that point

        const x = MathUtils.clamp( v1.dot( xAxis ), - halfSize.x, halfSize.x );
        target.add( xAxis.multiplyScalar( x ) );

        const y = MathUtils.clamp( v1.dot( yAxis ), - halfSize.y, halfSize.y );
        target.add( yAxis.multiplyScalar( y ) );

        const z = MathUtils.clamp( v1.dot( zAxis ), - halfSize.z, halfSize.z );
        target.add( zAxis.multiplyScalar( z ) );

        return target;

    }

    /**
     * Returns `true` if the given point lies within this OBB.
     *
     * @param {Vector3} point - The point to test.
     * @returns {boolean} - Whether the given point lies within this OBB or not.
     */
    containsPoint( point ) {

        v1.subVectors( point, this.center );
        this.rotation.extractBasis( xAxis, yAxis, zAxis );

        // project v1 onto each axis and check if these points lie inside the OBB

        return Math.abs( v1.dot( xAxis ) ) <= this.halfSize.x &&
                Math.abs( v1.dot( yAxis ) ) <= this.halfSize.y &&
                Math.abs( v1.dot( zAxis ) ) <= this.halfSize.z;

    }

    /**
     * Returns `true` if the given AABB intersects this OBB.
     *
     * @param {Box3} box3 - The AABB to test.
     * @returns {boolean} - Whether the given AABB intersects this OBB or not.
     */
    intersectsBox3( box3 ) {

        return this.intersectsOBB( obb.fromBox3( box3 ) );

    }

    /**
     * Returns `true` if the given bounding sphere intersects this OBB.
     *
     * @param {Sphere} sphere - The bounding sphere to test.
     * @returns {boolean} - Whether the given bounding sphere intersects this OBB or not.
     */
    intersectsSphere( sphere ) {

        // find the point on the OBB closest to the sphere center

        this.clampPoint( sphere.center, closestPoint );

        // if that point is inside the sphere, the OBB and sphere intersect

        return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );

    }

    /**
     * Returns `true` if the given OBB intersects this OBB.
     *
     * @param {OBB} obb - The OBB to test.
     * @param {number} [epsilon=Number.EPSILON] - A small value to prevent arithmetic errors.
     * @returns {boolean} - Whether the given OBB intersects this OBB or not.
     */
    intersectsOBB( obb, epsilon = Number.EPSILON ) {

        // Reference: OBB-OBB Intersection in Real-Time Collision Detection
        // by Christer Ericson (chapter 4.4.1)

        // prepare data structures (the code uses the same nomenclature like the reference)

        a.c = this.center;
        a.e[ 0 ] = this.halfSize.x;
        a.e[ 1 ] = this.halfSize.y;
        a.e[ 2 ] = this.halfSize.z;
        this.rotation.extractBasis( a.u[ 0 ], a.u[ 1 ], a.u[ 2 ] );

        b.c = obb.center;
        b.e[ 0 ] = obb.halfSize.x;
        b.e[ 1 ] = obb.halfSize.y;
        b.e[ 2 ] = obb.halfSize.z;
        obb.rotation.extractBasis( b.u[ 0 ], b.u[ 1 ], b.u[ 2 ] );

        // compute rotation matrix expressing b in a's coordinate frame

        for ( let i = 0; i < 3; i ++ ) {

            for ( let j = 0; j < 3; j ++ ) {

                R[ i ][ j ] = a.u[ i ].dot( b.u[ j ] );

            }

        }

        // compute translation vector

        v1.subVectors( b.c, a.c );

        // bring translation into a's coordinate frame

        t[ 0 ] = v1.dot( a.u[ 0 ] );
        t[ 1 ] = v1.dot( a.u[ 1 ] );
        t[ 2 ] = v1.dot( a.u[ 2 ] );

        // compute common subexpressions. Add in an epsilon term to
        // counteract arithmetic errors when two edges are parallel and
        // their cross product is (near) null

        for ( let i = 0; i < 3; i ++ ) {

            for ( let j = 0; j < 3; j ++ ) {

                AbsR[ i ][ j ] = Math.abs( R[ i ][ j ] ) + epsilon;

            }

        }

        let ra, rb;

        // test axes L = A0, L = A1, L = A2

        for ( let i = 0; i < 3; i ++ ) {

            ra = a.e[ i ];
            rb = b.e[ 0 ] * AbsR[ i ][ 0 ] + b.e[ 1 ] * AbsR[ i ][ 1 ] + b.e[ 2 ] * AbsR[ i ][ 2 ];
            if ( Math.abs( t[ i ] ) > ra + rb ) return false;


        }

        // test axes L = B0, L = B1, L = B2

        for ( let i = 0; i < 3; i ++ ) {

            ra = a.e[ 0 ] * AbsR[ 0 ][ i ] + a.e[ 1 ] * AbsR[ 1 ][ i ] + a.e[ 2 ] * AbsR[ 2 ][ i ];
            rb = b.e[ i ];
            if ( Math.abs( t[ 0 ] * R[ 0 ][ i ] + t[ 1 ] * R[ 1 ][ i ] + t[ 2 ] * R[ 2 ][ i ] ) > ra + rb ) return false;

        }

        // test axis L = A0 x B0

        ra = a.e[ 1 ] * AbsR[ 2 ][ 0 ] + a.e[ 2 ] * AbsR[ 1 ][ 0 ];
        rb = b.e[ 1 ] * AbsR[ 0 ][ 2 ] + b.e[ 2 ] * AbsR[ 0 ][ 1 ];
        if ( Math.abs( t[ 2 ] * R[ 1 ][ 0 ] - t[ 1 ] * R[ 2 ][ 0 ] ) > ra + rb ) return false;

        // test axis L = A0 x B1

        ra = a.e[ 1 ] * AbsR[ 2 ][ 1 ] + a.e[ 2 ] * AbsR[ 1 ][ 1 ];
        rb = b.e[ 0 ] * AbsR[ 0 ][ 2 ] + b.e[ 2 ] * AbsR[ 0 ][ 0 ];
        if ( Math.abs( t[ 2 ] * R[ 1 ][ 1 ] - t[ 1 ] * R[ 2 ][ 1 ] ) > ra + rb ) return false;

        // test axis L = A0 x B2

        ra = a.e[ 1 ] * AbsR[ 2 ][ 2 ] + a.e[ 2 ] * AbsR[ 1 ][ 2 ];
        rb = b.e[ 0 ] * AbsR[ 0 ][ 1 ] + b.e[ 1 ] * AbsR[ 0 ][ 0 ];
        if ( Math.abs( t[ 2 ] * R[ 1 ][ 2 ] - t[ 1 ] * R[ 2 ][ 2 ] ) > ra + rb ) return false;

        // test axis L = A1 x B0

        ra = a.e[ 0 ] * AbsR[ 2 ][ 0 ] + a.e[ 2 ] * AbsR[ 0 ][ 0 ];
        rb = b.e[ 1 ] * AbsR[ 1 ][ 2 ] + b.e[ 2 ] * AbsR[ 1 ][ 1 ];
        if ( Math.abs( t[ 0 ] * R[ 2 ][ 0 ] - t[ 2 ] * R[ 0 ][ 0 ] ) > ra + rb ) return false;

        // test axis L = A1 x B1

        ra = a.e[ 0 ] * AbsR[ 2 ][ 1 ] + a.e[ 2 ] * AbsR[ 0 ][ 1 ];
        rb = b.e[ 0 ] * AbsR[ 1 ][ 2 ] + b.e[ 2 ] * AbsR[ 1 ][ 0 ];
        if ( Math.abs( t[ 0 ] * R[ 2 ][ 1 ] - t[ 2 ] * R[ 0 ][ 1 ] ) > ra + rb ) return false;

        // test axis L = A1 x B2

        ra = a.e[ 0 ] * AbsR[ 2 ][ 2 ] + a.e[ 2 ] * AbsR[ 0 ][ 2 ];
        rb = b.e[ 0 ] * AbsR[ 1 ][ 1 ] + b.e[ 1 ] * AbsR[ 1 ][ 0 ];
        if ( Math.abs( t[ 0 ] * R[ 2 ][ 2 ] - t[ 2 ] * R[ 0 ][ 2 ] ) > ra + rb ) return false;

        // test axis L = A2 x B0

        ra = a.e[ 0 ] * AbsR[ 1 ][ 0 ] + a.e[ 1 ] * AbsR[ 0 ][ 0 ];
        rb = b.e[ 1 ] * AbsR[ 2 ][ 2 ] + b.e[ 2 ] * AbsR[ 2 ][ 1 ];
        if ( Math.abs( t[ 1 ] * R[ 0 ][ 0 ] - t[ 0 ] * R[ 1 ][ 0 ] ) > ra + rb ) return false;

        // test axis L = A2 x B1

        ra = a.e[ 0 ] * AbsR[ 1 ][ 1 ] + a.e[ 1 ] * AbsR[ 0 ][ 1 ];
        rb = b.e[ 0 ] * AbsR[ 2 ][ 2 ] + b.e[ 2 ] * AbsR[ 2 ][ 0 ];
        if ( Math.abs( t[ 1 ] * R[ 0 ][ 1 ] - t[ 0 ] * R[ 1 ][ 1 ] ) > ra + rb ) return false;

        // test axis L = A2 x B2

        ra = a.e[ 0 ] * AbsR[ 1 ][ 2 ] + a.e[ 1 ] * AbsR[ 0 ][ 2 ];
        rb = b.e[ 0 ] * AbsR[ 2 ][ 1 ] + b.e[ 1 ] * AbsR[ 2 ][ 0 ];
        if ( Math.abs( t[ 1 ] * R[ 0 ][ 2 ] - t[ 0 ] * R[ 1 ][ 2 ] ) > ra + rb ) return false;

        // since no separating axis is found, the OBBs must be intersecting

        return true;

    }

    /**
     * Returns `true` if the given plane intersects this OBB.
     *
     * @param {Plane} plane - The plane to test.
     * @returns {boolean} Whether the given plane intersects this OBB or not.
     */
    intersectsPlane( plane ) {

        // Reference: Testing Box Against Plane in Real-Time Collision Detection
        // by Christer Ericson (chapter 5.2.3)

        this.rotation.extractBasis( xAxis, yAxis, zAxis );

        // compute the projection interval radius of this OBB onto L(t) = this->center + t * p.normal;

        const r = this.halfSize.x * Math.abs( plane.normal.dot( xAxis ) ) +
                this.halfSize.y * Math.abs( plane.normal.dot( yAxis ) ) +
                this.halfSize.z * Math.abs( plane.normal.dot( zAxis ) );

        // compute distance of the OBB's center from the plane

        const d = plane.normal.dot( this.center ) - plane.constant;

        // Intersection occurs when distance d falls within [-r,+r] interval

        return Math.abs( d ) <= r;

    }

    /**
     * Performs a ray/OBB intersection test and stores the intersection point
     * in the given 3D vector.
     *
     * @param {Ray} ray - The ray to test.
     * @param {Vector3} target - The target vector that is used to store the method's result.
     * @return {?Vector3} The intersection point. If no intersection is detected, `null` is returned.
     */
    intersectRay( ray, target ) {

        // the idea is to perform the intersection test in the local space
        // of the OBB.

        this.getSize( size );
        aabb.setFromCenterAndSize( v1.set( 0, 0, 0 ), size );

        // create a 4x4 transformation matrix

        matrix.setFromMatrix3( this.rotation );
        matrix.setPosition( this.center );

        // transform ray to the local space of the OBB

        inverse.copy( matrix ).invert();
        localRay.copy( ray ).applyMatrix4( inverse );

        // perform ray <-> AABB intersection test

        if ( localRay.intersectBox( aabb, target ) ) {

            // transform the intersection point back to world space

            return target.applyMatrix4( matrix );

        } else {

            return null;

        }

    }

    /**
     * Returns `true` if the given ray intersects this OBB.
     *
     * @param {Ray} ray - The ray to test.
     * @returns {boolean} Whether the given ray intersects this OBB or not.
     */
    intersectsRay( ray ) {

        return this.intersectRay( ray, v1 ) !== null;

    }

    /**
     * Defines an OBB based on the given AABB.
     *
     * @param {Box3} box3 - The AABB to setup the OBB from.
     * @return {OBB} A reference of this OBB.
     */
    fromBox3( box3 ) {

        box3.getCenter( this.center );

        box3.getSize( this.halfSize ).multiplyScalar( 0.5 );

        this.rotation.identity();

        return this;

    }

    /**
     * Returns `true` if the given OBB is equal to this OBB.
     *
     * @param {OBB} obb - The OBB to test.
     * @returns {boolean} Whether the given OBB is equal to this OBB or not.
     */
    equals( obb ) {

        return obb.center.equals( this.center ) &&
            obb.halfSize.equals( this.halfSize ) &&
            obb.rotation.equals( this.rotation );

    }

    /**
     * Applies the given transformation matrix to this OBB. This method can be
     * used to transform the bounding volume with the world matrix of a 3D object
     * in order to keep both entities in sync.
     *
     * @param {Matrix4} matrix - The matrix to apply.
     * @return {OBB} A reference of this OBB.
     */
    applyMatrix4( matrix ) {

        const e = matrix.elements;

        let sx = v1.set( e[ 0 ], e[ 1 ], e[ 2 ] ).length();
        const sy = v1.set( e[ 4 ], e[ 5 ], e[ 6 ] ).length();
        const sz = v1.set( e[ 8 ], e[ 9 ], e[ 10 ] ).length();

        const det = matrix.determinant();
        if ( det < 0 ) sx = - sx;

        rotationMatrix.setFromMatrix4( matrix );

        const invSX = 1 / sx;
        const invSY = 1 / sy;
        const invSZ = 1 / sz;

        rotationMatrix.elements[ 0 ] *= invSX;
        rotationMatrix.elements[ 1 ] *= invSX;
        rotationMatrix.elements[ 2 ] *= invSX;

        rotationMatrix.elements[ 3 ] *= invSY;
        rotationMatrix.elements[ 4 ] *= invSY;
        rotationMatrix.elements[ 5 ] *= invSY;

        rotationMatrix.elements[ 6 ] *= invSZ;
        rotationMatrix.elements[ 7 ] *= invSZ;
        rotationMatrix.elements[ 8 ] *= invSZ;

        this.rotation.multiply( rotationMatrix );

        this.halfSize.x *= sx;
        this.halfSize.y *= sy;
        this.halfSize.z *= sz;

        v1.setFromMatrixPosition( matrix );
        this.center.add( v1 );

        return this;

    }

}

Methods

set(center: Vector3, halfSize: Vector3, rotation: Matrix3): OBB
Code
set( center, halfSize, rotation ) {

        this.center = center;
        this.halfSize = halfSize;
        this.rotation = rotation;

        return this;

    }
copy(obb: OBB): OBB
Code
copy( obb ) {

        this.center.copy( obb.center );
        this.halfSize.copy( obb.halfSize );
        this.rotation.copy( obb.rotation );

        return this;

    }
clone(): OBB
Code
clone() {

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

    }
getSize(target: Vector3): Vector3
Code
getSize( target ) {

        return target.copy( this.halfSize ).multiplyScalar( 2 );

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

        // Reference: Closest Point on OBB to Point in Real-Time Collision Detection
        // by Christer Ericson (chapter 5.1.4)

        const halfSize = this.halfSize;

        v1.subVectors( point, this.center );
        this.rotation.extractBasis( xAxis, yAxis, zAxis );

        // start at the center position of the OBB

        target.copy( this.center );

        // project the target onto the OBB axes and walk towards that point

        const x = MathUtils.clamp( v1.dot( xAxis ), - halfSize.x, halfSize.x );
        target.add( xAxis.multiplyScalar( x ) );

        const y = MathUtils.clamp( v1.dot( yAxis ), - halfSize.y, halfSize.y );
        target.add( yAxis.multiplyScalar( y ) );

        const z = MathUtils.clamp( v1.dot( zAxis ), - halfSize.z, halfSize.z );
        target.add( zAxis.multiplyScalar( z ) );

        return target;

    }
containsPoint(point: Vector3): boolean
Code
containsPoint( point ) {

        v1.subVectors( point, this.center );
        this.rotation.extractBasis( xAxis, yAxis, zAxis );

        // project v1 onto each axis and check if these points lie inside the OBB

        return Math.abs( v1.dot( xAxis ) ) <= this.halfSize.x &&
                Math.abs( v1.dot( yAxis ) ) <= this.halfSize.y &&
                Math.abs( v1.dot( zAxis ) ) <= this.halfSize.z;

    }
intersectsBox3(box3: Box3): boolean
Code
intersectsBox3( box3 ) {

        return this.intersectsOBB( obb.fromBox3( box3 ) );

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

        // find the point on the OBB closest to the sphere center

        this.clampPoint( sphere.center, closestPoint );

        // if that point is inside the sphere, the OBB and sphere intersect

        return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );

    }
intersectsOBB(obb: OBB, epsilon: number): boolean
Code
intersectsOBB( obb, epsilon = Number.EPSILON ) {

        // Reference: OBB-OBB Intersection in Real-Time Collision Detection
        // by Christer Ericson (chapter 4.4.1)

        // prepare data structures (the code uses the same nomenclature like the reference)

        a.c = this.center;
        a.e[ 0 ] = this.halfSize.x;
        a.e[ 1 ] = this.halfSize.y;
        a.e[ 2 ] = this.halfSize.z;
        this.rotation.extractBasis( a.u[ 0 ], a.u[ 1 ], a.u[ 2 ] );

        b.c = obb.center;
        b.e[ 0 ] = obb.halfSize.x;
        b.e[ 1 ] = obb.halfSize.y;
        b.e[ 2 ] = obb.halfSize.z;
        obb.rotation.extractBasis( b.u[ 0 ], b.u[ 1 ], b.u[ 2 ] );

        // compute rotation matrix expressing b in a's coordinate frame

        for ( let i = 0; i < 3; i ++ ) {

            for ( let j = 0; j < 3; j ++ ) {

                R[ i ][ j ] = a.u[ i ].dot( b.u[ j ] );

            }

        }

        // compute translation vector

        v1.subVectors( b.c, a.c );

        // bring translation into a's coordinate frame

        t[ 0 ] = v1.dot( a.u[ 0 ] );
        t[ 1 ] = v1.dot( a.u[ 1 ] );
        t[ 2 ] = v1.dot( a.u[ 2 ] );

        // compute common subexpressions. Add in an epsilon term to
        // counteract arithmetic errors when two edges are parallel and
        // their cross product is (near) null

        for ( let i = 0; i < 3; i ++ ) {

            for ( let j = 0; j < 3; j ++ ) {

                AbsR[ i ][ j ] = Math.abs( R[ i ][ j ] ) + epsilon;

            }

        }

        let ra, rb;

        // test axes L = A0, L = A1, L = A2

        for ( let i = 0; i < 3; i ++ ) {

            ra = a.e[ i ];
            rb = b.e[ 0 ] * AbsR[ i ][ 0 ] + b.e[ 1 ] * AbsR[ i ][ 1 ] + b.e[ 2 ] * AbsR[ i ][ 2 ];
            if ( Math.abs( t[ i ] ) > ra + rb ) return false;


        }

        // test axes L = B0, L = B1, L = B2

        for ( let i = 0; i < 3; i ++ ) {

            ra = a.e[ 0 ] * AbsR[ 0 ][ i ] + a.e[ 1 ] * AbsR[ 1 ][ i ] + a.e[ 2 ] * AbsR[ 2 ][ i ];
            rb = b.e[ i ];
            if ( Math.abs( t[ 0 ] * R[ 0 ][ i ] + t[ 1 ] * R[ 1 ][ i ] + t[ 2 ] * R[ 2 ][ i ] ) > ra + rb ) return false;

        }

        // test axis L = A0 x B0

        ra = a.e[ 1 ] * AbsR[ 2 ][ 0 ] + a.e[ 2 ] * AbsR[ 1 ][ 0 ];
        rb = b.e[ 1 ] * AbsR[ 0 ][ 2 ] + b.e[ 2 ] * AbsR[ 0 ][ 1 ];
        if ( Math.abs( t[ 2 ] * R[ 1 ][ 0 ] - t[ 1 ] * R[ 2 ][ 0 ] ) > ra + rb ) return false;

        // test axis L = A0 x B1

        ra = a.e[ 1 ] * AbsR[ 2 ][ 1 ] + a.e[ 2 ] * AbsR[ 1 ][ 1 ];
        rb = b.e[ 0 ] * AbsR[ 0 ][ 2 ] + b.e[ 2 ] * AbsR[ 0 ][ 0 ];
        if ( Math.abs( t[ 2 ] * R[ 1 ][ 1 ] - t[ 1 ] * R[ 2 ][ 1 ] ) > ra + rb ) return false;

        // test axis L = A0 x B2

        ra = a.e[ 1 ] * AbsR[ 2 ][ 2 ] + a.e[ 2 ] * AbsR[ 1 ][ 2 ];
        rb = b.e[ 0 ] * AbsR[ 0 ][ 1 ] + b.e[ 1 ] * AbsR[ 0 ][ 0 ];
        if ( Math.abs( t[ 2 ] * R[ 1 ][ 2 ] - t[ 1 ] * R[ 2 ][ 2 ] ) > ra + rb ) return false;

        // test axis L = A1 x B0

        ra = a.e[ 0 ] * AbsR[ 2 ][ 0 ] + a.e[ 2 ] * AbsR[ 0 ][ 0 ];
        rb = b.e[ 1 ] * AbsR[ 1 ][ 2 ] + b.e[ 2 ] * AbsR[ 1 ][ 1 ];
        if ( Math.abs( t[ 0 ] * R[ 2 ][ 0 ] - t[ 2 ] * R[ 0 ][ 0 ] ) > ra + rb ) return false;

        // test axis L = A1 x B1

        ra = a.e[ 0 ] * AbsR[ 2 ][ 1 ] + a.e[ 2 ] * AbsR[ 0 ][ 1 ];
        rb = b.e[ 0 ] * AbsR[ 1 ][ 2 ] + b.e[ 2 ] * AbsR[ 1 ][ 0 ];
        if ( Math.abs( t[ 0 ] * R[ 2 ][ 1 ] - t[ 2 ] * R[ 0 ][ 1 ] ) > ra + rb ) return false;

        // test axis L = A1 x B2

        ra = a.e[ 0 ] * AbsR[ 2 ][ 2 ] + a.e[ 2 ] * AbsR[ 0 ][ 2 ];
        rb = b.e[ 0 ] * AbsR[ 1 ][ 1 ] + b.e[ 1 ] * AbsR[ 1 ][ 0 ];
        if ( Math.abs( t[ 0 ] * R[ 2 ][ 2 ] - t[ 2 ] * R[ 0 ][ 2 ] ) > ra + rb ) return false;

        // test axis L = A2 x B0

        ra = a.e[ 0 ] * AbsR[ 1 ][ 0 ] + a.e[ 1 ] * AbsR[ 0 ][ 0 ];
        rb = b.e[ 1 ] * AbsR[ 2 ][ 2 ] + b.e[ 2 ] * AbsR[ 2 ][ 1 ];
        if ( Math.abs( t[ 1 ] * R[ 0 ][ 0 ] - t[ 0 ] * R[ 1 ][ 0 ] ) > ra + rb ) return false;

        // test axis L = A2 x B1

        ra = a.e[ 0 ] * AbsR[ 1 ][ 1 ] + a.e[ 1 ] * AbsR[ 0 ][ 1 ];
        rb = b.e[ 0 ] * AbsR[ 2 ][ 2 ] + b.e[ 2 ] * AbsR[ 2 ][ 0 ];
        if ( Math.abs( t[ 1 ] * R[ 0 ][ 1 ] - t[ 0 ] * R[ 1 ][ 1 ] ) > ra + rb ) return false;

        // test axis L = A2 x B2

        ra = a.e[ 0 ] * AbsR[ 1 ][ 2 ] + a.e[ 1 ] * AbsR[ 0 ][ 2 ];
        rb = b.e[ 0 ] * AbsR[ 2 ][ 1 ] + b.e[ 1 ] * AbsR[ 2 ][ 0 ];
        if ( Math.abs( t[ 1 ] * R[ 0 ][ 2 ] - t[ 0 ] * R[ 1 ][ 2 ] ) > ra + rb ) return false;

        // since no separating axis is found, the OBBs must be intersecting

        return true;

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

        // Reference: Testing Box Against Plane in Real-Time Collision Detection
        // by Christer Ericson (chapter 5.2.3)

        this.rotation.extractBasis( xAxis, yAxis, zAxis );

        // compute the projection interval radius of this OBB onto L(t) = this->center + t * p.normal;

        const r = this.halfSize.x * Math.abs( plane.normal.dot( xAxis ) ) +
                this.halfSize.y * Math.abs( plane.normal.dot( yAxis ) ) +
                this.halfSize.z * Math.abs( plane.normal.dot( zAxis ) );

        // compute distance of the OBB's center from the plane

        const d = plane.normal.dot( this.center ) - plane.constant;

        // Intersection occurs when distance d falls within [-r,+r] interval

        return Math.abs( d ) <= r;

    }
intersectRay(ray: Ray, target: Vector3): Vector3
Code
intersectRay( ray, target ) {

        // the idea is to perform the intersection test in the local space
        // of the OBB.

        this.getSize( size );
        aabb.setFromCenterAndSize( v1.set( 0, 0, 0 ), size );

        // create a 4x4 transformation matrix

        matrix.setFromMatrix3( this.rotation );
        matrix.setPosition( this.center );

        // transform ray to the local space of the OBB

        inverse.copy( matrix ).invert();
        localRay.copy( ray ).applyMatrix4( inverse );

        // perform ray <-> AABB intersection test

        if ( localRay.intersectBox( aabb, target ) ) {

            // transform the intersection point back to world space

            return target.applyMatrix4( matrix );

        } else {

            return null;

        }

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

        return this.intersectRay( ray, v1 ) !== null;

    }
fromBox3(box3: Box3): OBB
Code
fromBox3( box3 ) {

        box3.getCenter( this.center );

        box3.getSize( this.halfSize ).multiplyScalar( 0.5 );

        this.rotation.identity();

        return this;

    }
equals(obb: OBB): boolean
Code
equals( obb ) {

        return obb.center.equals( this.center ) &&
            obb.halfSize.equals( this.halfSize ) &&
            obb.rotation.equals( this.rotation );

    }
applyMatrix4(matrix: Matrix4): OBB
Code
applyMatrix4( matrix ) {

        const e = matrix.elements;

        let sx = v1.set( e[ 0 ], e[ 1 ], e[ 2 ] ).length();
        const sy = v1.set( e[ 4 ], e[ 5 ], e[ 6 ] ).length();
        const sz = v1.set( e[ 8 ], e[ 9 ], e[ 10 ] ).length();

        const det = matrix.determinant();
        if ( det < 0 ) sx = - sx;

        rotationMatrix.setFromMatrix4( matrix );

        const invSX = 1 / sx;
        const invSY = 1 / sy;
        const invSZ = 1 / sz;

        rotationMatrix.elements[ 0 ] *= invSX;
        rotationMatrix.elements[ 1 ] *= invSX;
        rotationMatrix.elements[ 2 ] *= invSX;

        rotationMatrix.elements[ 3 ] *= invSY;
        rotationMatrix.elements[ 4 ] *= invSY;
        rotationMatrix.elements[ 5 ] *= invSY;

        rotationMatrix.elements[ 6 ] *= invSZ;
        rotationMatrix.elements[ 7 ] *= invSZ;
        rotationMatrix.elements[ 8 ] *= invSZ;

        this.rotation.multiply( rotationMatrix );

        this.halfSize.x *= sx;
        this.halfSize.y *= sy;
        this.halfSize.z *= sz;

        v1.setFromMatrixPosition( matrix );
        this.center.add( v1 );

        return this;

    }