source: other-projects/nz-flag-design/trunk/render-3d/Flag_files/Projector.js@ 29737

Last change on this file since 29737 was 29737, checked in by bmt11, 9 years ago

Added interaction with objects. May be able to use this to update flag in 3d rendering aswell as 2d

File size: 14.3 KB
Line 
1/**
2 * @author mr.doob / 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 = [],
10 _vertex, _vertexCount, _vertexPool = [],
11 _face, _face3Count, _face3Pool = [], _face4Count, _face4Pool = [],
12 _line, _lineCount, _linePool = [],
13 _particle, _particleCount, _particlePool = [],
14
15 _renderData = { objects: [], sprites: [], lights: [], elements: [] },
16
17 _vector3 = new THREE.Vector3(),
18 _vector4 = new THREE.Vector4(),
19
20 _projScreenMatrix = new THREE.Matrix4(),
21 _projScreenobjectMatrixWorld = new THREE.Matrix4(),
22
23 _frustum = [
24 new THREE.Vector4(),
25 new THREE.Vector4(),
26 new THREE.Vector4(),
27 new THREE.Vector4(),
28 new THREE.Vector4(),
29 new THREE.Vector4()
30 ],
31
32 _clippedVertex1PositionScreen = new THREE.Vector4(),
33 _clippedVertex2PositionScreen = new THREE.Vector4(),
34
35 _face3VertexNormals;
36
37 this.computeFrustum = function ( m ) {
38
39 _frustum[ 0 ].set( m.n41 - m.n11, m.n42 - m.n12, m.n43 - m.n13, m.n44 - m.n14 );
40 _frustum[ 1 ].set( m.n41 + m.n11, m.n42 + m.n12, m.n43 + m.n13, m.n44 + m.n14 );
41 _frustum[ 2 ].set( m.n41 + m.n21, m.n42 + m.n22, m.n43 + m.n23, m.n44 + m.n24 );
42 _frustum[ 3 ].set( m.n41 - m.n21, m.n42 - m.n22, m.n43 - m.n23, m.n44 - m.n24 );
43 _frustum[ 4 ].set( m.n41 - m.n31, m.n42 - m.n32, m.n43 - m.n33, m.n44 - m.n34 );
44 _frustum[ 5 ].set( m.n41 + m.n31, m.n42 + m.n32, m.n43 + m.n33, m.n44 + m.n34 );
45
46 for ( var i = 0; i < 6; i ++ ) {
47
48 var plane = _frustum[ i ];
49 plane.divideScalar( Math.sqrt( plane.x * plane.x + plane.y * plane.y + plane.z * plane.z ) );
50
51 }
52
53 }
54
55 this.projectVector = function ( vector, camera ) {
56
57 camera.matrixWorldInverse.getInverse( camera.matrixWorld );
58
59 _projScreenMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse );
60 _projScreenMatrix.multiplyVector3( vector );
61
62 return vector;
63
64 };
65
66 this.unprojectVector = function ( vector, camera ) {
67
68 camera.projectionMatrixInverse.getInverse( camera.projectionMatrix );
69
70 _projScreenMatrix.multiply( camera.matrixWorld, camera.projectionMatrixInverse );
71 _projScreenMatrix.multiplyVector3( vector );
72
73 return vector;
74
75 };
76
77 /**
78 * Translates a 2D point from NDC to a THREE.Ray
79 * that can be used for picking.
80 * @vector - THREE.Vector3 that represents 2D point
81 * @camera - THREE.Camera
82 */
83 this.pickingRay = function ( vector, camera ) {
84
85 var end, ray, t;
86
87 // set two vectors with opposing z values
88 vector.z = -1.0;
89 end = new THREE.Vector3( vector.x, vector.y, 1.0 );
90
91 this.unprojectVector( vector, camera );
92 this.unprojectVector( end, camera );
93
94 // find direction from vector to end
95 end.subSelf( vector ).normalize();
96
97 return new THREE.Ray( vector, end );
98
99 };
100
101 this.projectGraph = function ( root, sort ) {
102
103 _objectCount = 0;
104
105 _renderData.objects.length = 0;
106 _renderData.sprites.length = 0;
107 _renderData.lights.length = 0;
108
109 var projectObject = function ( object ) {
110
111 if ( object.visible === false ) return;
112
113 if ( ( object instanceof THREE.Mesh || object instanceof THREE.Line ) &&
114 ( object.frustumCulled === false || isInFrustum( object ) ) ) {
115
116 _projScreenMatrix.multiplyVector3( _vector3.copy( object.position ) );
117
118 _object = getNextObjectInPool();
119 _object.object = object;
120 _object.z = _vector3.z;
121
122 _renderData.objects.push( _object );
123
124 } else if ( object instanceof THREE.Sprite || object instanceof THREE.Particle ) {
125
126 _projScreenMatrix.multiplyVector3( _vector3.copy( object.position ) );
127
128 _object = getNextObjectInPool();
129 _object.object = object;
130 _object.z = _vector3.z;
131
132 _renderData.sprites.push( _object );
133
134 } else if ( object instanceof THREE.Light ) {
135
136 _renderData.lights.push( object );
137
138 }
139
140 for ( var c = 0, cl = object.children.length; c < cl; c ++ ) {
141
142 projectObject( object.children[ c ] );
143
144 }
145
146 };
147
148 projectObject( root );
149
150 sort && _renderData.objects.sort( painterSort );
151
152 return _renderData;
153
154 };
155
156 this.projectScene = function ( scene, camera, sort ) {
157
158 var near = camera.near, far = camera.far,
159 o, ol, v, vl, f, fl, n, nl, c, cl, u, ul, object,
160 objectMatrixWorld, objectMatrixWorldRotation, objectMaterial,
161 geometry, geometryMaterials, vertices, vertex, vertexPositionScreen,
162 faces, face, faceVertexNormals, normal, faceVertexUvs, uvs,
163 v1, v2, v3, v4;
164
165 _face3Count = 0;
166 _face4Count = 0;
167 _lineCount = 0;
168 _particleCount = 0;
169
170 _renderData.elements.length = 0;
171
172 if ( camera.parent === undefined ) {
173
174 console.warn( 'DEPRECATED: Camera hasn\'t been added to a Scene. Adding it...' );
175 scene.add( camera );
176
177 }
178
179 scene.updateMatrixWorld();
180
181 camera.matrixWorldInverse.getInverse( camera.matrixWorld );
182
183 _projScreenMatrix.multiply( camera.projectionMatrix, camera.matrixWorldInverse );
184
185 this.computeFrustum( _projScreenMatrix );
186
187 _renderData = this.projectGraph( scene, false );
188
189 for ( o = 0, ol = _renderData.objects.length; o < ol; o++ ) {
190
191 object = _renderData.objects[ o ].object;
192
193 objectMatrixWorld = object.matrixWorld;
194 objectMaterial = object.material;
195
196 _vertexCount = 0;
197
198 if ( object instanceof THREE.Mesh ) {
199
200 geometry = object.geometry;
201 geometryMaterials = object.geometry.materials;
202 vertices = geometry.vertices;
203 faces = geometry.faces;
204 faceVertexUvs = geometry.faceVertexUvs;
205
206 objectMatrixWorldRotation = object.matrixRotationWorld.extractRotation( objectMatrixWorld );
207
208 for ( v = 0, vl = vertices.length; v < vl; v ++ ) {
209
210 _vertex = getNextVertexInPool();
211 _vertex.positionWorld.copy( vertices[ v ].position );
212
213 objectMatrixWorld.multiplyVector3( _vertex.positionWorld );
214
215 _vertex.positionScreen.copy( _vertex.positionWorld );
216 _projScreenMatrix.multiplyVector4( _vertex.positionScreen );
217
218 _vertex.positionScreen.x /= _vertex.positionScreen.w;
219 _vertex.positionScreen.y /= _vertex.positionScreen.w;
220
221 _vertex.visible = _vertex.positionScreen.z > near && _vertex.positionScreen.z < far;
222
223 }
224
225 for ( f = 0, fl = faces.length; f < fl; f ++ ) {
226
227 face = faces[ f ];
228
229 if ( face instanceof THREE.Face3 ) {
230
231 v1 = _vertexPool[ face.a ];
232 v2 = _vertexPool[ face.b ];
233 v3 = _vertexPool[ face.c ];
234
235 if ( v1.visible && v2.visible && v3.visible &&
236 ( object.doubleSided || ( object.flipSided !=
237 ( v3.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) -
238 ( v3.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) < 0 ) ) ) {
239
240 _face = getNextFace3InPool();
241
242 _face.v1.copy( v1 );
243 _face.v2.copy( v2 );
244 _face.v3.copy( v3 );
245
246 } else {
247
248 continue;
249
250 }
251
252 } else if ( face instanceof THREE.Face4 ) {
253
254 v1 = _vertexPool[ face.a ];
255 v2 = _vertexPool[ face.b ];
256 v3 = _vertexPool[ face.c ];
257 v4 = _vertexPool[ face.d ];
258
259 if ( v1.visible && v2.visible && v3.visible && v4.visible &&
260 ( object.doubleSided || ( object.flipSided !=
261 ( ( v4.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) -
262 ( v4.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) < 0 ||
263 ( v2.positionScreen.x - v3.positionScreen.x ) * ( v4.positionScreen.y - v3.positionScreen.y ) -
264 ( v2.positionScreen.y - v3.positionScreen.y ) * ( v4.positionScreen.x - v3.positionScreen.x ) < 0 ) ) ) ) {
265
266 _face = getNextFace4InPool();
267
268 _face.v1.copy( v1 );
269 _face.v2.copy( v2 );
270 _face.v3.copy( v3 );
271 _face.v4.copy( v4 );
272
273 } else {
274
275 continue;
276
277 }
278
279 }
280
281 _face.normalWorld.copy( face.normal );
282 objectMatrixWorldRotation.multiplyVector3( _face.normalWorld );
283
284 _face.centroidWorld.copy( face.centroid );
285 objectMatrixWorld.multiplyVector3( _face.centroidWorld );
286
287 _face.centroidScreen.copy( _face.centroidWorld );
288 _projScreenMatrix.multiplyVector3( _face.centroidScreen );
289
290 faceVertexNormals = face.vertexNormals;
291
292 for ( n = 0, nl = faceVertexNormals.length; n < nl; n ++ ) {
293
294 normal = _face.vertexNormalsWorld[ n ];
295 normal.copy( faceVertexNormals[ n ] );
296 objectMatrixWorldRotation.multiplyVector3( normal );
297
298 }
299
300 for ( c = 0, cl = faceVertexUvs.length; c < cl; c ++ ) {
301
302 uvs = faceVertexUvs[ c ][ f ];
303
304 if ( !uvs ) continue;
305
306 for ( u = 0, ul = uvs.length; u < ul; u ++ ) {
307
308 _face.uvs[ c ][ u ] = uvs[ u ];
309
310 }
311
312 }
313
314 _face.material = objectMaterial;
315 _face.faceMaterial = face.materialIndex !== null ? geometryMaterials[ face.materialIndex ] : null;
316
317 _face.z = _face.centroidScreen.z;
318
319 _renderData.elements.push( _face );
320
321 }
322
323 } else if ( object instanceof THREE.Line ) {
324
325 _projScreenobjectMatrixWorld.multiply( _projScreenMatrix, objectMatrixWorld );
326
327 vertices = object.geometry.vertices;
328
329 v1 = getNextVertexInPool();
330 v1.positionScreen.copy( vertices[ 0 ].position );
331 _projScreenobjectMatrixWorld.multiplyVector4( v1.positionScreen );
332
333 for ( v = 1, vl = vertices.length; v < vl; v++ ) {
334
335 v1 = getNextVertexInPool();
336 v1.positionScreen.copy( vertices[ v ].position );
337 _projScreenobjectMatrixWorld.multiplyVector4( v1.positionScreen );
338
339 v2 = _vertexPool[ _vertexCount - 2 ];
340
341 _clippedVertex1PositionScreen.copy( v1.positionScreen );
342 _clippedVertex2PositionScreen.copy( v2.positionScreen );
343
344 if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) ) {
345
346 // Perform the perspective divide
347 _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );
348 _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );
349
350 _line = getNextLineInPool();
351 _line.v1.positionScreen.copy( _clippedVertex1PositionScreen );
352 _line.v2.positionScreen.copy( _clippedVertex2PositionScreen );
353
354 _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );
355
356 _line.material = objectMaterial;
357
358 _renderData.elements.push( _line );
359
360 }
361
362 }
363
364 }
365
366 }
367
368 for ( o = 0, ol = _renderData.sprites.length; o < ol; o++ ) {
369
370 object = _renderData.sprites[ o ].object;
371
372 objectMatrixWorld = object.matrixWorld;
373
374 if ( object instanceof THREE.Particle ) {
375
376 _vector4.set( objectMatrixWorld.n14, objectMatrixWorld.n24, objectMatrixWorld.n34, 1 );
377 _projScreenMatrix.multiplyVector4( _vector4 );
378
379 _vector4.z /= _vector4.w;
380
381 if ( _vector4.z > 0 && _vector4.z < 1 ) {
382
383 _particle = getNextParticleInPool();
384 _particle.x = _vector4.x / _vector4.w;
385 _particle.y = _vector4.y / _vector4.w;
386 _particle.z = _vector4.z;
387
388 _particle.rotation = object.rotation.z;
389
390 _particle.scale.x = object.scale.x * Math.abs( _particle.x - ( _vector4.x + camera.projectionMatrix.n11 ) / ( _vector4.w + camera.projectionMatrix.n14 ) );
391 _particle.scale.y = object.scale.y * Math.abs( _particle.y - ( _vector4.y + camera.projectionMatrix.n22 ) / ( _vector4.w + camera.projectionMatrix.n24 ) );
392
393 _particle.material = object.material;
394
395 _renderData.elements.push( _particle );
396
397 }
398
399 }
400
401 }
402
403 sort && _renderData.elements.sort( painterSort );
404
405 return _renderData;
406
407 };
408
409 // Pools
410
411 function getNextObjectInPool() {
412
413 var object = _objectPool[ _objectCount ] = _objectPool[ _objectCount ] || new THREE.RenderableObject();
414
415 _objectCount ++;
416
417 return object;
418
419 }
420
421 function getNextVertexInPool() {
422
423 var vertex = _vertexPool[ _vertexCount ] = _vertexPool[ _vertexCount ] || new THREE.RenderableVertex();
424
425 _vertexCount ++;
426
427 return vertex;
428
429 }
430
431 function getNextFace3InPool() {
432
433 var face = _face3Pool[ _face3Count ] = _face3Pool[ _face3Count ] || new THREE.RenderableFace3();
434
435 _face3Count ++;
436
437 return face;
438
439 }
440
441 function getNextFace4InPool() {
442
443 var face = _face4Pool[ _face4Count ] = _face4Pool[ _face4Count ] || new THREE.RenderableFace4();
444
445 _face4Count ++;
446
447 return face;
448
449 }
450
451 function getNextLineInPool() {
452
453 var line = _linePool[ _lineCount ] = _linePool[ _lineCount ] || new THREE.RenderableLine();
454
455 _lineCount ++;
456
457 return line;
458
459 }
460
461 function getNextParticleInPool() {
462
463 var particle = _particlePool[ _particleCount ] = _particlePool[ _particleCount ] || new THREE.RenderableParticle();
464 _particleCount ++;
465 return particle;
466
467 }
468
469 //
470
471 function painterSort( a, b ) {
472
473 return b.z - a.z;
474
475 }
476
477 function isInFrustum( object ) {
478
479 var distance, matrix = object.matrixWorld,
480 radius = - object.geometry.boundingSphere.radius * Math.max( object.scale.x, Math.max( object.scale.y, object.scale.z ) );
481
482 for ( var i = 0; i < 6; i ++ ) {
483
484 distance = _frustum[ i ].x * matrix.n14 + _frustum[ i ].y * matrix.n24 + _frustum[ i ].z * matrix.n34 + _frustum[ i ].w;
485 if ( distance <= radius ) return false;
486
487 }
488
489 return true;
490
491 };
492
493 function clipLine( s1, s2 ) {
494
495 var alpha1 = 0, alpha2 = 1,
496
497 // Calculate the boundary coordinate of each vertex for the near and far clip planes,
498 // Z = -1 and Z = +1, respectively.
499 bc1near = s1.z + s1.w,
500 bc2near = s2.z + s2.w,
501 bc1far = - s1.z + s1.w,
502 bc2far = - s2.z + s2.w;
503
504 if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {
505
506 // Both vertices lie entirely within all clip planes.
507 return true;
508
509 } else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) {
510
511 // Both vertices lie entirely outside one of the clip planes.
512 return false;
513
514 } else {
515
516 // The line segment spans at least one clip plane.
517
518 if ( bc1near < 0 ) {
519
520 // v1 lies outside the near plane, v2 inside
521 alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );
522
523 } else if ( bc2near < 0 ) {
524
525 // v2 lies outside the near plane, v1 inside
526 alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );
527
528 }
529
530 if ( bc1far < 0 ) {
531
532 // v1 lies outside the far plane, v2 inside
533 alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );
534
535 } else if ( bc2far < 0 ) {
536
537 // v2 lies outside the far plane, v2 inside
538 alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );
539
540 }
541
542 if ( alpha2 < alpha1 ) {
543
544 // The line segment spans two boundaries, but is outside both of them.
545 // (This can't happen when we're only clipping against just near/far but good
546 // to leave the check here for future usage if other clip planes are added.)
547 return false;
548
549 } else {
550
551 // Update the s1 and s2 vertices to match the clipped line segment.
552 s1.lerpSelf( s2, alpha1 );
553 s2.lerpSelf( s1, 1 - alpha2 );
554
555 return true;
556
557 }
558
559 }
560
561 }
562
563};
Note: See TracBrowser for help on using the repository browser.