feat: initialize project with core dependencies and game entry point
This commit is contained in:
535
node_modules/three/examples/jsm/math/OBB.js
generated
vendored
Normal file
535
node_modules/three/examples/jsm/math/OBB.js
generated
vendored
Normal file
@@ -0,0 +1,535 @@
|
||||
import {
|
||||
Box3,
|
||||
MathUtils,
|
||||
Matrix4,
|
||||
Matrix3,
|
||||
Ray,
|
||||
Vector3
|
||||
} from 'three';
|
||||
|
||||
// module scope helper variables
|
||||
|
||||
const 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();
|
||||
|
||||
/**
|
||||
* Represents an oriented bounding box (OBB) in 3D space.
|
||||
*
|
||||
* @three_import import { OBB } from 'three/addons/math/OBB.js';
|
||||
*/
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const obb = new OBB();
|
||||
|
||||
export { OBB };
|
||||
Reference in New Issue
Block a user