Projector.js 14.4 KB
Newer Older
1
/**
M
Mr.doob 已提交
2
 * @author mrdoob / http://mrdoob.com/
3 4 5 6 7 8
 * @author supereggbert / http://www.paulbrunt.co.uk/
 * @author julianwa / https://github.com/julianwa
 */

THREE.Projector = function() {

M
Mr.doob 已提交
9 10 11 12 13 14
	var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
	_vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
	_face, _face3Count, _face3Pool = [], _face3PoolLength = 0,
	_face4Count, _face4Pool = [], _face4PoolLength = 0,
	_line, _lineCount, _linePool = [], _linePoolLength = 0,
	_particle, _particleCount, _particlePool = [], _particlePoolLength = 0,
15

M
Mr.doob 已提交
16
	_renderData = { objects: [], sprites: [], lights: [], elements: [] },
17

18
	_vector3 = new THREE.Vector3(),
19
	_vector4 = new THREE.Vector4(),
20

21 22
	_viewProjectionMatrix = new THREE.Matrix4(),
	_modelViewProjectionMatrix = new THREE.Matrix4(),
23

A
alteredq 已提交
24
	_frustum = new THREE.Frustum(),
25 26 27 28 29 30 31

	_clippedVertex1PositionScreen = new THREE.Vector4(),
	_clippedVertex2PositionScreen = new THREE.Vector4(),

	_face3VertexNormals;

	this.projectVector = function ( vector, camera ) {
32

33
		camera.matrixWorldInverse.getInverse( camera.matrixWorld );
34

35 36
		_viewProjectionMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse );
		_viewProjectionMatrix.multiplyVector3( vector );
37 38

		return vector;
39

40 41
	};

J
Justin Sermeno 已提交
42
	this.unprojectVector = function ( vector, camera ) {
43

44 45
		camera.projectionMatrixInverse.getInverse( camera.projectionMatrix );

46 47
		_viewProjectionMatrix.multiply( camera.matrixWorld, camera.projectionMatrixInverse );
		_viewProjectionMatrix.multiplyVector3( vector );
48

J
Justin Sermeno 已提交
49
		return vector;
50

J
Justin Sermeno 已提交
51
	};
J
Justin Sermeno 已提交
52

J
Justin Sermeno 已提交
53
	this.pickingRay = function ( vector, camera ) {
J
Justin Sermeno 已提交
54

55 56 57
		var end, ray, t;

		// set two vectors with opposing z values
J
Justin Sermeno 已提交
58 59
		vector.z = -1.0;
		end = new THREE.Vector3( vector.x, vector.y, 1.0 );
J
Justin Sermeno 已提交
60

J
Justin Sermeno 已提交
61 62 63
		this.unprojectVector( vector, camera );
		this.unprojectVector( end, camera );

64 65
		// find direction from vector to end
		end.subSelf( vector ).normalize();
66

67
		return new THREE.Ray( vector, end );
68

69 70
	};

