Pārlūkot izejas kodu

Merge @jotinha/dev-raycaster-aabb-2.

Mr.doob 12 gadi atpakaļ
vecāks
revīzija
2e7e660c2a
4 mainītis faili ar 200 papildinājumiem un 79 dzēšanām
  1. 17 10
      src/core/Raycaster.js
  2. 144 0
      src/math/Ray.js
  3. 0 69
      src/math/Triangle.js
  4. 39 0
      test/unit/math/Ray.js

+ 17 - 10
src/core/Raycaster.js

@@ -80,6 +80,21 @@
 
 			}
 
+			//Check boundingBox before continuing
+			
+			inverseMatrix.getInverse( object.matrixWorld );  
+			localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
+
+			if ( geometry.boundingBox !== null) {
+
+				if ( localRay.isIntersectionBox(geometry.boundingBox) === false )  {
+
+					return intersects;
+
+				}
+
+			} 
+
 			var vertices = geometry.vertices;
 
 			if ( geometry instanceof THREE.BufferGeometry ) {
@@ -92,10 +107,6 @@
 				var a, b, c;
 				var precision = raycaster.precision;
 
-				inverseMatrix.getInverse( object.matrixWorld );
-
-				localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
-
 				var fl;
 				var indexed = false;
 
@@ -153,7 +164,7 @@
 							positions[ c * 3 + 2 ]
 						);
 
-						var interPoint = THREE.Triangle.intersectionRay( localRay, vA, vB, vC, material.side !== THREE.DoubleSide );
+						var interPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );
 
 						if ( !interPoint ) continue;
 
@@ -186,10 +197,6 @@
 				var a, b, c, d;
 				var precision = raycaster.precision;
 
-				inverseMatrix.getInverse( object.matrixWorld );
-
-				localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
-
 				for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
 
 					var face = geometry.faces[ f ];
@@ -202,7 +209,7 @@
 					b = vertices[ face.b ];
 					c = vertices[ face.c ];
 					
