Browse Source

Merge pull request #13079 from matthias-w/feature/box-intersects-triangle

Box3: new method intersectsTriangle
Mr.doob 7 years ago
parent
commit
789efa65ba

+ 7 - 0
docs/api/math/Box3.html

@@ -209,6 +209,13 @@
 		Determines whether or not this box intersects [page:Sphere sphere].
 		</div>
 
+		<h3>[method:Boolean intersectsTriangle]( [page:Triangle triangle] )</h3>
+		<div>
+		[page:Triangle triangle] - [page:Triangle] to check for intersection against.<br /><br />
+
+		Determines whether or not this box intersects [page:Triangle triangle].
+		</div>
+
 		<h3>[method:Boolean isEmpty]()</h3>
 		<div>
 		Returns true if this box includes zero points within its bounds.<br>

+ 7 - 0
docs/api/math/Triangle.html

@@ -93,6 +93,13 @@
 		Returns true if the two triangles have identical [page:.a a], [page:.b b] and [page:.c c] properties.
 		</div>
 
+		<h3>[method:Boolean intersectsBox]( [page:Box3 box] )</h3>
+		<div>
+		[page:Box3 box] - Box to check for intersection against.<br /><br />
+
+		Determines whether or not this triangle intersects [page:Box3 box].
+		</div>
+
 		<h3>[method:Vector3 midpoint]( [page:Vector3 optionalTarget] )</h3>
 		<div>
 			[page:Vector3 optionalTarget] - (optional) if specified, the result will be copied into this [page:Vector3], otherwise a new [page:Vector3] will be created.<br /><br />

+ 101 - 0
src/math/Box3.js