M
Mr.doob 已提交
71
	var projectGraph = function ( root, sort ) {
M
Mr.doob 已提交
72 73

		_objectCount = 0;
74

75
		_renderData.objects.length = 0;
M
Mr.doob 已提交
76
		_renderData.sprites.length = 0;
77
		_renderData.lights.length = 0;
78

M
Mr.doob 已提交
79
		var projectObject = function ( object ) {
80

M
Mr.doob 已提交
81
			if ( object.visible === false ) return;
82

M
Mr.doob 已提交
83
			if ( ( object instanceof THREE.Mesh || object instanceof THREE.Line ) &&
M
Mr.doob 已提交
84
			( object.frustumCulled === false || _frustum.contains( object ) === true ) ) {
85

86
				_vector3.copy( object.matrixWorld.getPosition() );
87
				_viewProjectionMatrix.multiplyVector3( _vector3 );
88

M
Mr.doob 已提交
89 90 91
				_object = getNextObjectInPool();
				_object.object = object;
				_object.z = _vector3.z;
M
Mr.doob 已提交
92

M
Mr.doob 已提交
93
				_renderData.objects.push( _object );
M
Mr.doob 已提交
94 95 96

			} else if ( object instanceof THREE.Sprite || object instanceof THREE.Particle ) {

97
				_vector3.copy( object.matrixWorld.getPosition() );
98
				_viewProjectionMatrix.multiplyVector3( _vector3 );
M
Mr.doob 已提交
99 100 101 102 103 104

				_object = getNextObjectInPool();
				_object.object = object;
				_object.z = _vector3.z;

				_renderData.sprites.push( _object );
M
Mr.doob 已提交
105

106
			} else if ( object instanceof THREE.Light ) {
107

108
				_renderData.lights.push( object );
109

M
Mr.doob 已提交
110
			}
111

M
Mr.doob 已提交
112 113 114 115 116 117 118 119
			for ( var c = 0, cl = object.children.length; c < cl; c ++ ) {

				projectObject( object.children[ c ] );

			}

		};

M
Mr.doob 已提交
120 121
		projectObject( root );

M
Mr.doob 已提交
122
		if ( sort === true ) _renderData.objects.sort( painterSort );
123

124
		return _renderData;
125 126 127 128 129

	};

	this.projectScene = function ( scene, camera, sort ) {

130
		var near = camera.near, far = camera.far, visible = false,
131
		o, ol, v, vl, f, fl, n, nl, c, cl, u, ul, object,
132
		modelMatrix, rotationMatrix,
133
		geometry, geometryMaterials, vertices, vertex, vertexPositionScreen,
134
		faces, face, faceVertexNormals, normal, faceVertexUvs, uvs,
135
		v1, v2, v3, v4, isFaceMaterial, material, side;
136 137 138 139 140 141

		_face3Count = 0;
		_face4Count = 0;
		_lineCount = 0;
		_particleCount = 0;

142 143
		_renderData.elements.length = 0;

M
Mr.doob 已提交
144
		scene.updateMatrixWorld();
145

146 147
		if ( camera.parent === undefined ) camera.updateMatrixWorld();

148
		camera.matrixWorldInverse.getInverse( camera.matrixWorld );
149

150
		_viewProjectionMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse );
151

152
		_frustum.setFromMatrix( _viewProjectionMatrix );
153

154
		_renderData = projectGraph( scene, false );
155

