| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 | import {	Box3,	MathUtils,	Matrix4,	Matrix3,	Ray,	Vector3} from '../../../build/three.module.js';// module scope helper variablesconst a = {	c: null, // center	u: [ new Vector3(), new Vector3(), new Vector3() ], // basis vectors	e: [] // half width};const b = {	c: null, // center	u: [ new Vector3(), new Vector3(), new Vector3() ], // basis vectors	e: [] // half width};const R = [[], [], []];const AbsR = [[], [], []];const t = [];const xAxis = new Vector3();const yAxis = new Vector3();const zAxis = new Vector3();const v1 = new Vector3();const size = new Vector3();const closestPoint = new Vector3();const rotationMatrix = new Matrix3();const aabb = new Box3();const matrix = new Matrix4();const inverse = new Matrix4();const localRay = new Ray();// OBBclass OBB {	constructor( center = new Vector3(), halfSize = new Vector3(), rotation = new Matrix3() ) {		this.center = center;		this.halfSize = halfSize;		this.rotation = rotation;	}	set( center, halfSize, rotation ) {		this.center = center;		this.halfSize = halfSize;		this.rotation = rotation;		return this;	}	copy( obb ) {		this.center.copy( obb.center );		this.halfSize.copy( obb.halfSize );		this.rotation.copy( obb.rotation );		return this;	}	clone() {		return new this.constructor().copy( this );	}	getSize( result ) {		return result.copy( this.halfSize ).multiplyScalar( 2 );	}	/**	* Reference: Closest Point on OBB to Point in Real-Time Collision Detection	* by Christer Ericson (chapter 5.1.4)	*/	clampPoint( point, result ) {		const halfSize = this.halfSize;		v1.subVectors( point, this.center );		this.rotation.extractBasis( xAxis, yAxis, zAxis );		// start at the center position of the OBB		result.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 );		result.add( xAxis.multiplyScalar( x ) );		const y = MathUtils.clamp( v1.dot( yAxis ), - halfSize.y, halfSize.y );		result.add( yAxis.multiplyScalar( y ) );		const z = MathUtils.clamp( v1.dot( zAxis ), - halfSize.z, halfSize.z );		result.add( zAxis.multiplyScalar( z ) );		return result;	}	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 ) {		return this.intersectsOBB( obb.fromBox3( box3 ) );	}	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 );	}	/**	* Reference: OBB-OBB Intersection in Real-Time Collision Detection	* by Christer Ericson (chapter 4.4.1)	*	*/	intersectsOBB( obb, epsilon = Number.EPSILON ) {		// 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;	}	/**	* Reference: Testing Box Against Plane in Real-Time Collision Detection	* by Christer Ericson (chapter 5.2.3)	*/	intersectsPlane( plane ) {		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	* to the given 3D vector. If no intersection is detected, *null* is returned.	*/	intersectRay( ray, result ) {		// 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, result ) ) {			// transform the intersection point back to world space			return result.applyMatrix4( matrix );		} else {			return null;		}	}	/**	* Performs a ray/OBB intersection test. Returns either true or false if	* there is a intersection or not.	*/	intersectsRay( ray ) {		return this.intersectRay( ray, v1 ) !== null;	}	fromBox3( box3 ) {		box3.getCenter( this.center );		box3.getSize( this.halfSize ).multiplyScalar( 0.5 );		this.rotation.identity();		return this;	}	equals( obb ) {		return obb.center.equals( this.center ) &&			obb.halfSize.equals( this.halfSize ) &&			obb.rotation.equals( this.rotation );	}	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;	}}const obb = new OBB();export { OBB };
 |