Browse Source

Raycaster checks for bounding box intersection

jotinha 12 years ago
parent
commit
a518807e49
3 changed files with 131 additions and 8 deletions
  1. 15 8
      src/core/Raycaster.js
  2. 77 0
      src/math/Ray.js
  3. 39 0
      test/unit/math/Ray.js

+ 15 - 8
src/core/Raycaster.js

@@ -76,6 +76,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;
 			var vertices = geometry.vertices;
 
 
 			if ( geometry instanceof THREE.BufferGeometry ) {
 			if ( geometry instanceof THREE.BufferGeometry ) {
@@ -88,10 +103,6 @@
 				var a, b, c;
 				var a, b, c;
 				var precision = raycaster.precision;
 				var precision = raycaster.precision;
 
 
-				inverseMatrix.getInverse( object.matrixWorld );
-
-				localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
-
 				var fl;
 				var fl;
 				var indexed = false;
 				var indexed = false;
 
 
@@ -186,10 +197,6 @@
 				var a, b, c, d;
 				var a, b, c, d;
 				var precision = raycaster.precision;
 				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 ++ ) {
 				for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
 
 
 					var face = geometry.faces[ f ];
 					var face = geometry.faces[ f ];

+ 77 - 0
src/math/Ray.js

@@ -282,6 +282,83 @@ 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;
+
+		if (tymin > tmin || isNaN(tmin) ) tmin = tymin;
+
+		if (tymax < tmax || isNaN(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 || isNaN(tmin) ) tmin = tzmin;
+
+		if (tzmax < tmax || isNaN(tmax) ) tmax = tzmax;
+
+		//return point closest to the ray (positive side)
+
+		if ( tmax < 0 ) return null;
+
+		return this.at( tmin >= 0 ? tmin : tmax, optionalTarget );
+
+	},
+
 	applyMatrix4: function ( matrix4 ) {
 	applyMatrix4: function ( matrix4 ) {
 
 
 		this.direction.add( this.origin ).applyMatrix4( matrix4 );
 		this.direction.add( this.origin ).applyMatrix4( matrix4 );

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

@@ -217,3 +217,42 @@ test( "distanceSqToSegment", function() {
 	ok( distSqr < 0.0001, "Passed!" );
 	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 coplar 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 coplar with one of the boxes side - box behind ray
+	ok( f.isIntersectionBox(box) === false, "Passed!" );
+	ok( f.intersectBox(box) == null, "Passed!" );		
+	
+});
+
+