156
		for ( o = 0, ol = _renderData.objects.length; o < ol; o++ ) {
157

M
Mr.doob 已提交
158
			object = _renderData.objects[ o ].object;
159

160
			modelMatrix = object.matrixWorld;
161 162 163 164 165 166

			_vertexCount = 0;

			if ( object instanceof THREE.Mesh ) {

				geometry = object.geometry;
167
				geometryMaterials = object.geometry.materials;
168 169 170 171
				vertices = geometry.vertices;
				faces = geometry.faces;
				faceVertexUvs = geometry.faceVertexUvs;

172 173
				rotationMatrix = object.matrixRotationWorld.extractRotation( modelMatrix );

174 175
				isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
				side = object.material.side;
M
Mr.doob 已提交
176

177 178 179
				for ( v = 0, vl = vertices.length; v < vl; v ++ ) {

					_vertex = getNextVertexInPool();
180
					_vertex.positionWorld.copy( vertices[ v ] );
181

182
					modelMatrix.multiplyVector3( _vertex.positionWorld );
183 184

					_vertex.positionScreen.copy( _vertex.positionWorld );
185
					_viewProjectionMatrix.multiplyVector4( _vertex.positionScreen );
186 187 188 189 190 191 192 193 194 195 196 197

					_vertex.positionScreen.x /= _vertex.positionScreen.w;
					_vertex.positionScreen.y /= _vertex.positionScreen.w;

					_vertex.visible = _vertex.positionScreen.z > near && _vertex.positionScreen.z < far;

				}

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

					face = faces[ f ];

198
					material = isFaceMaterial === true ? geometryMaterials[ face.materialIndex ] : object.material;
199 200 201

					if ( material === undefined ) continue;

202 203
					side = material.side;

204 205 206 207 208 209
					if ( face instanceof THREE.Face3 ) {

						v1 = _vertexPool[ face.a ];
						v2 = _vertexPool[ face.b ];
						v3 = _vertexPool[ face.c ];

M
Mr.doob 已提交
210
						if ( v1.visible === true && v2.visible === true && v3.visible === true ) {
211

212 213
							visible = ( ( v3.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) -
								( v3.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;
214

215
							if ( side === THREE.DoubleSide || visible === ( side === THREE.FrontSide ) ) {
216 217 218 219 220 221 222 223 224 225 226 227

								_face = getNextFace3InPool();

								_face.v1.copy( v1 );
								_face.v2.copy( v2 );
								_face.v3.copy( v3 );

							} else {

								continue;

							}
228 229 230 231 232 233 234 235 236 237 238 239 240 241

						} else {

							continue;

						}

					} else if ( face instanceof THREE.Face4 ) {

						v1 = _vertexPool[ face.a ];
						v2 = _vertexPool[ face.b ];
						v3 = _vertexPool[ face.c ];
						v4 = _vertexPool[ face.d ];

M
Mr.doob 已提交
242
						if ( v1.visible === true && v2.visible === true && v3.visible === true && v4.visible === true ) {
243 244 245 246 247 248 249

							visible = ( v4.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) -
								( v4.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) < 0 ||
								( v2.positionScreen.x - v3.positionScreen.x ) * ( v4.positionScreen.y - v3.positionScreen.y ) -
								( v2.positionScreen.y - v3.positionScreen.y ) * ( v4.positionScreen.x - v3.positionScreen.x ) < 0;


250
							if ( side === THREE.DoubleSide || visible === ( side === THREE.FrontSide ) ) {
251 252 253 254 255 256 257 258 259

								_face = getNextFace4InPool();

								_face.v1.copy( v1 );
								_face.v2.copy( v2 );
								_face.v3.copy( v3 );
								_face.v4.copy( v4 );

							} else {
260

261
								continue;
262

263
							}
264 265 266 267 268 269 270 271 272 273

						} else {

							continue;

						}

					}

					_face.normalWorld.copy( face.normal );
274

275
					if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) _face.normalWorld.negate();
276
					rotationMatrix.multiplyVector3( _face.normalWorld );
277 278

					_face.centroidWorld.copy( face.centroid );
279
					modelMatrix.multiplyVector3( _face.centroidWorld );
280 281

					_face.centroidScreen.copy( _face.centroidWorld );
282
					_viewProjectionMatrix.multiplyVector3( _face.centroidScreen );
283 284 285 286 287 288 289

					faceVertexNormals = face.vertexNormals;

					for ( n = 0, nl = faceVertexNormals.length; n < nl; n ++ ) {

						normal = _face.vertexNormalsWorld[ n ];
						normal.copy( faceVertexNormals[ n ] );
M
Mr.doob 已提交
290

291
						if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) normal.negate();
M
Mr.doob 已提交
292

293
						rotationMatrix.multiplyVector3( normal );
294 295 296

					}

297
					_face.vertexNormalsLength = faceVertexNormals.length;
298

299 300 301 302
					for ( c = 0, cl = faceVertexUvs.length; c < cl; c ++ ) {

						uvs = faceVertexUvs[ c ][ f ];

M
Mr.doob 已提交
303
						if ( uvs === undefined ) continue;
304 305 306 307 308 309 310 311 312

						for ( u = 0, ul = uvs.length; u < ul; u ++ ) {

							_face.uvs[ c ][ u ] = uvs[ u ];

						}

					}

313
					_face.material = material;
314 315 316

					_face.z = _face.centroidScreen.z;

317
					_renderData.elements.push( _face );
318 319 320

				}

M
Mr.doob 已提交
321
			} else if ( object instanceof THREE.Line ) {
M
Mr.doob 已提交
322

323
				_modelViewProjectionMatrix.multiply( _viewProjectionMatrix, modelMatrix );
324 325

				vertices = object.geometry.vertices;
M
Mr.doob 已提交
326

327
				v1 = getNextVertexInPool();
328
				v1.positionScreen.copy( vertices[ 0 ] );
329
				_modelViewProjectionMatrix.multiplyVector4( v1.positionScreen );
330

M
Mr.doob 已提交
331 332 333 334
				// Handle LineStrip and LinePieces
				var step = object.type === THREE.LinePieces ? 2 : 1;

				for ( v = 1, vl = vertices.length; v < vl; v ++ ) {
335 336

					v1 = getNextVertexInPool();
337
					v1.positionScreen.copy( vertices[ v ] );
338
					_modelViewProjectionMatrix.multiplyVector4( v1.positionScreen );
339

M
Mr.doob 已提交
340
					if ( ( v + 1 ) % step > 0 ) continue;
M
Mr.doob 已提交
341

342 343 344 345 346
					v2 = _vertexPool[ _vertexCount - 2 ];

					_clippedVertex1PositionScreen.copy( v1.positionScreen );
					_clippedVertex2PositionScreen.copy( v2.positionScreen );

M
Mr.doob 已提交
347
					if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) {
348 349 350 351 352 353 354 355 356 357 358

						// Perform the perspective divide
						_clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );
						_clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );

						_line = getNextLineInPool();
						_line.v1.positionScreen.copy( _clippedVertex1PositionScreen );
						_line.v2.positionScreen.copy( _clippedVertex2PositionScreen );

						_line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );

