Browse Source

Fixed raycasting with BufferGeometry

Raycasts now take BufferGeometry offsets into account.
Added a safeguard to check for the existence of color before adding them
to the intersected face.
Made a minor optimizations by moving a precondition out of the loop.
michael 12 years ago
parent
commit
bc6b55f5f3
1 changed files with 71 additions and 60 deletions
  1. 71 60
      src/core/Raycaster.js

+ 71 - 60
src/core/Raycaster.js

@@ -81,6 +81,11 @@
 
 			if ( geometry instanceof THREE.BufferGeometry ) {
 
+				var material = object.material;
+
+				if (material === undefined) return intersects;
+				if (!geometry.dynamic) return intersects;
+
 				var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
 				var objectMaterials = isFaceMaterial === true ? object.material.materials : null;
 
@@ -93,8 +98,6 @@
 
 				localRay.copy(raycaster.ray).applyMatrix4(inverseMatrix);
 
-				if (!geometry.dynamic) return intersects;
-
 				var fl;
 				var indexed = false;
 				if (geometry.attributes.index) {
@@ -104,81 +107,89 @@
 					fl = geometry.attributes.position.numItems / 9;
 				}
 
-				for (var f = 0; f < fl; f++) {
+				for ( var oi = 0; oi < geometry.offsets.length; ++oi ) {
 
-					if (indexed) {
-						a = geometry.attributes.index.array[f * 3];
-						b = geometry.attributes.index.array[f * 3 + 1];
-						c = geometry.attributes.index.array[f * 3 + 2];
-					} else {
-						a = f * 3;
-						b = f * 3 + 1;
-						c = f * 3 + 2;
-					}
+					var start = geometry.offsets[ oi ].start;
+					var count = geometry.offsets[ oi ].count;
+					var index = geometry.offsets[ oi ].index;
 
-					var v1 = [geometry.attributes.position.array[a * 3],
-								geometry.attributes.position.array[a * 3 + 1],
-								geometry.attributes.position.array[a * 3 + 2]];
-					var v2 = [geometry.attributes.position.array[b * 3],
-								geometry.attributes.position.array[b * 3 + 1],
-								geometry.attributes.position.array[b * 3 + 2]];
-					var v3 = [geometry.attributes.position.array[c * 3],
-								geometry.attributes.position.array[c * 3 + 1],
-								geometry.attributes.position.array[c * 3 + 2]];
+					for ( var i = start, il = start + count; i < il; i += 3 ) {
 
-					var material = object.material;
-					if (material === undefined) continue;
+						if ( indexed ) {
+							a = index + geometry.attributes.index.array[ i ];
+							b = index + geometry.attributes.index.array[ i + 1 ];
+							c = index + geometry.attributes.index.array[ i + 2 ];
+						} else {
+							a = index;
+							b = index + 1;
+							c = index + 2;
+						}
 
-					var cb = new THREE.Vector3(), ab = new THREE.Vector3();
-					var vA = new THREE.Vector3(v1[0], v1[1], v1[2]);
-					var vB = new THREE.Vector3(v2[0], v2[1], v2[2]);
-					var vC = new THREE.Vector3(v3[0], v3[1], v3[2]);
+						var v1 = [geometry.attributes.position.array[a * 3],
+									geometry.attributes.position.array[a * 3 + 1],
+									geometry.attributes.position.array[a * 3 + 2]];
+						var v2 = [geometry.attributes.position.array[b * 3],
+									geometry.attributes.position.array[b * 3 + 1],
+									geometry.attributes.position.array[b * 3 + 2]];
+						var v3 = [geometry.attributes.position.array[c * 3],
+									geometry.attributes.position.array[c * 3 + 1],
+									geometry.attributes.position.array[c * 3 + 2]];
 
-					cb.subVectors(vC, vB);
-					ab.subVectors(vA, vB);
-					cb.cross(ab);
-					cb.normalize();
+						var cb = new THREE.Vector3(), ab = new THREE.Vector3();
+						var vA = new THREE.Vector3(v1[0], v1[1], v1[2]);
+						var vB = new THREE.Vector3(v2[0], v2[1], v2[2]);
+						var vC = new THREE.Vector3(v3[0], v3[1], v3[2]);
 
-					facePlane.setFromNormalAndCoplanarPoint(cb, vA);
+						cb.subVectors(vC, vB);
+						ab.subVectors(vA, vB);
+						cb.cross(ab);
+						cb.normalize();
 
-					var planeDistance = localRay.distanceToPlane(facePlane);
+						facePlane.setFromNormalAndCoplanarPoint(cb, vA);
 
-					// bail if raycaster and plane are parallel
-					if (Math.abs(planeDistance) < precision) continue;
+						var planeDistance = localRay.distanceToPlane(facePlane);
 
-					// if negative distance, then plane is behind raycaster
-					if (planeDistance < 0) continue;
+						// bail if raycaster and plane are parallel
+						if (Math.abs(planeDistance) < precision) continue;
 
-					// check if we hit the wrong side of a single sided face
-					side = material.side;
-					if (side !== THREE.DoubleSide) {
+						// if negative distance, then plane is behind raycaster
+						if (planeDistance < 0) continue;
 
-						var planeSign = localRay.direction.dot(facePlane.normal);
+						// check if we hit the wrong side of a single sided face
+						side = material.side;
+						if (side !== THREE.DoubleSide) {
 
-						if (!(side === THREE.FrontSide ? planeSign < 0 : planeSign > 0)) continue;
+							var planeSign = localRay.direction.dot(facePlane.normal);
 
-					}
+							if (!(side === THREE.FrontSide ? planeSign < 0 : planeSign > 0)) continue;
 
-					// this can be done using the planeDistance from localRay because localRay wasn't normalized, but ray was
-					if (planeDistance < raycaster.near || planeDistance > raycaster.far) continue;
+						}
 
-					intersectPoint = localRay.at(planeDistance, intersectPoint); // passing in intersectPoint avoids a copy
+						// this can be done using the planeDistance from localRay because localRay wasn't normalized, but ray was
+						if (planeDistance < raycaster.near || planeDistance > raycaster.far) continue;
 
-					if (!THREE.Triangle.containsPoint(intersectPoint, vA, vB, vC)) continue;
+						intersectPoint = localRay.at(planeDistance, intersectPoint); // passing in intersectPoint avoids a copy
 
-					var face = new THREE.Face3(a, b, c);
-					var colors = geometry.attributes.color.array;
-					face.vertexColors[0] = new THREE.Color(colors[a * 3], colors[a * 3 + 1], colors[a * 3 + 2]);
-					face.vertexColors[1] = new THREE.Color(colors[b * 3], colors[b * 3 + 1], colors[b * 3 + 2]);
-					face.vertexColors[2] = new THREE.Color(colors[c * 3], colors[c * 3 + 1], colors[c * 3 + 2]);
-					intersects.push({
-						distance: planeDistance, // this works because the original ray was normalized, and the transformed localRay wasn't
-						point: raycaster.ray.at(planeDistance),
-						face: face,
-						faceIndex: f,
-						object: object
-					});
+						if (!THREE.Triangle.containsPoint(intersectPoint, vA, vB, vC)) continue;
+
+						var face = new THREE.Face3(a, b, c);
+
+						if ( geometry.attributes.color != null ) {
+							var colors = geometry.attributes.color.array;
+							face.vertexColors[0] = new THREE.Color(colors[a * 3], colors[a * 3 + 1], colors[a * 3 + 2]);
+							face.vertexColors[1] = new THREE.Color(colors[b * 3], colors[b * 3 + 1], colors[b * 3 + 2]);
+							face.vertexColors[2] = new THREE.Color(colors[c * 3], colors[c * 3 + 1], colors[c * 3 + 2]);
+						}
 
+						intersects.push({
+							distance: planeDistance, // this works because the original ray was normalized, and the transformed localRay wasn't
+							point: raycaster.ray.at(planeDistance),
+							face: face,
+							faceIndex: f,
+							object: object
+						});
+
+					}
 				}
 
 			} else if ( geometry instanceof THREE.Geometry ) {
@@ -256,7 +267,7 @@
 
 					intersects.push( {
 
-						distance: planeDistance,	// this works because the original ray was normalized, and the transformed localRay wasn't
+						distance: planeDistance,    // this works because the original ray was normalized, and the transformed localRay wasn't
 						point: raycaster.ray.at( planeDistance ),
 						face: face,
 						faceIndex: f,