Ray.js 6.3 KB
Newer Older
1
/**
M
Mr.doob 已提交
2
 * @author mrdoob / http://mrdoob.com/
3 4
 */

N
niklassa 已提交
5
THREE.Ray = function ( origin, direction, near, far ) {
6 7 8

	this.origin = origin || new THREE.Vector3();
	this.direction = direction || new THREE.Vector3();
N
niklassa 已提交
9 10
	this.near = near || 0;
	this.far = far || Infinity;
11

M
Mr.doob 已提交
12
	//
13

M
Mr.doob 已提交
14 15 16 17
	var a = new THREE.Vector3();
	var b = new THREE.Vector3();
	var c = new THREE.Vector3();
	var d = new THREE.Vector3();
M
Mr.doob 已提交
18

19 20
	var originCopy = new THREE.Vector3();
	var directionCopy = new THREE.Vector3();
21 22
	
	var localOriginCopy = new THREE.Vector3();
23
	var localDirectionCopy = new THREE.Vector3();
24

25

26
	var vector = new THREE.Vector3();
M
Mr.doob 已提交
27
	var normal = new THREE.Vector3();
M
Mr.doob 已提交
28
	var intersectPoint = new THREE.Vector3();
29 30
	
	
31
	var inverseMatrix = new THREE.Matrix4();
A
alteredq 已提交
32

33
	var descSort = function ( a, b ) {
A
alteredq 已提交
34

35
			return a.distance - b.distance;
A
alteredq 已提交
36

37
	};
M
Mr.doob 已提交
38

M
Mr.doob 已提交
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
	//

	var v0 = new THREE.Vector3(), v1 = new THREE.Vector3(), v2 = new THREE.Vector3();
	var dot, intersect, distance;

	var distanceFromIntersection = function ( origin, direction, position ) {

		v0.sub( position, origin );
		dot = v0.dot( direction );

		intersect = v1.add( origin, v2.copy( direction ).multiplyScalar( dot ) );
		distance = position.distanceTo( intersect );

		return distance;

	}

	// http://www.blackpawn.com/texts/pointinpoly/default.html

	var dot00, dot01, dot02, dot11, dot12, invDenom, u, v;

	var pointInFace3 = function ( p, a, b, c ) {

		v0.sub( c, a );
		v1.sub( b, a );
		v2.sub( p, a );

		dot00 = v0.dot( v0 );
		dot01 = v0.dot( v1 );
		dot02 = v0.dot( v2 );
		dot11 = v1.dot( v1 );
		dot12 = v1.dot( v2 );

		invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 );
		u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
		v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;

		return ( u >= 0 ) && ( v >= 0 ) && ( u + v < 1 );

	}

	//

	var precision = 0.0001;

	this.setPrecision = function ( value ) {

		precision = value;

	};