359
						_line.material = object.material;
360

361
						_renderData.elements.push( _line );
362 363

					}
M
Mr.doob 已提交
364

365 366
				}

M
Mr.doob 已提交
367
			}
M
Mr.doob 已提交
368

M
Mr.doob 已提交
369 370 371 372
		}

		for ( o = 0, ol = _renderData.sprites.length; o < ol; o++ ) {

M
Mr.doob 已提交
373
			object = _renderData.sprites[ o ].object;
M
Mr.doob 已提交
374

375
			modelMatrix = object.matrixWorld;
M
Mr.doob 已提交
376 377

			if ( object instanceof THREE.Particle ) {
378

379 380
				_vector4.set( modelMatrix.elements[12], modelMatrix.elements[13], modelMatrix.elements[14], 1 );
				_viewProjectionMatrix.multiplyVector4( _vector4 );
381 382 383 384 385 386

				_vector4.z /= _vector4.w;

				if ( _vector4.z > 0 && _vector4.z < 1 ) {

					_particle = getNextParticleInPool();
387
					_particle.object = object;
388 389 390 391 392 393
					_particle.x = _vector4.x / _vector4.w;
					_particle.y = _vector4.y / _vector4.w;
					_particle.z = _vector4.z;

					_particle.rotation = object.rotation.z;

394 395
					_particle.scale.x = object.scale.x * Math.abs( _particle.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) );
					_particle.scale.y = object.scale.y * Math.abs( _particle.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) );
396

397
					_particle.material = object.material;
398

399
					_renderData.elements.push( _particle );
400 401 402 403 404 405 406

				}

			}

		}

407
		sort && _renderData.elements.sort( painterSort );
408

409
		return _renderData;
410 411 412 413 414

	};

	// Pools

M
Mr.doob 已提交
415 416
	function getNextObjectInPool() {

M
Mr.doob 已提交
417
		if ( _objectCount === _objectPoolLength ) {
M
Mr.doob 已提交
418

M
Mr.doob 已提交
419
			var object = new THREE.RenderableObject();
M
Mr.doob 已提交
420
			_objectPool.push( object );
M
Mr.doob 已提交
421 422 423
			_objectPoolLength ++;
			_objectCount ++;
			return object;
M
Mr.doob 已提交
424 425

		}
M
Mr.doob 已提交
426

M
Mr.doob 已提交
427
		return _objectPool[ _objectCount ++ ];
M
Mr.doob 已提交
428 429 430

	}

