Browse Source

Merge remote-tracking branch 'kevinoe/BufferGeometryRaycast' into dev

Mr.doob 12 years ago
parent
commit
d0875a9c57
1 changed files with 118 additions and 0 deletions
  1. 118 0
      src/core/Raycaster.js

+ 118 - 0
src/core/Raycaster.js

@@ -64,6 +64,124 @@
 
 			intersectObject( object.getObjectForDistance( distance ), raycaster, intersects );
 
+		} else if (object instanceof THREE.Mesh && object.geometry instanceof THREE.BufferGeometry) {
+
+			// Checking boundingSphere distance to ray
+			matrixPosition.getPositionFromMatrix(object.matrixWorld);
+			sphere.set(matrixPosition,
+				object.geometry.boundingSphere.radius * object.matrixWorld.getMaxScaleOnAxis());
+
+			if (!raycaster.ray.isIntersectionSphere(sphere)) {
+
+				return intersects;
+
+			}
+
+			// Checking faces
+
+			var geometry = object.geometry;
+			var vertices = geometry.vertices;
+
+			var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
+			var objectMaterials = isFaceMaterial === true ? object.material.materials : null;
+
+			var side = object.material.side;
+
+			var a, b, c;
+			var precision = raycaster.precision;
+
+			inverseMatrix.getInverse(object.matrixWorld);
+
+			localRay.copy(raycaster.ray).applyMatrix4(inverseMatrix);
+
+			if (!geometry.dynamic) return intersects;
+
+			var fl;
+			var indexed = false;
+			if (geometry.attributes.index) {
+				indexed = true;
+				fl = geometry.attributes.index.numItems / 3;
+			} else {
+				fl = geometry.attributes.position.numItems / 9;
+			}
+
+			for (var f = 0; f < fl; f++) {
+
+				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 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]];
+
+				var material = object.material;
+				if (material === undefined) continue;
+
+				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]);
+
+				cb.subVectors(vC, vB);
+				ab.subVectors(vA, vB);
+				cb.cross(ab);
+				cb.normalize();
+
+				facePlane.setFromNormalAndCoplanarPoint(cb, vA);
+
+				var planeDistance = localRay.distanceToPlane(facePlane);
+
+				// bail if raycaster and plane are parallel
+				if (Math.abs(planeDistance) < precision) continue;
+
+				// if negative distance, then plane is behind raycaster
+				if (planeDistance < 0) continue;
+
+				// check if we hit the wrong side of a single sided face
+				side = material.side;
+				if (side !== THREE.DoubleSide) {
+
+					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
+
+				if (!THREE.Triangle.containsPoint(intersectPoint, vA, vB, vC)) continue;
+
+				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
+				});
+
+			}
+
 		} else if ( object instanceof THREE.Mesh ) {
 
 			// Checking boundingSphere distance to ray