Ray.js 7.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 23 24
	
	var localOriginCopy = new THREE.Vector3();
    var localDirectionCopy = new THREE.Vector3();

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
			rangeSq = this.range * this.range,
146 147
			geometry = object.geometry,
			vertices = geometry.vertices,
148 149 150 151 152 153
			objMatrix, geometryMaterials,
			isFaceMaterial, material, side;

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

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

            objMatrix = object.matrixWorld;
            inverseMatrix.getInverse(objMatrix);
            
            
            
            localOriginCopy.copy(originCopy);
            inverseMatrix.multiplyVector3(localOriginCopy);
            
            localDirectionCopy.add(originCopy,directionCopy);
            inverseMatrix.multiplyVector3(localDirectionCopy);
            localDirectionCopy.subSelf(localOriginCopy).normalize();
M
Mr.doob 已提交
171

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

174
				face = geometry.faces[ f ];
175

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

				side = material.side;

181 182
				//originCopy.copy( this.origin );
				//directionCopy.copy( this.direction );
183

184
				//objMatrix = object.matrixWorld;
185

186 187
				// determine if ray intersects the plane of the face
				// note: this works regardless of the direction of the face normal
188 189 190 191 192 193 194
				
				//vector = objMatrix.multiplyVector3( vector.copy( face.centroid ) ).subSelf( originCopy );
				//normal = object.matrixRotationWorld.multiplyVector3( normal.copy( face.normal ) );
				//dot = directionCopy.dot( normal );
				vector.sub( face.centroid, localOriginCopy );
				normal.copy( face.normal );
                dot = localDirectionCopy.dot( normal );
195 196


197
				// bail if ray and plane are parallel
198

199
				if ( Math.abs( dot ) < precision ) continue;
200

201
				// calc distance to plane
202

203
				scalar = normal.dot( vector ) / dot;
204

205 206 207 208
				// if negative distance, then plane is behind ray

				if ( scalar < 0 ) continue;

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

211
					intersectPoint.add( localOriginCopy, localDirectionCopy.multiplyScalar( scalar ) );
212

213
					//distance = originCopy.distanceTo( intersectPoint );
M
Mr.doob 已提交
214

215 216
					//if ( distance < this.near ) continue;
					//if ( distance > this.far ) continue;
217

218 219
					if ( face instanceof THREE.Face3 ) {

220 221 222
						a.copy( vertices[ face.a ] );
						b.copy( vertices[ face.b ] );
						c.copy( vertices[ face.c ] );
223

224 225
						if ( pointInFace3( intersectPoint, a, b, c ) ) {

226 227 228 229 230 231 232
							var point = object.matrixWorld.multiplyVector3(intersectPoint.clone()); 
                            distance = originCopy.distanceTo( point);
                            
                            if ( distance < this.near ) continue;
							if ( distance > this.far ) continue; 
                            
                            
233 234
							intersect = {

N
niklassa 已提交
235
								distance: distance,
236
								point: point,
237
								face: face,
A
alteredq 已提交
238
								faceIndex: f,
239 240 241
								object: object

							};
242

243
							intersects.push( intersect );
244

245
						}
246

247
					} else if ( face instanceof THREE.Face4 ) {
248

249 250 251 252
						a.copy( vertices[ face.a ] );
						b.copy( vertices[ face.b ] );
						c.copy( vertices[ face.c ] );
						d.copy( vertices[ face.d ] );
253

254
						if ( pointInFace3( intersectPoint, a, b, d ) || pointInFace3( intersectPoint, b, c, d ) ) {
255

256 257 258 259 260 261
							var point = object.matrixWorld.multiplyVector3(intersectPoint.clone()); 
                            distance = originCopy.distanceTo( point);
                            
                            if ( distance < this.near ) continue;
							if ( distance > this.far ) continue; 
                            
262
							intersect = {
263

N
niklassa 已提交
264
								distance: distance,
265
								point: point,
266
								face: face,
A
alteredq 已提交
267
								faceIndex: f,
268 269 270 271 272 273 274
								object: object

							};

							intersects.push( intersect );

						}
275 276 277 278 279 280

					}

				}

			}
281

M
Mr.doob 已提交
282
		}
283

284 285
		intersects.sort( descSort );

M
Mr.doob 已提交
286
		return intersects;
287

M
Mr.doob 已提交
288
	};
289

290
	this.intersectObjects = function ( objects, recursive ) {
M
Mr.doob 已提交
291 292 293 294 295

		var intersects = [];

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

296
			Array.prototype.push.apply( intersects, this.intersectObject( objects[ i ], recursive ) );
M
Mr.doob 已提交
297 298 299

		}

300
		intersects.sort( descSort );
M
Mr.doob 已提交
301 302 303 304 305

		return intersects;

	};

306
};