90
	this.intersectObject = function ( object, recursive ) {
M
Mr.doob 已提交
91

M
Mr.doob 已提交
92 93
		var intersect, intersects = [];

94 95 96 97 98 99 100 101 102 103
		if ( recursive === true ) {

			for ( var i = 0, l = object.children.length; i < l; i ++ ) {

				Array.prototype.push.apply( intersects, this.intersectObject( object.children[ i ], recursive ) );

			}

		}

104
		if ( object instanceof THREE.Particle ) {
105

106
			distance = distanceFromIntersection( this.origin, this.direction, object.matrixWorld.getPosition() );
107

M
Mr.doob 已提交
108
			if ( distance > object.scale.x ) {
109

110
				return [];
111

112
			}
113

M
Mr.doob 已提交
114
			intersect = {
115

116 117 118 119
				distance: distance,
				point: object.position,
				face: null,
				object: object
120

M
Mr.doob 已提交
121 122 123
			};

			intersects.push( intersect );
124

125
		} else if ( object instanceof THREE.Mesh ) {
126

127
			// Checking boundingSphere
M
Mr.doob 已提交
128

M
r47  
Mr.doob 已提交
129
			var scale = THREE.Frustum.__v1.set( object.matrixWorld.getColumnX().length(), object.matrixWorld.getColumnY().length(), object.matrixWorld.getColumnZ().length() );
A
alteredq 已提交
130
			var scaledRadius = object.geometry.boundingSphere.radius * Math.max( scale.x, Math.max( scale.y, scale.z ) );
131 132

			// Checking distance to ray
A
alteredq 已提交
133

134 135 136
			distance = distanceFromIntersection( this.origin, this.direction, object.matrixWorld.getPosition() );

			if ( distance > scaledRadius) {
137

M
Mr.doob 已提交
138
				return intersects;
139 140 141 142 143

			}

			// Checking faces

144
			var f, fl, face, dot, scalar,
145 146
			geometry = object.geometry,
			vertices = geometry.vertices,
147 148 149 150 151 152
			objMatrix, geometryMaterials,
			isFaceMaterial, material, side;

			geometryMaterials = object.geometry.materials;
			isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
			side = object.material.side;
153

M
Mr.doob 已提交
154
			object.matrixRotationWorld.extractRotation( object.matrixWorld );
155 156
			
			originCopy.copy( this.origin );
157 158 159 160 161 162 163 164 165 166 167 168
			directionCopy.copy( this.direction );

			objMatrix = object.matrixWorld;
			inverseMatrix.getInverse(objMatrix);
			
			
			
			localOriginCopy.copy(originCopy);
			inverseMatrix.multiplyVector3(localOriginCopy);
			
			localDirectionCopy.copy(directionCopy);
			inverseMatrix.rotateAxis(localDirectionCopy).normalize();
M
Mr.doob 已提交
169

170
			for ( f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
171

172
				face = geometry.faces[ f ];
173

174 175 176 177 178
				material = isFaceMaterial === true ? geometryMaterials[ face.materialIndex ] : object.material;
				if ( material === undefined ) continue;

				side = material.side;

179 180
				vector.sub( face.centroid, localOriginCopy );
				normal.copy( face.normal );
181
				dot = localDirectionCopy.dot( normal );
182 183


184
				// bail if ray and plane are parallel
185

186
				if ( Math.abs( dot ) < precision ) continue;
187

188
				// calc distance to plane
189

190
				scalar = normal.dot( vector ) / dot;
191

192 193 194 195
				// if negative distance, then plane is behind ray

				if ( scalar < 0 ) continue;

196
				if ( side === THREE.DoubleSide || ( side === THREE.FrontSide ? dot < 0 : dot > 0 ) ) {
197

198
					intersectPoint.add( localOriginCopy, localDirectionCopy.multiplyScalar( scalar ) );
199 200 201

					if ( face instanceof THREE.Face3 ) {

202 203 204
						a.copy( vertices[ face.a ] );
						b.copy( vertices[ face.b ] );
						c.copy( vertices[ face.c ] );
205

206 207
						if ( pointInFace3( intersectPoint, a, b, c ) ) {

208
							var point = object.matrixWorld.multiplyVector3(intersectPoint.clone()); 
209 210 211
							distance = originCopy.distanceTo( point);
							
							if ( distance < this.near ) continue;
212
							if ( distance > this.far ) continue; 
213 214
							
							
215 216
							intersect = {

N
niklassa 已提交
217
								distance: distance,
218
								point: point,
219
								face: face,
A
alteredq 已提交
220
								faceIndex: f,
221 222 223
								object: object

							};
224

225
							intersects.push( intersect );
226

227
						}
228

229
					} else if ( face instanceof THREE.Face4 ) {
230

231 232 233 234
						a.copy( vertices[ face.a ] );
						b.copy( vertices[ face.b ] );
						c.copy( vertices[ face.c ] );
						d.copy( vertices[ face.d ] );
235

236
						if ( pointInFace3( intersectPoint, a, b, d ) || pointInFace3( intersectPoint, b, c, d ) ) {
237

238
							var point = object.matrixWorld.multiplyVector3(intersectPoint.clone()); 
239 240 241
							distance = originCopy.distanceTo( point);
							
							if ( distance < this.near ) continue;
242
							if ( distance > this.far ) continue; 
243
							
244
							intersect = {
245

N
niklassa 已提交
246
								distance: distance,
247
								point: point,
248
								face: face,
A
alteredq 已提交
249
								faceIndex: f,
250 251 252 253 254 255 256
								object: object

							};

							intersects.push( intersect );

						}
257 258 259 260 261 262

					}

				}

			}
263

M
Mr.doob 已提交
264
		}
265

266 267
		intersects.sort( descSort );

M
Mr.doob 已提交
268
		return intersects;
269

M
Mr.doob 已提交
270
	};
271

272
	this.intersectObjects = function ( objects, recursive ) {
M
Mr.doob 已提交
273 274 275 276 277

		var intersects = [];

		for ( var i = 0, l = objects.length; i < l; i ++ ) {

278
			Array.prototype.push.apply( intersects, this.intersectObject( objects[ i ], recursive ) );
M
Mr.doob 已提交
279 280 281

		}

282
		intersects.sort( descSort );
M
Mr.doob 已提交
283 284 285 286 287

		return intersects;

	};

288
};