Browse Source

Octree: Add `Box3` interface. (#32343)

Michael Herzog 3 months ago
parent
commit
acc03cc90c
1 changed files with 131 additions and 1 deletions
  1. 131 1
      examples/jsm/math/Octree.js

+ 131 - 1
examples/jsm/math/Octree.js

@@ -17,8 +17,10 @@ const _point2 = new Vector3();
 const _plane = new Plane();
 const _line1 = new Line3();
 const _line2 = new Line3();
+const _box = new Box3();
 const _sphere = new Sphere();
 const _capsule = new Capsule();
+const _center = new Capsule();
 
 const _temp1 = new Vector3();
 const _temp2 = new Vector3();
@@ -373,6 +375,61 @@ class Octree {
 
 	}
 
+	/**
+	 * Computes the intersection between the given bounding box and triangle.
+	 *
+	 * @param {Box3} box - The bounding box to test.
+	 * @param {Triangle} triangle - The triangle to test.
+	 * @return {Object|false} The intersection object. If no intersection
+	 * is detected, the method returns `false`.
+	 */
+	triangleBoxIntersect( box, triangle ) {
+
+		// cheap check
+
+		if ( Math.max( triangle.a.x, triangle.b.x, triangle.c.x ) < box.min.x ||
+				Math.min( triangle.a.x, triangle.b.x, triangle.c.x ) > box.max.x ||
+				Math.max( triangle.a.y, triangle.b.y, triangle.c.y ) < box.min.y ||
+				Math.min( triangle.a.y, triangle.b.y, triangle.c.y ) > box.max.y ||
+				Math.max( triangle.a.z, triangle.b.z, triangle.c.z ) < box.min.z ||
+				Math.min( triangle.a.z, triangle.b.z, triangle.c.z ) > box.max.z ) {
+
+			return false;
+
+		}
+
+		// expensive check
+
+		if ( ! box.intersectsTriangle( triangle ) ) return false;
+
+		// there is an intersection, now compute collision data
+
+		triangle.getPlane( _plane );
+
+		// determine which corner of the box is "deepest" into the plane
+
+		_v1.x = ( _plane.normal.x > 0 ) ? box.min.x : box.max.x;
+		_v1.y = ( _plane.normal.y > 0 ) ? box.min.y : box.max.y;
+		_v1.z = ( _plane.normal.z > 0 ) ? box.min.z : box.max.z;
+
+		// Calculate the distance from the plane to that corner (the distance will be negative
+		// because of the intersection)
+
+		const distance = _plane.distanceToPoint( _v1 );
+
+		const intersection = {
+			depth: - distance, // Flip sign so depth is positive
+			normal: _plane.normal.clone(),
+			point: _v1.clone()
+		};
+
+		// project the point onto the triangle surface
+		intersection.point.addScaledVector( intersection.normal, distance );
+
+		return intersection;
+
+	}
+
 	/**
 	 * Computes the intersection between the given sphere and triangle.
 	 *
@@ -455,6 +512,38 @@ class Octree {
 
 	}
 
+	/**
+	 * Computes the triangles that potentially intersect with the given bounding box.
+	 *
+	 * @param {Box3} box - The bounding box.
+	 * @param {Array<Triangle>} triangles - The target array that holds the triangles.
+	 */
+	getBoxTriangles( box, triangles ) {
+
+		for ( let i = 0; i < this.subTrees.length; i ++ ) {
+
+			const subTree = this.subTrees[ i ];
+
+			if ( ! box.intersectsBox( subTree.box ) ) continue;
+
+			if ( subTree.triangles.length > 0 ) {
+
+				for ( let j = 0; j < subTree.triangles.length; j ++ ) {
+
+					if ( triangles.indexOf( subTree.triangles[ j ] ) === - 1 ) triangles.push( subTree.triangles[ j ] );
+
+				}
+
+			} else {
+
+				subTree.getBoxTriangles( box, triangles );
+
+			}
+
+		}
+
+	}
+
 	/**
 	 * Computes the triangles that potentially intersect with the given capsule.
 	 *
@@ -487,6 +576,47 @@ class Octree {
 
 	}
 
+	/**
+	 * Performs a bounding box intersection test with this Octree.
+	 *
+	 * @param {Box3} box - The bounding box to test.
+	 * @return {Object|boolean} The intersection object. If no intersection
+	 * is detected, the method returns `false`.
+	 */
+	boxIntersect( box ) {
+
+		_box.copy( box );
+
+		const triangles = [];
+		let result, hit = false;
+
+		this.getBoxTriangles( box, triangles );
+
+		for ( let i = 0; i < triangles.length; i ++ ) {
+
+			if ( result = this.triangleBoxIntersect( _box, triangles[ i ] ) ) {
+
+				hit = true;
+
+				_box.translate( result.normal.multiplyScalar( result.depth ) );
+
+			}
+
+		}
+
+		if ( hit ) {
+
+			const collisionVector = _box.getCenter( _center ).sub( box.getCenter( _v1 ) );
+			const depth = collisionVector.length();
+
+			return { normal: collisionVector.normalize(), depth: depth };
+
+		}
+
+		return false;
+
+	}
+
 	/**
 	 * Performs a bounding sphere intersection test with this Octree.
 	 *
@@ -558,7 +688,7 @@ class Octree {
 
 		if ( hit ) {
 
-			const collisionVector = _capsule.getCenter( new Vector3() ).sub( capsule.getCenter( _v1 ) );
+			const collisionVector = _capsule.getCenter( _center ).sub( capsule.getCenter( _v1 ) );
 			const depth = collisionVector.length();
 
 			return { normal: collisionVector.normalize(), depth: depth };

粤ICP备19079148号