@@ -371,6 +371,107 @@ Object.assign( Box3.prototype, {
 
 	},
 
+	intersectsTriangle: ( function () {
+
+		// triangle centered vertices
+		var v0 = new Vector3();
+		var v1 = new Vector3();
+		var v2 = new Vector3();
+
+		// triangle edge vectors
+		var f0 = new Vector3();
+		var f1 = new Vector3();
+		var f2 = new Vector3();
+
+		var testAxis = new Vector3();
+
+		var center = new Vector3();
+		var extents = new Vector3();
+
+		var triangleNormal = new Vector3();
+
+		function satForAxes( axes ) {
+
+			var i, j;
+
+			for ( i = 0, j = axes.length - 3; i <= j; i += 3 ) {
+
+				testAxis.fromArray( axes, i );
+				// project the aabb onto the seperating axis
+				var r = extents.x * Math.abs( testAxis.x ) + extents.y * Math.abs( testAxis.y ) + extents.z * Math.abs( testAxis.z );
+				// project all 3 vertices of the triangle onto the seperating axis
+				var p0 = v0.dot( testAxis );
+				var p1 = v1.dot( testAxis );
+				var p2 = v2.dot( testAxis );
+				// actual test, basically see if either of the most extreme of the triangle points intersects r
+				if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
+
+					// points of the projected triangle are outside the projected half-length of the aabb
+					// the axis is seperating and we can exit
+					return false;
+
+				}
+
+			}
+
+			return true;
+
+		}
+
+		return function intersectsTriangle( triangle ) {
+
+			if ( this.isEmpty() ) {
+
+				return false;
+
+			}
+
+			// compute box center and extents
+			this.getCenter( center );
+			extents.subVectors( this.max, center );
+
+			// translate triangle to aabb origin
+			v0.subVectors( triangle.a, center );
+			v1.subVectors( triangle.b, center );
+			v2.subVectors( triangle.c, center );
+
+			// compute edge vectors for triangle
+			f0.subVectors( v1, v0 );
+			f1.subVectors( v2, v1 );
+			f2.subVectors( v0, v2 );
+
+			// test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
+			// make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
+			// axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
+			var axes = [
+				0, - f0.z, f0.y, 0, - f1.z, f1.y, 0, - f2.z, f2.y,
+				f0.z, 0, - f0.x, f1.z, 0, - f1.x, f2.z, 0, - f2.x,
+				- f0.y, f0.x, 0, - f1.y, f1.x, 0, - f2.y, f2.x, 0
+			];
+			if ( ! satForAxes( axes ) ) {
+
+				return false;
+
+			}
+
+			// test 3 face normals from the aabb
+			axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
+			if ( ! satForAxes( axes ) ) {
+
+				return false;
+
+			}
+
+			// finally testing the face normal of the triangle
+			// use already existing triangle edge vectors here
+			triangleNormal.crossVectors( f0, f1 );
+			axes = [ triangleNormal.x, triangleNormal.y, triangleNormal.z ];
+			return satForAxes( axes );
+
+		};
+
+	} )(),
+
 	clampPoint: function ( point, optionalTarget ) {
 
 		var result = optionalTarget || new Vector3();

+ 6 - 0
src/math/Triangle.js

@@ -189,6 +189,12 @@ Object.assign( Triangle.prototype, {
 
 	},
 
+	intersectsBox: function ( box ) {
+
+		return box.intersectsTriangle( this );
+
+	},
+
 	closestPointToPoint: function () {
 
 		var plane = new Plane();

+ 18 - 0
test/unit/src/math/Box3.tests.js

@@ -6,6 +6,7 @@
 
 import { Box3 } from '../../../../src/math/Box3';
 import { Sphere } from '../../../../src/math/Sphere';
+import { Triangle } from '../../../../src/math/Triangle';
 import { Plane } from '../../../../src/math/Plane';
 import { Vector3 } from '../../../../src/math/Vector3';
 import { Matrix4 } from '../../../../src/math/Matrix4';
@@ -390,6 +391,23 @@ export default QUnit.module( 'Maths', () => {
 
 		} );
 
+		QUnit.test( "intersectsTriangle", ( assert ) => {
+
+			var a = new Box3( one3.clone(), two3.clone() );
+			var b = new Triangle( new Vector3( 1.5, 1.5, 2.5 ), new Vector3( 2.5, 1.5, 1.5 ), new Vector3( 1.5, 2.5, 1.5 ) );
+			var c = new Triangle( new Vector3( 1.5, 1.5, 3.5 ), new Vector3( 3.5, 1.5, 1.5 ), new Vector3( 1.5, 1.5, 1.5 ) );
+			var d = new Triangle( new Vector3( 1.5, 1.75, 3 ), new Vector3( 3, 1.75, 1.5 ), new Vector3( 1.5, 2.5, 1.5 ) );
+			var e = new Triangle( new Vector3( 1.5, 1.8, 3 ), new Vector3( 3, 1.8, 1.5 ), new Vector3( 1.5, 2.5, 1.5 ) );
+			var f = new Triangle( new Vector3( 1.5, 2.5, 3 ), new Vector3( 3, 2.5, 1.5 ), new Vector3( 1.5, 2.5, 1.5 ) );
+
+			assert.ok( a.intersectsTriangle( b ), "Passed!" );
+			assert.ok( a.intersectsTriangle( c ), "Passed!" );
+			assert.ok( a.intersectsTriangle( d ), "Passed!" );
+			assert.ok( ! a.intersectsTriangle( e ), "Passed!" );
+			assert.ok( ! a.intersectsTriangle( f ), "Passed!" );
+
+		} );
+
 		QUnit.test( "clampPoint", ( assert ) => {
 
 			var a = new Box3( zero3.clone(), zero3.clone() );

+ 18 - 0
test/unit/src/math/Triangle.tests.js

@@ -5,6 +5,7 @@
 /* global QUnit */
 
 import { Triangle } from '../../../../src/math/Triangle';
+import { Box3 } from '../../../../src/math/Box3';
 import { Vector3 } from '../../../../src/math/Vector3';
 import {
 	zero3,
@@ -219,6 +220,23 @@ export default QUnit.module( 'Maths', () => {
 
 		} );
 
+		QUnit.test( "intersectsBox", ( assert ) => {
+
+			var a = new Box3( one3.clone(), two3.clone() );
+			var b = new Triangle( new Vector3( 1.5, 1.5, 2.5 ), new Vector3( 2.5, 1.5, 1.5 ), new Vector3( 1.5, 2.5, 1.5 ) );
+			var c = new Triangle( new Vector3( 1.5, 1.5, 3.5 ), new Vector3( 3.5, 1.5, 1.5 ), new Vector3( 1.5, 1.5, 1.5 ) );
+			var d = new Triangle( new Vector3( 1.5, 1.75, 3 ), new Vector3( 3, 1.75, 1.5 ), new Vector3( 1.5, 2.5, 1.5 ) );
+			var e = new Triangle( new Vector3( 1.5, 1.8, 3 ), new Vector3( 3, 1.8, 1.5 ), new Vector3( 1.5, 2.5, 1.5 ) );
+			var f = new Triangle( new Vector3( 1.5, 2.5, 3 ), new Vector3( 3, 2.5, 1.5 ), new Vector3( 1.5, 2.5, 1.5 ) );
+
+			assert.ok( b.intersectsBox( a ), "Passed!" );
+			assert.ok( c.intersectsBox( a ), "Passed!" );
+			assert.ok( d.intersectsBox( a ), "Passed!" );
+			assert.ok( ! e.intersectsBox( a ), "Passed!" );
+			assert.ok( ! f.intersectsBox( a ), "Passed!" );
+
+		} );
+
 		QUnit.test( "closestPointToPoint", ( assert ) => {
 
 			var a = new Triangle( new Vector3( - 1, 0, 0 ), new Vector3( 1, 0, 0 ), new Vector3( 0, 1, 0 ) );