431 432
	function getNextVertexInPool() {

M
Mr.doob 已提交
433
		if ( _vertexCount === _vertexPoolLength ) {
M
Mr.doob 已提交
434

M
Mr.doob 已提交
435
			var vertex = new THREE.RenderableVertex();
M
Mr.doob 已提交
436
			_vertexPool.push( vertex );
M
Mr.doob 已提交
437 438 439
			_vertexPoolLength ++;
			_vertexCount ++;
			return vertex;
M
Mr.doob 已提交
440 441

		}
442

M
Mr.doob 已提交
443
		return _vertexPool[ _vertexCount ++ ];
444 445 446 447 448

	}

	function getNextFace3InPool() {

M
Mr.doob 已提交
449
		if ( _face3Count === _face3PoolLength ) {
M
Mr.doob 已提交
450

M
Mr.doob 已提交
451
			var face = new THREE.RenderableFace3();
M
Mr.doob 已提交
452
			_face3Pool.push( face );
M
Mr.doob 已提交
453 454 455
			_face3PoolLength ++;
			_face3Count ++;
			return face;
M
Mr.doob 已提交
456 457

		}
458

M
Mr.doob 已提交
459
		return _face3Pool[ _face3Count ++ ];
460

M
Mr.doob 已提交
461

462 463 464 465
	}

	function getNextFace4InPool() {

M
Mr.doob 已提交
466
		if ( _face4Count === _face4PoolLength ) {
M
Mr.doob 已提交
467

M
Mr.doob 已提交
468
			var face = new THREE.RenderableFace4();
M
Mr.doob 已提交
469
			_face4Pool.push( face );
M
Mr.doob 已提交
470 471 472
			_face4PoolLength ++;
			_face4Count ++;
			return face;
M
Mr.doob 已提交
473 474

		}
475

M
Mr.doob 已提交
476
		return _face4Pool[ _face4Count ++ ];
477 478 479 480 481

	}

	function getNextLineInPool() {

M
Mr.doob 已提交
482
		if ( _lineCount === _linePoolLength ) {
M
Mr.doob 已提交
483

M
Mr.doob 已提交
484
			var line = new THREE.RenderableLine();
M
Mr.doob 已提交
485
			_linePool.push( line );
M
Mr.doob 已提交
486 487 488
			_linePoolLength ++;
			_lineCount ++
			return line;
M
Mr.doob 已提交
489 490

		}
491

M
Mr.doob 已提交
492
		return _linePool[ _lineCount ++ ];
493 494 495 496 497

	}

	function getNextParticleInPool() {

M
Mr.doob 已提交
498
		if ( _particleCount === _particlePoolLength ) {
M
Mr.doob 已提交
499

M
Mr.doob 已提交
500
			var particle = new THREE.RenderableParticle();
M
Mr.doob 已提交
501
			_particlePool.push( particle );
M
Mr.doob 已提交
502 503 504
			_particlePoolLength ++;
			_particleCount ++
			return particle;
M
Mr.doob 已提交
505 506 507

		}

M
Mr.doob 已提交
508
		return _particlePool[ _particleCount ++ ];
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590

	}

	//

	function painterSort( a, b ) {

		return b.z - a.z;

	}

	function clipLine( s1, s2 ) {

		var alpha1 = 0, alpha2 = 1,

		// Calculate the boundary coordinate of each vertex for the near and far clip planes,
		// Z = -1 and Z = +1, respectively.
		bc1near =  s1.z + s1.w,
		bc2near =  s2.z + s2.w,
		bc1far =  - s1.z + s1.w,
		bc2far =  - s2.z + s2.w;

		if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {

			// Both vertices lie entirely within all clip planes.
			return true;

		} else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) {

			// Both vertices lie entirely outside one of the clip planes.
			return false;

		} else {

			// The line segment spans at least one clip plane.

			if ( bc1near < 0 ) {

				// v1 lies outside the near plane, v2 inside
				alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );

			} else if ( bc2near < 0 ) {

				// v2 lies outside the near plane, v1 inside
				alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );

			}

			if ( bc1far < 0 ) {

				// v1 lies outside the far plane, v2 inside
				alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );

			} else if ( bc2far < 0 ) {

				// v2 lies outside the far plane, v2 inside
				alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );

			}

			if ( alpha2 < alpha1 ) {

				// The line segment spans two boundaries, but is outside both of them.
				// (This can't happen when we're only clipping against just near/far but good
				//  to leave the check here for future usage if other clip planes are added.)
				return false;

			} else {

				// Update the s1 and s2 vertices to match the clipped line segment.
				s1.lerpSelf( s2, alpha1 );
				s2.lerpSelf( s1, 1 - alpha2 );

				return true;

			}

		}

	}

};