-					var interPoint = THREE.Triangle.intersectionRay( localRay, a, b, c, material.side !== THREE.DoubleSide );
+					var interPoint = localRay.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide );
 
 					if ( !interPoint ) {
 

+ 144 - 0
src/math/Ray.js

@@ -282,6 +282,150 @@ THREE.Ray.prototype = {
 
 	},
 
+	isIntersectionBox: function () {
+		
+		var v = new THREE.Vector3();
+
+		return function ( box ) {
+
+			return this.intersectBox( box, v ) !== null;
+
+		}
+
+	}(),
+
+	intersectBox: function ( box , optionalTarget ) {
+
+		// http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/
+
+		var tmin,tmax,tymin,tymax,tzmin,tzmax;
+
+		var invdirx = 1/this.direction.x,
+			invdiry = 1/this.direction.y,
+			invdirz = 1/this.direction.z;
+
+		var origin = this.origin;
+
+		if (invdirx >= 0) {
+				
+			tmin = (box.min.x - origin.x) * invdirx;
+			tmax = (box.max.x - origin.x) * invdirx;
+
+		} else { 
+
+			tmin = (box.max.x - origin.x) * invdirx;
+			tmax = (box.min.x - origin.x) * invdirx;
+		}			
+
+		if (invdiry >= 0) {
+		
+			tymin = (box.min.y - origin.y) * invdiry;
+			tymax = (box.max.y - origin.y) * invdiry;
+
+		} else {
+
+			tymin = (box.max.y - origin.y) * invdiry;
+			tymax = (box.min.y - origin.y) * invdiry;
+		}
+
+		if ((tmin > tymax) || (tymin > tmax)) return null;
+
+		// These lines also handle the case where tmin or tmax is NaN
+		// (result of 0 * Infinity). x !== x returns true if x is NaN
+		
+		if (tymin > tmin || tmin !== tmin ) tmin = tymin;
+
+		if (tymax < tmax || tmax !== tmax ) tmax = tymax;
+
+		if (invdirz >= 0) {
+		
+			tzmin = (box.min.z - origin.z) * invdirz;
+			tzmax = (box.max.z - origin.z) * invdirz;
+
+		} else {
+
+			tzmin = (box.max.z - origin.z) * invdirz;
+			tzmax = (box.min.z - origin.z) * invdirz;
+		}
+
+		if ((tmin > tzmax) || (tzmin > tmax)) return null;
+
+		if (tzmin > tmin || tmin !== tmin ) tmin = tzmin;
+
+		if (tzmax < tmax || tmax !== tmax ) tmax = tzmax;
+
+		//return point closest to the ray (positive side)
+
+		if ( tmax < 0 ) return null;
+
+		return this.at( tmin >= 0 ? tmin : tmax, optionalTarget );
+
+	},
+
+	intersectTriangle: function() {
+
+		// Compute the offset origin, edges, and normal.
+		var diff = new THREE.Vector3();
+		var edge1 = new THREE.Vector3();
+		var edge2 = new THREE.Vector3();
+		var normal = new THREE.Vector3();
+
+		return function ( a, b, c, backfaceCulling, optionalTarget ) {
+
+			//from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp
+
+			edge1.subVectors( b, a );
+			edge2.subVectors( c, a );
+			normal.crossVectors( edge1, edge2 );
+
+			// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
+			// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
+			//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
+			//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
+			//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
+			var DdN = this.direction.dot(normal);
+			var sign;
+			if ( DdN > 0 ) {
+
+					if ( backfaceCulling ) return null;
+					sign = 1;
+
+			} else if ( DdN < 0 ) {
+
+					sign = - 1;
+					DdN = - DdN;
+
+			} else return null;
+
+			diff.subVectors( this.origin, a );
+			var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );
+
+			// b1 < 0, no intersection
+			if ( DdQxE2 < 0 )
+				return null;
+
+			var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );
+			// b2 < 0, no intersection
+			if ( DdE1xQ < 0 )
+				return null;
+
+			// b1+b2 > 1, no intersection
+			if ( DdQxE2 + DdE1xQ > DdN )
+				return null
+
+			// Line intersects triangle, check if ray does.
+			var QdN = - sign * diff.dot( normal );
+			// t < 0, no intersection
+			if ( QdN < 0 )
+				return null
+
+			// Ray intersects triangle.
+			return this.at( QdN / DdN, optionalTarget );
+	
+		}
+	
+	}(),
+
 	applyMatrix4: function ( matrix4 ) {
 
 		this.direction.add( this.origin ).applyMatrix4( matrix4 );

+ 0 - 69
src/math/Triangle.js

@@ -92,69 +92,6 @@ THREE.Triangle.containsPoint = function() {
 
 }();
 
-THREE.Triangle.intersectionRay = function ()	{
-
-	// Compute the offset origin, edges, and normal.
-	var diff = new THREE.Vector3();
-	var edge1 = new THREE.Vector3();
-	var edge2 = new THREE.Vector3();
-	var normal = new THREE.Vector3();
-
-	return function ( ray, a, b, c, backfaceCulling ) {
-
-		//from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp
-
-		edge1.subVectors( b, a );
-		edge2.subVectors( c, a );
-		normal.crossVectors( edge1, edge2 );
-
-		// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
-		// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
-		//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
-		//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
-		//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
-		var DdN = ray.direction.dot(normal);
-		var sign;
-		if ( DdN > 0 ) {
-
-				if ( backfaceCulling ) return null;
-				sign = 1;
-
-		} else if ( DdN < 0 ) {
-
-				sign = - 1;
-				DdN = - DdN;
-
-		} else return null;
-
-		diff.subVectors( ray.origin, a );
-		var DdQxE2 = sign * ray.direction.dot( edge2.crossVectors( diff, edge2 ) );
-
-		// b1 < 0, no intersection
-		if ( DdQxE2 < 0 )
-			return null;
-
-		var DdE1xQ = sign * ray.direction.dot( edge1.cross( diff ) );
-		// b2 < 0, no intersection
-		if ( DdE1xQ < 0 )
-			return null;
-
-		// b1+b2 > 1, no intersection
-		if ( DdQxE2 + DdE1xQ > DdN )
-			return null
-
-		// Line intersects triangle, check if ray does.
-		var QdN = - sign * diff.dot( normal );
-		// t < 0, no intersection
-		if ( QdN < 0 )
-			return null
-
-		// Ray intersects triangle.
-		return ray.at( QdN / DdN );
-	}
-
-}();
-
 THREE.Triangle.prototype = {
 
 	constructor: THREE.Triangle,
@@ -238,12 +175,6 @@ THREE.Triangle.prototype = {
 
 	},
 
-	intersectionRay: function ( ray, backfaceCulling ) {
-
-		return THREE.Triangle.intersectionRay( ray, this.a, this.b, this.c, backfaceCulling );
-
-	},
-
 	equals: function ( triangle ) {
 
 		return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );

+ 39 - 0
test/unit/math/Ray.js

@@ -217,3 +217,42 @@ test( "distanceSqToSegment", function() {
 	ok( distSqr < 0.0001, "Passed!" );
 });
 
+test( "intersectBox", function() {
+
+	var TOL = 0.0001;
+	
+	var box = new THREE.Box3( new THREE.Vector3(  -1, -1, -1 ), new THREE.Vector3( 1, 1, 1 ) );
+
+	var a = new THREE.Ray( new THREE.Vector3( -2, 0, 0 ), new THREE.Vector3( 1, 0, 0) );
+	//ray should intersect box at -1,0,0
+	ok( a.isIntersectionBox(box) === true, "Passed!" );
+	ok( a.intersectBox(box).distanceTo( new THREE.Vector3( -1, 0, 0 ) ) < TOL, "Passed!" );
+
+	var b = new THREE.Ray( new THREE.Vector3( -2, 0, 0 ), new THREE.Vector3( -1, 0, 0) );
+	//ray is point away from box, it should not intersect
+	ok( b.isIntersectionBox(box) === false, "Passed!" );
+	ok( b.intersectBox(box) === null, "Passed!" );
+
+	var c = new THREE.Ray( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0) );
+	// ray is inside box, should return exit point
+	ok( c.isIntersectionBox(box) === true, "Passed!" );
+	ok( c.intersectBox(box).distanceTo( new THREE.Vector3( 1, 0, 0 ) ) < TOL, "Passed!" );
+
+	var d = new THREE.Ray( new THREE.Vector3( 0, 2, 1 ), new THREE.Vector3( 0, -1, -1).normalize() );
+	//tilted ray should intersect box at 0,1,0
+	ok( d.isIntersectionBox(box) === true, "Passed!" );
+	ok( d.intersectBox(box).distanceTo( new THREE.Vector3( 0, 1, 0 ) ) < TOL, "Passed!" );	
+
+	var e = new THREE.Ray( new THREE.Vector3( 1, -2, 1 ), new THREE.Vector3( 0, 1, 0).normalize() );
+	//handle case where ray is coplanar with one of the boxes side - box in front of ray
+	ok( e.isIntersectionBox(box) === true, "Passed!" );
+	ok( e.intersectBox(box).distanceTo( new THREE.Vector3( 1, -1, 1 ) ) < TOL, "Passed!" );	
+	
+	var f = new THREE.Ray( new THREE.Vector3( 1, -2, 0 ), new THREE.Vector3( 0, -1, 0).normalize() );
+	//handle case where ray is coplanar with one of the boxes side - box behind ray
+	ok( f.isIntersectionBox(box) === false, "Passed!" );
+	ok( f.intersectBox(box) == null, "Passed!" );		
+	
+});
+
+