source: other-projects/playing-in-the-street/summer-2013/trunk/Playing-in-the-Street-WPF/Content/Web/mrdoob-three.js-4862f5f/src/core/Projector.js@ 28897

Last change on this file since 28897 was 28897, checked in by davidb, 10 years ago

GUI front-end to server base plus web page content

File size: 15.6 KB
Line 
1/**
2 * @author mrdoob / http://mrdoob.com/
3 * @author supereggbert / http://www.paulbrunt.co.uk/
4 * @author julianwa / https://github.com/julianwa
5 */
6
7THREE.Projector = function () {
8
9 var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
10 _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
11 _face, _face3Count, _face3Pool = [], _face3PoolLength = 0,
12 _line, _lineCount, _linePool = [], _linePoolLength = 0,
13 _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0,
14
15 _renderData = { objects: [], sprites: [], lights: [], elements: [] },
16
17 _vA = new THREE.Vector3(),
18 _vB = new THREE.Vector3(),
19 _vC = new THREE.Vector3(),
20
21 _vector3 = new THREE.Vector3(),
22 _vector4 = new THREE.Vector4(),
23
24 _clipBox = new THREE.Box3( new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3( 1, 1, 1 ) ),
25 _boundingBox = new THREE.Box3(),
26 _points3 = new Array( 3 ),
27 _points4 = new Array( 4 ),
28
29 _viewMatrix = new THREE.Matrix4(),
30 _viewProjectionMatrix = new THREE.Matrix4(),
31
32 _modelMatrix,
33 _modelViewProjectionMatrix = new THREE.Matrix4(),
34
35 _normalMatrix = new THREE.Matrix3(),
36 _normalViewMatrix = new THREE.Matrix3(),
37
38 _centroid = new THREE.Vector3(),
39
40 _frustum = new THREE.Frustum(),
41
42 _clippedVertex1PositionScreen = new THREE.Vector4(),
43 _clippedVertex2PositionScreen = new THREE.Vector4();
44
45 this.projectVector = function ( vector, camera ) {
46
47 camera.matrixWorldInverse.getInverse( camera.matrixWorld );
48
49 _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
50
51 return vector.applyProjection( _viewProjectionMatrix );
52
53 };
54
55 this.unprojectVector = function () {
56
57 var projectionMatrixInverse = new THREE.Matrix4();
58
59 return function ( vector, camera ) {
60
61 projectionMatrixInverse.getInverse( camera.projectionMatrix );
62 _viewProjectionMatrix.multiplyMatrices( camera.matrixWorld, projectionMatrixInverse );
63
64 return vector.applyProjection( _viewProjectionMatrix );
65
66 };
67
68 }();
69
70 this.pickingRay = function ( vector, camera ) {
71
72 // set two vectors with opposing z values
73 vector.z = -1.0;
74 var end = new THREE.Vector3( vector.x, vector.y, 1.0 );
75
76 this.unprojectVector( vector, camera );
77 this.unprojectVector( end, camera );
78
79 // find direction from vector to end
80 end.sub( vector ).normalize();
81
82 return new THREE.Raycaster( vector, end );
83
84 };
85
86 var getObject = function ( object ) {
87
88 _object = getNextObjectInPool();
89 _object.id = object.id;
90 _object.object = object;
91
92 if ( object.renderDepth !== null ) {
93
94 _object.z = object.renderDepth;
95
96 } else {
97
98 _vector3.setFromMatrixPosition( object.matrixWorld );
99 _vector3.applyProjection( _viewProjectionMatrix );
100 _object.z = _vector3.z;
101
102 }
103
104 return _object;
105
106 };
107
108 var projectVertex = function ( vertex ) {
109
110 var position = vertex.position;
111 var positionWorld = vertex.positionWorld;
112 var positionScreen = vertex.positionScreen;
113
114 positionWorld.copy( position ).applyMatrix4( _modelMatrix );
115 positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix );
116
117 var invW = 1 / positionScreen.w;
118
119 positionScreen.x *= invW;
120 positionScreen.y *= invW;
121 positionScreen.z *= invW;
122
123 vertex.visible = positionScreen.x >= -1 && positionScreen.x <= 1 &&
124 positionScreen.y >= -1 && positionScreen.y <= 1 &&
125 positionScreen.z >= -1 && positionScreen.z <= 1;
126
127 };
128
129 var projectObject = function ( object ) {
130
131 if ( object.visible === false ) return;
132
133 if ( object instanceof THREE.Light ) {
134
135 _renderData.lights.push( object );
136
137 } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line ) {
138
139 if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {
140
141 _renderData.objects.push( getObject( object ) );
142
143 }
144
145 } else if ( object instanceof THREE.Sprite ) {
146
147 _renderData.sprites.push( getObject( object ) );
148
149 }
150
151 for ( var i = 0, l = object.children.length; i < l; i ++ ) {
152
153 projectObject( object.children[ i ] );
154
155 }
156
157 };
158
159 var projectGraph = function ( root, sortObjects ) {
160
161 _objectCount = 0;
162
163 _renderData.objects.length = 0;
164 _renderData.sprites.length = 0;
165 _renderData.lights.length = 0;
166
167 projectObject( root );
168
169 if ( sortObjects === true ) {
170
171 _renderData.objects.sort( painterSort );
172
173 }
174
175 };
176
177 this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
178
179 var visible = false,
180 object, geometry, vertices, faces, face, faceVertexNormals, faceVertexUvs, uvs,
181 v1, v2, v3, v4, isFaceMaterial, objectMaterials;
182
183 _face3Count = 0;
184 _lineCount = 0;
185 _spriteCount = 0;
186
187 _renderData.elements.length = 0;
188
189 if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
190 if ( camera.parent === undefined ) camera.updateMatrixWorld();
191
192 _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) );
193 _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
194
195 _normalViewMatrix.getNormalMatrix( _viewMatrix );
196
197 _frustum.setFromMatrix( _viewProjectionMatrix );
198
199 projectGraph( scene, sortObjects );
200
201 for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) {
202
203 object = _renderData.objects[ o ].object;
204
205 _modelMatrix = object.matrixWorld;
206
207 _vertexCount = 0;
208
209 if ( object instanceof THREE.Mesh ) {
210
211 geometry = object.geometry;
212
213 vertices = geometry.vertices;
214 faces = geometry.faces;
215 faceVertexUvs = geometry.faceVertexUvs;
216
217 _normalMatrix.getNormalMatrix( _modelMatrix );
218
219 isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
220 objectMaterials = isFaceMaterial === true ? object.material : null;
221
222 for ( var v = 0, vl = vertices.length; v < vl; v ++ ) {
223
224 _vertex = getNextVertexInPool();
225 _vertex.position.copy( vertices[ v ] );
226
227 projectVertex( _vertex );
228
229 }
230
231 for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
232
233 face = faces[ f ];
234
235 var material = isFaceMaterial === true
236 ? objectMaterials.materials[ face.materialIndex ]
237 : object.material;
238
239 if ( material === undefined ) continue;
240
241 var side = material.side;
242
243 v1 = _vertexPool[ face.a ];
244 v2 = _vertexPool[ face.b ];
245 v3 = _vertexPool[ face.c ];
246
247 if ( material.morphTargets === true ) {
248
249 var morphTargets = geometry.morphTargets;
250 var morphInfluences = object.morphTargetInfluences;
251
252 var v1p = v1.position;
253 var v2p = v2.position;
254 var v3p = v3.position;
255
256 _vA.set( 0, 0, 0 );
257 _vB.set( 0, 0, 0 );
258 _vC.set( 0, 0, 0 );
259
260 for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
261
262 var influence = morphInfluences[ t ];
263
264 if ( influence === 0 ) continue;
265
266 var targets = morphTargets[ t ].vertices;
267
268 _vA.x += ( targets[ face.a ].x - v1p.x ) * influence;
269 _vA.y += ( targets[ face.a ].y - v1p.y ) * influence;
270 _vA.z += ( targets[ face.a ].z - v1p.z ) * influence;
271
272 _vB.x += ( targets[ face.b ].x - v2p.x ) * influence;
273 _vB.y += ( targets[ face.b ].y - v2p.y ) * influence;
274 _vB.z += ( targets[ face.b ].z - v2p.z ) * influence;
275
276 _vC.x += ( targets[ face.c ].x - v3p.x ) * influence;
277 _vC.y += ( targets[ face.c ].y - v3p.y ) * influence;
278 _vC.z += ( targets[ face.c ].z - v3p.z ) * influence;
279
280 }
281
282 v1.position.add( _vA );
283 v2.position.add( _vB );
284 v3.position.add( _vC );
285
286 projectVertex( v1 );
287 projectVertex( v2 );
288 projectVertex( v3 );
289
290 }
291
292 _points3[ 0 ] = v1.positionScreen;
293 _points3[ 1 ] = v2.positionScreen;
294 _points3[ 2 ] = v3.positionScreen;
295
296 if ( v1.visible === true || v2.visible === true || v3.visible === true ||
297 _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ) ) {
298
299 visible = ( ( v3.positionScreen.x - v1.positionScreen.x ) *
300 ( v2.positionScreen.y - v1.positionScreen.y ) -
301 ( v3.positionScreen.y - v1.positionScreen.y ) *
302 ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;
303
304 if ( side === THREE.DoubleSide || visible === ( side === THREE.FrontSide ) ) {
305
306 _face = getNextFace3InPool();
307
308 _face.id = object.id;
309 _face.v1.copy( v1 );
310 _face.v2.copy( v2 );
311 _face.v3.copy( v3 );
312
313 } else {
314
315 continue;
316
317 }
318
319 } else {
320
321 continue;
322
323 }
324
325 _face.normalModel.copy( face.normal );
326
327 if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
328
329 _face.normalModel.negate();
330
331 }
332
333 _face.normalModel.applyMatrix3( _normalMatrix ).normalize();
334
335 _face.normalModelView.copy( _face.normalModel ).applyMatrix3( _normalViewMatrix );
336
337 _face.centroidModel.copy( face.centroid ).applyMatrix4( _modelMatrix );
338
339 faceVertexNormals = face.vertexNormals;
340
341 for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) {
342
343 var normalModel = _face.vertexNormalsModel[ n ];
344 normalModel.copy( faceVertexNormals[ n ] );
345
346 if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
347
348 normalModel.negate();
349
350 }
351
352 normalModel.applyMatrix3( _normalMatrix ).normalize();
353
354 var normalModelView = _face.vertexNormalsModelView[ n ];
355 normalModelView.copy( normalModel ).applyMatrix3( _normalViewMatrix );
356
357 }
358
359 _face.vertexNormalsLength = faceVertexNormals.length;
360
361 for ( var c = 0, cl = Math.min( faceVertexUvs.length, 3 ); c < cl; c ++ ) {
362
363 uvs = faceVertexUvs[ c ][ f ];
364
365 if ( uvs === undefined ) continue;
366
367 for ( var u = 0, ul = uvs.length; u < ul; u ++ ) {
368
369 _face.uvs[ c ][ u ] = uvs[ u ];
370
371 }
372
373 }
374
375 _face.color = face.color;
376 _face.material = material;
377
378 _centroid.copy( _face.centroidModel ).applyProjection( _viewProjectionMatrix );
379
380 _face.z = _centroid.z;
381
382 _renderData.elements.push( _face );
383
384 }
385
386 } else if ( object instanceof THREE.Line ) {
387
388 _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
389
390 vertices = object.geometry.vertices;
391
392 v1 = getNextVertexInPool();
393 v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix );
394
395 // Handle LineStrip and LinePieces
396 var step = object.type === THREE.LinePieces ? 2 : 1;
397
398 for ( v = 1, vl = vertices.length; v < vl; v ++ ) {
399
400 v1 = getNextVertexInPool();
401 v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix );
402
403 if ( ( v + 1 ) % step > 0 ) continue;
404
405 v2 = _vertexPool[ _vertexCount - 2 ];
406
407 _clippedVertex1PositionScreen.copy( v1.positionScreen );
408 _clippedVertex2PositionScreen.copy( v2.positionScreen );
409
410 if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) {
411
412 // Perform the perspective divide
413 _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );
414 _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );
415
416 _line = getNextLineInPool();
417
418 _line.id = object.id;
419 _line.v1.positionScreen.copy( _clippedVertex1PositionScreen );
420 _line.v2.positionScreen.copy( _clippedVertex2PositionScreen );
421
422 _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );
423
424 _line.material = object.material;
425
426 if ( object.material.vertexColors === THREE.VertexColors ) {
427
428 _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] );
429 _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] );
430
431 }
432
433 _renderData.elements.push( _line );
434
435 }
436
437 }
438
439 }
440
441 }
442
443 for ( o = 0, ol = _renderData.sprites.length; o < ol; o++ ) {
444
445 object = _renderData.sprites[ o ].object;
446
447 _modelMatrix = object.matrixWorld;
448
449 _vector4.set( _modelMatrix.elements[12], _modelMatrix.elements[13], _modelMatrix.elements[14], 1 );
450 _vector4.applyMatrix4( _viewProjectionMatrix );
451
452 var invW = 1 / _vector4.w;
453
454 _vector4.z *= invW;
455
456 if ( _vector4.z >= -1 && _vector4.z <= 1 ) {
457
458 _sprite = getNextSpriteInPool();
459 _sprite.id = object.id;
460 _sprite.x = _vector4.x * invW;
461 _sprite.y = _vector4.y * invW;
462 _sprite.z = _vector4.z;
463 _sprite.object = object;
464
465 _sprite.rotation = object.rotation;
466
467 _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) );
468 _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) );
469
470 _sprite.material = object.material;
471
472 _renderData.elements.push( _sprite );
473
474 }
475
476 }
477
478 if ( sortElements === true ) _renderData.elements.sort( painterSort );
479
480 return _renderData;
481
482 };
483
484 // Pools
485
486 function getNextObjectInPool() {
487
488 if ( _objectCount === _objectPoolLength ) {
489
490 var object = new THREE.RenderableObject();
491 _objectPool.push( object );
492 _objectPoolLength ++;
493 _objectCount ++;
494 return object;
495
496 }
497
498 return _objectPool[ _objectCount ++ ];
499
500 }
501
502 function getNextVertexInPool() {
503
504 if ( _vertexCount === _vertexPoolLength ) {
505
506 var vertex = new THREE.RenderableVertex();
507 _vertexPool.push( vertex );
508 _vertexPoolLength ++;
509 _vertexCount ++;
510 return vertex;
511
512 }
513
514 return _vertexPool[ _vertexCount ++ ];
515
516 }
517
518 function getNextFace3InPool() {
519
520 if ( _face3Count === _face3PoolLength ) {
521
522 var face = new THREE.RenderableFace3();
523 _face3Pool.push( face );
524 _face3PoolLength ++;
525 _face3Count ++;
526 return face;
527
528 }
529
530 return _face3Pool[ _face3Count ++ ];
531
532
533 }
534
535 function getNextLineInPool() {
536
537 if ( _lineCount === _linePoolLength ) {
538
539 var line = new THREE.RenderableLine();
540 _linePool.push( line );
541 _linePoolLength ++;
542 _lineCount ++
543 return line;
544
545 }
546
547 return _linePool[ _lineCount ++ ];
548
549 }
550
551 function getNextSpriteInPool() {
552
553 if ( _spriteCount === _spritePoolLength ) {
554
555 var sprite = new THREE.RenderableSprite();
556 _spritePool.push( sprite );
557 _spritePoolLength ++;
558 _spriteCount ++
559 return sprite;
560
561 }
562
563 return _spritePool[ _spriteCount ++ ];
564
565 }
566
567 //
568
569 function painterSort( a, b ) {
570
571 if ( a.z !== b.z ) {
572
573 return b.z - a.z;
574
575 } else if ( a.id !== b.id ) {
576
577 return a.id - b.id;
578
579 } else {
580
581 return 0;
582
583 }
584
585 }
586
587 function clipLine( s1, s2 ) {
588
589 var alpha1 = 0, alpha2 = 1,
590
591 // Calculate the boundary coordinate of each vertex for the near and far clip planes,
592 // Z = -1 and Z = +1, respectively.
593 bc1near = s1.z + s1.w,
594 bc2near = s2.z + s2.w,
595 bc1far = - s1.z + s1.w,
596 bc2far = - s2.z + s2.w;
597
598 if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {
599
600 // Both vertices lie entirely within all clip planes.
601 return true;
602
603 } else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) {
604
605 // Both vertices lie entirely outside one of the clip planes.
606 return false;
607
608 } else {
609
610 // The line segment spans at least one clip plane.
611
612 if ( bc1near < 0 ) {
613
614 // v1 lies outside the near plane, v2 inside
615 alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );
616
617 } else if ( bc2near < 0 ) {
618
619 // v2 lies outside the near plane, v1 inside
620 alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );
621
622 }
623
624 if ( bc1far < 0 ) {
625
626 // v1 lies outside the far plane, v2 inside
627 alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );
628
629 } else if ( bc2far < 0 ) {
630
631 // v2 lies outside the far plane, v2 inside
632 alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );
633
634 }
635
636 if ( alpha2 < alpha1 ) {
637
638 // The line segment spans two boundaries, but is outside both of them.
639 // (This can't happen when we're only clipping against just near/far but good
640 // to leave the check here for future usage if other clip planes are added.)
641 return false;
642
643 } else {
644
645 // Update the s1 and s2 vertices to match the clipped line segment.
646 s1.lerp( s2, alpha1 );
647 s2.lerp( s1, 1 - alpha2 );
648
649 return true;
650
651 }
652
653 }
654
655 }
656
657};
Note: See TracBrowser for help on using the repository browser.