240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
376 |
377 |
378 |
379 |
380 |
--------------------------------------------------------------------------------
/AlexNet.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
15 |
81 |
82 |
83 |
84 |
85 |
99 |
100 |
101 |
102 |
103 |
Style:
104 |
105 |
Renderer
106 |
107 |
108 | webGL
109 |
110 |
111 |
112 |
113 | SVG
114 |
115 |
116 |
The SVG renderer is required to download SVG, however the WebGL renderer is required to show tensor dimensions.
117 |
118 |
119 |
120 |
121 |
122 | Color 1
123 |
124 |
125 |
126 | Color 2
127 |
128 |
129 |
130 | Color 3
131 |
132 |
133 | Tensor Opacity
134 |
135 |
136 |
137 |
138 | Filter Opacity
139 |
140 |
141 |
145 |
146 | Spacing Between Layers
147 |
148 |
149 |
150 |
151 |
152 |
153 | Log Feature-Map Depth Scaling
154 |
155 |
156 | Depth Size Scaling
157 |
158 | 10
159 |
160 |
161 |
162 | Log Feature-Map Width Scaling
163 |
164 |
165 | Width Size Scaling
166 |
167 | 10
168 |
169 |
170 |
171 | Log Convolutional Filter Size Scaling
172 |
173 |
174 | Convolutional Filter Scaling
175 |
176 | 1
177 |
178 |
179 |
180 |
181 |
182 | Show Tensor Dimensions
183 |
184 |
185 |
186 | Show Conv Dimensions
187 |
188 |
189 |
190 |
Architecture:
191 |
192 |
Height | Width | Depth | filter Height | filter Width
193 |
203 |
213 |
223 |
233 |
243 |
253 |
263 |
264 |
265 |
266 |
267 |
Vector Length
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
462 |
463 |
464 |
465 |
466 |
--------------------------------------------------------------------------------
/OrbitControls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author qiao / https://github.com/qiao
3 | * @author mrdoob / http://mrdoob.com
4 | * @author alteredq / http://alteredqualia.com/
5 | * @author WestLangley / http://github.com/WestLangley
6 | * @author erich666 / http://erichaines.com
7 | */
8 |
9 | // This set of controls performs orbiting, dollying (zooming), and panning.
10 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
11 | //
12 | // Orbit - left mouse / touch: one-finger move
13 | // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
14 | // Pan - right mouse, or arrow keys / touch: two-finger move
15 |
16 | THREE.OrbitControls = function ( object, domElement ) {
17 |
18 | this.object = object;
19 |
20 | this.domElement = ( domElement !== undefined ) ? domElement : document;
21 |
22 | // Set to false to disable this control
23 | this.enabled = true;
24 |
25 | // "target" sets the location of focus, where the object orbits around
26 | this.target = new THREE.Vector3();
27 |
28 | // How far you can dolly in and out ( PerspectiveCamera only )
29 | this.minDistance = 0;
30 | this.maxDistance = Infinity;
31 |
32 | // How far you can zoom in and out ( OrthographicCamera only )
33 | this.minZoom = 0;
34 | this.maxZoom = Infinity;
35 |
36 | // How far you can orbit vertically, upper and lower limits.
37 | // Range is 0 to Math.PI radians.
38 | this.minPolarAngle = 0; // radians
39 | this.maxPolarAngle = Math.PI; // radians
40 |
41 | // How far you can orbit horizontally, upper and lower limits.
42 | // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
43 | this.minAzimuthAngle = - Infinity; // radians
44 | this.maxAzimuthAngle = Infinity; // radians
45 |
46 | // Set to true to enable damping (inertia)
47 | // If damping is enabled, you must call controls.update() in your animation loop
48 | this.enableDamping = false;
49 | this.dampingFactor = 0.25;
50 |
51 | // This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
52 | // Set to false to disable zooming
53 | this.enableZoom = true;
54 | this.zoomSpeed = 1.0;
55 |
56 | // Set to false to disable rotating
57 | this.enableRotate = true;
58 | this.rotateSpeed = 1.0;
59 |
60 | // Set to false to disable panning
61 | this.enablePan = true;
62 | this.panSpeed = 1.0;
63 | this.screenSpacePanning = false; // if true, pan in screen-space
64 | this.keyPanSpeed = 20.0; // pixels moved per arrow key push
65 |
66 | // Set to true to automatically rotate around the target
67 | // If auto-rotate is enabled, you must call controls.update() in your animation loop
68 | this.autoRotate = false;
69 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
70 |
71 | // Set to false to disable use of the keys
72 | this.enableKeys = true;
73 |
74 | // The four arrow keys
75 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
76 |
77 | // Mouse buttons
78 | this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };
79 |
80 | // for reset
81 | this.target0 = this.target.clone();
82 | this.position0 = this.object.position.clone();
83 | this.zoom0 = this.object.zoom;
84 |
85 | //
86 | // public methods
87 | //
88 |
89 | this.getPolarAngle = function () {
90 |
91 | return spherical.phi;
92 |
93 | };
94 |
95 | this.getAzimuthalAngle = function () {
96 |
97 | return spherical.theta;
98 |
99 | };
100 |
101 | this.saveState = function () {
102 |
103 | scope.target0.copy( scope.target );
104 | scope.position0.copy( scope.object.position );
105 | scope.zoom0 = scope.object.zoom;
106 |
107 | };
108 |
109 | this.reset = function () {
110 |
111 | scope.target.copy( scope.target0 );
112 | scope.object.position.copy( scope.position0 );
113 | scope.object.zoom = scope.zoom0;
114 |
115 | scope.object.updateProjectionMatrix();
116 | scope.dispatchEvent( changeEvent );
117 |
118 | scope.update();
119 |
120 | state = STATE.NONE;
121 |
122 | };
123 |
124 | // this method is exposed, but perhaps it would be better if we can make it private...
125 | this.update = function () {
126 |
127 | var offset = new THREE.Vector3();
128 |
129 | // so camera.up is the orbit axis
130 | var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
131 | var quatInverse = quat.clone().inverse();
132 |
133 | var lastPosition = new THREE.Vector3();
134 | var lastQuaternion = new THREE.Quaternion();
135 |
136 | return function update() {
137 |
138 | var position = scope.object.position;
139 |
140 | offset.copy( position ).sub( scope.target );
141 |
142 | // rotate offset to "y-axis-is-up" space
143 | offset.applyQuaternion( quat );
144 |
145 | // angle from z-axis around y-axis
146 | spherical.setFromVector3( offset );
147 |
148 | if ( scope.autoRotate && state === STATE.NONE ) {
149 |
150 | rotateLeft( getAutoRotationAngle() );
151 |
152 | }
153 |
154 | spherical.theta += sphericalDelta.theta;
155 | spherical.phi += sphericalDelta.phi;
156 |
157 | // restrict theta to be between desired limits
158 | spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) );
159 |
160 | // restrict phi to be between desired limits
161 | spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );
162 |
163 | spherical.makeSafe();
164 |
165 |
166 | spherical.radius *= scale;
167 |
168 | // restrict radius to be between desired limits
169 | spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) );
170 |
171 | // move target to panned location
172 | scope.target.add( panOffset );
173 |
174 | offset.setFromSpherical( spherical );
175 |
176 | // rotate offset back to "camera-up-vector-is-up" space
177 | offset.applyQuaternion( quatInverse );
178 |
179 | position.copy( scope.target ).add( offset );
180 |
181 | scope.object.lookAt( scope.target );
182 |
183 | if ( scope.enableDamping === true ) {
184 |
185 | sphericalDelta.theta *= ( 1 - scope.dampingFactor );
186 | sphericalDelta.phi *= ( 1 - scope.dampingFactor );
187 |
188 | panOffset.multiplyScalar( 1 - scope.dampingFactor );
189 |
190 | } else {
191 |
192 | sphericalDelta.set( 0, 0, 0 );
193 |
194 | panOffset.set( 0, 0, 0 );
195 |
196 | }
197 |
198 | scale = 1;
199 |
200 | // update condition is:
201 | // min(camera displacement, camera rotation in radians)^2 > EPS
202 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8
203 |
204 | if ( zoomChanged ||
205 | lastPosition.distanceToSquared( scope.object.position ) > EPS ||
206 | 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) {
207 |
208 | scope.dispatchEvent( changeEvent );
209 |
210 | lastPosition.copy( scope.object.position );
211 | lastQuaternion.copy( scope.object.quaternion );
212 | zoomChanged = false;
213 |
214 | return true;
215 |
216 | }
217 |
218 | return false;
219 |
220 | };
221 |
222 | }();
223 |
224 | this.dispose = function () {
225 |
226 | scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false );
227 | scope.domElement.removeEventListener( 'mousedown', onMouseDown, false );
228 | scope.domElement.removeEventListener( 'wheel', onMouseWheel, false );
229 |
230 | scope.domElement.removeEventListener( 'touchstart', onTouchStart, false );
231 | scope.domElement.removeEventListener( 'touchend', onTouchEnd, false );
232 | scope.domElement.removeEventListener( 'touchmove', onTouchMove, false );
233 |
234 | document.removeEventListener( 'mousemove', onMouseMove, false );
235 | document.removeEventListener( 'mouseup', onMouseUp, false );
236 |
237 | window.removeEventListener( 'keydown', onKeyDown, false );
238 |
239 | //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
240 |
241 | };
242 |
243 | //
244 | // internals
245 | //
246 |
247 | var scope = this;
248 |
249 | var changeEvent = { type: 'change' };
250 | var startEvent = { type: 'start' };
251 | var endEvent = { type: 'end' };
252 |
253 | var STATE = { NONE: - 1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY_PAN: 4 };
254 |
255 | var state = STATE.NONE;
256 |
257 | var EPS = 0.000001;
258 |
259 | // current position in spherical coordinates
260 | var spherical = new THREE.Spherical();
261 | var sphericalDelta = new THREE.Spherical();
262 |
263 | var scale = 1;
264 | var panOffset = new THREE.Vector3();
265 | var zoomChanged = false;
266 |
267 | var rotateStart = new THREE.Vector2();
268 | var rotateEnd = new THREE.Vector2();
269 | var rotateDelta = new THREE.Vector2();
270 |
271 | var panStart = new THREE.Vector2();
272 | var panEnd = new THREE.Vector2();
273 | var panDelta = new THREE.Vector2();
274 |
275 | var dollyStart = new THREE.Vector2();
276 | var dollyEnd = new THREE.Vector2();
277 | var dollyDelta = new THREE.Vector2();
278 |
279 | function getAutoRotationAngle() {
280 |
281 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
282 |
283 | }
284 |
285 | function getZoomScale() {
286 |
287 | return Math.pow( 0.95, scope.zoomSpeed );
288 |
289 | }
290 |
291 | function rotateLeft( angle ) {
292 |
293 | sphericalDelta.theta -= angle;
294 |
295 | }
296 |
297 | function rotateUp( angle ) {
298 |
299 | sphericalDelta.phi -= angle;
300 |
301 | }
302 |
303 | var panLeft = function () {
304 |
305 | var v = new THREE.Vector3();
306 |
307 | return function panLeft( distance, objectMatrix ) {
308 |
309 | v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix
310 | v.multiplyScalar( - distance );
311 |
312 | panOffset.add( v );
313 |
314 | };
315 |
316 | }();
317 |
318 | var panUp = function () {
319 |
320 | var v = new THREE.Vector3();
321 |
322 | return function panUp( distance, objectMatrix ) {
323 |
324 | if ( scope.screenSpacePanning === true ) {
325 |
326 | v.setFromMatrixColumn( objectMatrix, 1 );
327 |
328 | } else {
329 |
330 | v.setFromMatrixColumn( objectMatrix, 0 );
331 | v.crossVectors( scope.object.up, v );
332 |
333 | }
334 |
335 | v.multiplyScalar( distance );
336 |
337 | panOffset.add( v );
338 |
339 | };
340 |
341 | }();
342 |
343 | // deltaX and deltaY are in pixels; right and down are positive
344 | var pan = function () {
345 |
346 | var offset = new THREE.Vector3();
347 |
348 | return function pan( deltaX, deltaY ) {
349 |
350 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
351 |
352 | if ( scope.object.isPerspectiveCamera ) {
353 |
354 | // perspective
355 | var position = scope.object.position;
356 | offset.copy( position ).sub( scope.target );
357 | var targetDistance = offset.length();
358 |
359 | // half of the fov is center to top of screen
360 | targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
361 |
362 | // we use only clientHeight here so aspect ratio does not distort speed
363 | panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );
364 | panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );
365 |
366 | } else if ( scope.object.isOrthographicCamera ) {
367 |
368 | // orthographic
369 | panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );
370 | panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );
371 |
372 | } else {
373 |
374 | // camera neither orthographic nor perspective
375 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
376 | scope.enablePan = false;
377 |
378 | }
379 |
380 | };
381 |
382 | }();
383 |
384 | function dollyIn( dollyScale ) {
385 |
386 | if ( scope.object.isPerspectiveCamera ) {
387 |
388 | scale /= dollyScale;
389 |
390 | } else if ( scope.object.isOrthographicCamera ) {
391 |
392 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) );
393 | scope.object.updateProjectionMatrix();
394 | zoomChanged = true;
395 |
396 | } else {
397 |
398 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
399 | scope.enableZoom = false;
400 |
401 | }
402 |
403 | }
404 |
405 | function dollyOut( dollyScale ) {
406 |
407 | if ( scope.object.isPerspectiveCamera ) {
408 |
409 | scale *= dollyScale;
410 |
411 | } else if ( scope.object.isOrthographicCamera ) {
412 |
413 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) );
414 | scope.object.updateProjectionMatrix();
415 | zoomChanged = true;
416 |
417 | } else {
418 |
419 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
420 | scope.enableZoom = false;
421 |
422 | }
423 |
424 | }
425 |
426 | //
427 | // event callbacks - update the object state
428 | //
429 |
430 | function handleMouseDownRotate( event ) {
431 |
432 | //console.log( 'handleMouseDownRotate' );
433 |
434 | rotateStart.set( event.clientX, event.clientY );
435 |
436 | }
437 |
438 | function handleMouseDownDolly( event ) {
439 |
440 | //console.log( 'handleMouseDownDolly' );
441 |
442 | dollyStart.set( event.clientX, event.clientY );
443 |
444 | }
445 |
446 | function handleMouseDownPan( event ) {
447 |
448 | //console.log( 'handleMouseDownPan' );
449 |
450 | panStart.set( event.clientX, event.clientY );
451 |
452 | }
453 |
454 | function handleMouseMoveRotate( event ) {
455 |
456 | //console.log( 'handleMouseMoveRotate' );
457 |
458 | rotateEnd.set( event.clientX, event.clientY );
459 |
460 | rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
461 |
462 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
463 |
464 | // rotating across whole screen goes 360 degrees around
465 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth );
466 |
467 | // rotating up and down along whole screen attempts to go 360, but limited to 180
468 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
469 |
470 | rotateStart.copy( rotateEnd );
471 |
472 | scope.update();
473 |
474 | }
475 |
476 | function handleMouseMoveDolly( event ) {
477 |
478 | //console.log( 'handleMouseMoveDolly' );
479 |
480 | dollyEnd.set( event.clientX, event.clientY );
481 |
482 | dollyDelta.subVectors( dollyEnd, dollyStart );
483 |
484 | if ( dollyDelta.y > 0 ) {
485 |
486 | dollyIn( getZoomScale() );
487 |
488 | } else if ( dollyDelta.y < 0 ) {
489 |
490 | dollyOut( getZoomScale() );
491 |
492 | }
493 |
494 | dollyStart.copy( dollyEnd );
495 |
496 | scope.update();
497 |
498 | }
499 |
500 | function handleMouseMovePan( event ) {
501 |
502 | //console.log( 'handleMouseMovePan' );
503 |
504 | panEnd.set( event.clientX, event.clientY );
505 |
506 | panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
507 |
508 | pan( panDelta.x, panDelta.y );
509 |
510 | panStart.copy( panEnd );
511 |
512 | scope.update();
513 |
514 | }
515 |
516 | function handleMouseUp( event ) {
517 |
518 | // console.log( 'handleMouseUp' );
519 |
520 | }
521 |
522 | function handleMouseWheel( event ) {
523 |
524 | // console.log( 'handleMouseWheel' );
525 |
526 | if ( event.deltaY < 0 ) {
527 |
528 | dollyOut( getZoomScale() );
529 |
530 | } else if ( event.deltaY > 0 ) {
531 |
532 | dollyIn( getZoomScale() );
533 |
534 | }
535 |
536 | scope.update();
537 |
538 | }
539 |
540 | function handleKeyDown( event ) {
541 |
542 | //console.log( 'handleKeyDown' );
543 |
544 | switch ( event.keyCode ) {
545 |
546 | case scope.keys.UP:
547 | pan( 0, scope.keyPanSpeed );
548 | scope.update();
549 | break;
550 |
551 | case scope.keys.BOTTOM:
552 | pan( 0, - scope.keyPanSpeed );
553 | scope.update();
554 | break;
555 |
556 | case scope.keys.LEFT:
557 | pan( scope.keyPanSpeed, 0 );
558 | scope.update();
559 | break;
560 |
561 | case scope.keys.RIGHT:
562 | pan( - scope.keyPanSpeed, 0 );
563 | scope.update();
564 | break;
565 |
566 | }
567 |
568 | }
569 |
570 | function handleTouchStartRotate( event ) {
571 |
572 | //console.log( 'handleTouchStartRotate' );
573 |
574 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
575 |
576 | }
577 |
578 | function handleTouchStartDollyPan( event ) {
579 |
580 | //console.log( 'handleTouchStartDollyPan' );
581 |
582 | if ( scope.enableZoom ) {
583 |
584 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
585 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
586 |
587 | var distance = Math.sqrt( dx * dx + dy * dy );
588 |
589 | dollyStart.set( 0, distance );
590 |
591 | }
592 |
593 | if ( scope.enablePan ) {
594 |
595 | var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
596 | var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
597 |
598 | panStart.set( x, y );
599 |
600 | }
601 |
602 | }
603 |
604 | function handleTouchMoveRotate( event ) {
605 |
606 | //console.log( 'handleTouchMoveRotate' );
607 |
608 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
609 |
610 | rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
611 |
612 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
613 |
614 | // rotating across whole screen goes 360 degrees around
615 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth );
616 |
617 | // rotating up and down along whole screen attempts to go 360, but limited to 180
618 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
619 |
620 | rotateStart.copy( rotateEnd );
621 |
622 | scope.update();
623 |
624 | }
625 |
626 | function handleTouchMoveDollyPan( event ) {
627 |
628 | //console.log( 'handleTouchMoveDollyPan' );
629 |
630 | if ( scope.enableZoom ) {
631 |
632 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
633 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
634 |
635 | var distance = Math.sqrt( dx * dx + dy * dy );
636 |
637 | dollyEnd.set( 0, distance );
638 |
639 | dollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) );
640 |
641 | dollyIn( dollyDelta.y );
642 |
643 | dollyStart.copy( dollyEnd );
644 |
645 | }
646 |
647 | if ( scope.enablePan ) {
648 |
649 | var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
650 | var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
651 |
652 | panEnd.set( x, y );
653 |
654 | panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
655 |
656 | pan( panDelta.x, panDelta.y );
657 |
658 | panStart.copy( panEnd );
659 |
660 | }
661 |
662 | scope.update();
663 |
664 | }
665 |
666 | function handleTouchEnd( event ) {
667 |
668 | //console.log( 'handleTouchEnd' );
669 |
670 | }
671 |
672 | //
673 | // event handlers - FSM: listen for events and reset state
674 | //
675 |
676 | function onMouseDown( event ) {
677 |
678 | if ( scope.enabled === false ) return;
679 |
680 | event.preventDefault();
681 |
682 | switch ( event.button ) {
683 |
684 | case scope.mouseButtons.ORBIT:
685 |
686 | if ( scope.enableRotate === false ) return;
687 |
688 | handleMouseDownRotate( event );
689 |
690 | state = STATE.ROTATE;
691 |
692 | break;
693 |
694 | case scope.mouseButtons.ZOOM:
695 |
696 | if ( scope.enableZoom === false ) return;
697 |
698 | handleMouseDownDolly( event );
699 |
700 | state = STATE.DOLLY;
701 |
702 | break;
703 |
704 | case scope.mouseButtons.PAN:
705 |
706 | if ( scope.enablePan === false ) return;
707 |
708 | handleMouseDownPan( event );
709 |
710 | state = STATE.PAN;
711 |
712 | break;
713 |
714 | }
715 |
716 | if ( state !== STATE.NONE ) {
717 |
718 | document.addEventListener( 'mousemove', onMouseMove, false );
719 | document.addEventListener( 'mouseup', onMouseUp, false );
720 |
721 | scope.dispatchEvent( startEvent );
722 |
723 | }
724 |
725 | }
726 |
727 | function onMouseMove( event ) {
728 |
729 | if ( scope.enabled === false ) return;
730 |
731 | event.preventDefault();
732 |
733 | switch ( state ) {
734 |
735 | case STATE.ROTATE:
736 |
737 | if ( scope.enableRotate === false ) return;
738 |
739 | handleMouseMoveRotate( event );
740 |
741 | break;
742 |
743 | case STATE.DOLLY:
744 |
745 | if ( scope.enableZoom === false ) return;
746 |
747 | handleMouseMoveDolly( event );
748 |
749 | break;
750 |
751 | case STATE.PAN:
752 |
753 | if ( scope.enablePan === false ) return;
754 |
755 | handleMouseMovePan( event );
756 |
757 | break;
758 |
759 | }
760 |
761 | }
762 |
763 | function onMouseUp( event ) {
764 |
765 | if ( scope.enabled === false ) return;
766 |
767 | handleMouseUp( event );
768 |
769 | document.removeEventListener( 'mousemove', onMouseMove, false );
770 | document.removeEventListener( 'mouseup', onMouseUp, false );
771 |
772 | scope.dispatchEvent( endEvent );
773 |
774 | state = STATE.NONE;
775 |
776 | }
777 |
778 | function onMouseWheel( event ) {
779 |
780 | if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return;
781 |
782 | event.preventDefault();
783 | event.stopPropagation();
784 |
785 | scope.dispatchEvent( startEvent );
786 |
787 | handleMouseWheel( event );
788 |
789 | scope.dispatchEvent( endEvent );
790 |
791 | }
792 |
793 | function onKeyDown( event ) {
794 |
795 | if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;
796 |
797 | handleKeyDown( event );
798 |
799 | }
800 |
801 | function onTouchStart( event ) {
802 |
803 | if ( scope.enabled === false ) return;
804 |
805 | event.preventDefault();
806 |
807 | switch ( event.touches.length ) {
808 |
809 | case 1: // one-fingered touch: rotate
810 |
811 | if ( scope.enableRotate === false ) return;
812 |
813 | handleTouchStartRotate( event );
814 |
815 | state = STATE.TOUCH_ROTATE;
816 |
817 | break;
818 |
819 | case 2: // two-fingered touch: dolly-pan
820 |
821 | if ( scope.enableZoom === false && scope.enablePan === false ) return;
822 |
823 | handleTouchStartDollyPan( event );
824 |
825 | state = STATE.TOUCH_DOLLY_PAN;
826 |
827 | break;
828 |
829 | default:
830 |
831 | state = STATE.NONE;
832 |
833 | }
834 |
835 | if ( state !== STATE.NONE ) {
836 |
837 | scope.dispatchEvent( startEvent );
838 |
839 | }
840 |
841 | }
842 |
843 | function onTouchMove( event ) {
844 |
845 | if ( scope.enabled === false ) return;
846 |
847 | event.preventDefault();
848 | event.stopPropagation();
849 |
850 | switch ( event.touches.length ) {
851 |
852 | case 1: // one-fingered touch: rotate
853 |
854 | if ( scope.enableRotate === false ) return;
855 | if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?
856 |
857 | handleTouchMoveRotate( event );
858 |
859 | break;
860 |
861 | case 2: // two-fingered touch: dolly-pan
862 |
863 | if ( scope.enableZoom === false && scope.enablePan === false ) return;
864 | if ( state !== STATE.TOUCH_DOLLY_PAN ) return; // is this needed?
865 |
866 | handleTouchMoveDollyPan( event );
867 |
868 | break;
869 |
870 | default:
871 |
872 | state = STATE.NONE;
873 |
874 | }
875 |
876 | }
877 |
878 | function onTouchEnd( event ) {
879 |
880 | if ( scope.enabled === false ) return;
881 |
882 | handleTouchEnd( event );
883 |
884 | scope.dispatchEvent( endEvent );
885 |
886 | state = STATE.NONE;
887 |
888 | }
889 |
890 | function onContextMenu( event ) {
891 |
892 | if ( scope.enabled === false ) return;
893 |
894 | event.preventDefault();
895 |
896 | }
897 |
898 | //
899 |
900 | scope.domElement.addEventListener( 'contextmenu', onContextMenu, false );
901 |
902 | scope.domElement.addEventListener( 'mousedown', onMouseDown, false );
903 | scope.domElement.addEventListener( 'wheel', onMouseWheel, false );
904 |
905 | scope.domElement.addEventListener( 'touchstart', onTouchStart, false );
906 | scope.domElement.addEventListener( 'touchend', onTouchEnd, false );
907 | scope.domElement.addEventListener( 'touchmove', onTouchMove, false );
908 |
909 | window.addEventListener( 'keydown', onKeyDown, false );
910 |
911 | // force an update at start
912 |
913 | this.update();
914 |
915 | };
916 |
917 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
918 | THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;
919 |
920 | Object.defineProperties( THREE.OrbitControls.prototype, {
921 |
922 | center: {
923 |
924 | get: function () {
925 |
926 | console.warn( 'THREE.OrbitControls: .center has been renamed to .target' );
927 | return this.target;
928 |
929 | }
930 |
931 | },
932 |
933 | // backward compatibility
934 |
935 | noZoom: {
936 |
937 | get: function () {
938 |
939 | console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
940 | return ! this.enableZoom;
941 |
942 | },
943 |
944 | set: function ( value ) {
945 |
946 | console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
947 | this.enableZoom = ! value;
948 |
949 | }
950 |
951 | },
952 |
953 | noRotate: {
954 |
955 | get: function () {
956 |
957 | console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
958 | return ! this.enableRotate;
959 |
960 | },
961 |
962 | set: function ( value ) {
963 |
964 | console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
965 | this.enableRotate = ! value;
966 |
967 | }
968 |
969 | },
970 |
971 | noPan: {
972 |
973 | get: function () {
974 |
975 | console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
976 | return ! this.enablePan;
977 |
978 | },
979 |
980 | set: function ( value ) {
981 |
982 | console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
983 | this.enablePan = ! value;
984 |
985 | }
986 |
987 | },
988 |
989 | noKeys: {
990 |
991 | get: function () {
992 |
993 | console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
994 | return ! this.enableKeys;
995 |
996 | },
997 |
998 | set: function ( value ) {
999 |
1000 | console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
1001 | this.enableKeys = ! value;
1002 |
1003 | }
1004 |
1005 | },
1006 |
1007 | staticMoving: {
1008 |
1009 | get: function () {
1010 |
1011 | console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
1012 | return ! this.enableDamping;
1013 |
1014 | },
1015 |
1016 | set: function ( value ) {
1017 |
1018 | console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
1019 | this.enableDamping = ! value;
1020 |
1021 | }
1022 |
1023 | },
1024 |
1025 | dynamicDampingFactor: {
1026 |
1027 | get: function () {
1028 |
1029 | console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
1030 | return this.dampingFactor;
1031 |
1032 | },
1033 |
1034 | set: function ( value ) {
1035 |
1036 | console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
1037 | this.dampingFactor = value;
1038 |
1039 | }
1040 |
1041 | }
1042 |
1043 | } );
1044 |
--------------------------------------------------------------------------------
/Projector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | * @author supereggbert / http://www.paulbrunt.co.uk/
4 | * @author julianwa / https://github.com/julianwa
5 | */
6 |
7 | THREE.RenderableObject = function () {
8 |
9 | this.id = 0;
10 |
11 | this.object = null;
12 | this.z = 0;
13 | this.renderOrder = 0;
14 |
15 | };
16 |
17 | //
18 |
19 | THREE.RenderableFace = function () {
20 |
21 | this.id = 0;
22 |
23 | this.v1 = new THREE.RenderableVertex();
24 | this.v2 = new THREE.RenderableVertex();
25 | this.v3 = new THREE.RenderableVertex();
26 |
27 | this.normalModel = new THREE.Vector3();
28 |
29 | this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
30 | this.vertexNormalsLength = 0;
31 |
32 | this.color = new THREE.Color();
33 | this.material = null;
34 | this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ];
35 |
36 | this.z = 0;
37 | this.renderOrder = 0;
38 |
39 | };
40 |
41 | //
42 |
43 | THREE.RenderableVertex = function () {
44 |
45 | this.position = new THREE.Vector3();
46 | this.positionWorld = new THREE.Vector3();
47 | this.positionScreen = new THREE.Vector4();
48 |
49 | this.visible = true;
50 |
51 | };
52 |
53 | THREE.RenderableVertex.prototype.copy = function ( vertex ) {
54 |
55 | this.positionWorld.copy( vertex.positionWorld );
56 | this.positionScreen.copy( vertex.positionScreen );
57 |
58 | };
59 |
60 | //
61 |
62 | THREE.RenderableLine = function () {
63 |
64 | this.id = 0;
65 |
66 | this.v1 = new THREE.RenderableVertex();
67 | this.v2 = new THREE.RenderableVertex();
68 |
69 | this.vertexColors = [ new THREE.Color(), new THREE.Color() ];
70 | this.material = null;
71 |
72 | this.z = 0;
73 | this.renderOrder = 0;
74 |
75 | };
76 |
77 | //
78 |
79 | THREE.RenderableSprite = function () {
80 |
81 | this.id = 0;
82 |
83 | this.object = null;
84 |
85 | this.x = 0;
86 | this.y = 0;
87 | this.z = 0;
88 |
89 | this.rotation = 0;
90 | this.scale = new THREE.Vector2();
91 |
92 | this.material = null;
93 | this.renderOrder = 0;
94 |
95 | };
96 |
97 | //
98 |
99 | THREE.Projector = function () {
100 |
101 | var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
102 | _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
103 | _face, _faceCount, _facePool = [], _facePoolLength = 0,
104 | _line, _lineCount, _linePool = [], _linePoolLength = 0,
105 | _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0,
106 |
107 | _renderData = { objects: [], lights: [], elements: [] },
108 |
109 | _vector3 = new THREE.Vector3(),
110 | _vector4 = new THREE.Vector4(),
111 |
112 | _clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ),
113 | _boundingBox = new THREE.Box3(),
114 | _points3 = new Array( 3 ),
115 |
116 | _viewMatrix = new THREE.Matrix4(),
117 | _viewProjectionMatrix = new THREE.Matrix4(),
118 |
119 | _modelMatrix,
120 | _modelViewProjectionMatrix = new THREE.Matrix4(),
121 |
122 | _normalMatrix = new THREE.Matrix3(),
123 |
124 | _frustum = new THREE.Frustum(),
125 |
126 | _clippedVertex1PositionScreen = new THREE.Vector4(),
127 | _clippedVertex2PositionScreen = new THREE.Vector4();
128 |
129 | //
130 |
131 | this.projectVector = function ( vector, camera ) {
132 |
133 | console.warn( 'THREE.Projector: .projectVector() is now vector.project().' );
134 | vector.project( camera );
135 |
136 | };
137 |
138 | this.unprojectVector = function ( vector, camera ) {
139 |
140 | console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );
141 | vector.unproject( camera );
142 |
143 | };
144 |
145 | this.pickingRay = function () {
146 |
147 | console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );
148 |
149 | };
150 |
151 | //
152 |
153 | var RenderList = function () {
154 |
155 | var normals = [];
156 | var colors = [];
157 | var uvs = [];
158 |
159 | var object = null;
160 | var material = null;
161 |
162 | var normalMatrix = new THREE.Matrix3();
163 |
164 | function setObject( value ) {
165 |
166 | object = value;
167 | material = object.material;
168 |
169 | normalMatrix.getNormalMatrix( object.matrixWorld );
170 |
171 | normals.length = 0;
172 | colors.length = 0;
173 | uvs.length = 0;
174 |
175 | }
176 |
177 | function projectVertex( vertex ) {
178 |
179 | var position = vertex.position;
180 | var positionWorld = vertex.positionWorld;
181 | var positionScreen = vertex.positionScreen;
182 |
183 | positionWorld.copy( position ).applyMatrix4( _modelMatrix );
184 | positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix );
185 |
186 | var invW = 1 / positionScreen.w;
187 |
188 | positionScreen.x *= invW;
189 | positionScreen.y *= invW;
190 | positionScreen.z *= invW;
191 |
192 | vertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 &&
193 | positionScreen.y >= - 1 && positionScreen.y <= 1 &&
194 | positionScreen.z >= - 1 && positionScreen.z <= 1;
195 |
196 | }
197 |
198 | function pushVertex( x, y, z ) {
199 |
200 | _vertex = getNextVertexInPool();
201 | _vertex.position.set( x, y, z );
202 |
203 | projectVertex( _vertex );
204 |
205 | }
206 |
207 | function pushNormal( x, y, z ) {
208 |
209 | normals.push( x, y, z );
210 |
211 | }
212 |
213 | function pushColor( r, g, b ) {
214 |
215 | colors.push( r, g, b );
216 |
217 | }
218 |
219 | function pushUv( x, y ) {
220 |
221 | uvs.push( x, y );
222 |
223 | }
224 |
225 | function checkTriangleVisibility( v1, v2, v3 ) {
226 |
227 | if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true;
228 |
229 | _points3[ 0 ] = v1.positionScreen;
230 | _points3[ 1 ] = v2.positionScreen;
231 | _points3[ 2 ] = v3.positionScreen;
232 |
233 | return _clipBox.intersectsBox( _boundingBox.setFromPoints( _points3 ) );
234 |
235 | }
236 |
237 | function checkBackfaceCulling( v1, v2, v3 ) {
238 |
239 | return ( ( v3.positionScreen.x - v1.positionScreen.x ) *
240 | ( v2.positionScreen.y - v1.positionScreen.y ) -
241 | ( v3.positionScreen.y - v1.positionScreen.y ) *
242 | ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;
243 |
244 | }
245 |
246 | function pushLine( a, b ) {
247 |
248 | var v1 = _vertexPool[ a ];
249 | var v2 = _vertexPool[ b ];
250 |
251 | // Clip
252 |
253 | v1.positionScreen.copy( v1.position ).applyMatrix4( _modelViewProjectionMatrix );
254 | v2.positionScreen.copy( v2.position ).applyMatrix4( _modelViewProjectionMatrix );
255 |
256 | if ( clipLine( v1.positionScreen, v2.positionScreen ) === true ) {
257 |
258 | // Perform the perspective divide
259 | v1.positionScreen.multiplyScalar( 1 / v1.positionScreen.w );
260 | v2.positionScreen.multiplyScalar( 1 / v2.positionScreen.w );
261 |
262 | _line = getNextLineInPool();
263 | _line.id = object.id;
264 | _line.v1.copy( v1 );
265 | _line.v2.copy( v2 );
266 | _line.z = Math.max( v1.positionScreen.z, v2.positionScreen.z );
267 | _line.renderOrder = object.renderOrder;
268 |
269 | _line.material = object.material;
270 |
271 | if ( object.material.vertexColors === THREE.VertexColors ) {
272 |
273 | _line.vertexColors[ 0 ].fromArray( colors, a * 3 );
274 | _line.vertexColors[ 1 ].fromArray( colors, b * 3 );
275 |
276 | }
277 |
278 | _renderData.elements.push( _line );
279 |
280 | }
281 |
282 | }
283 |
284 | function pushTriangle( a, b, c ) {
285 |
286 | var v1 = _vertexPool[ a ];
287 | var v2 = _vertexPool[ b ];
288 | var v3 = _vertexPool[ c ];
289 |
290 | if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return;
291 |
292 | if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) {
293 |
294 | _face = getNextFaceInPool();
295 |
296 | _face.id = object.id;
297 | _face.v1.copy( v1 );
298 | _face.v2.copy( v2 );
299 | _face.v3.copy( v3 );
300 | _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
301 | _face.renderOrder = object.renderOrder;
302 |
303 | // use first vertex normal as face normal
304 |
305 | _face.normalModel.fromArray( normals, a * 3 );
306 | _face.normalModel.applyMatrix3( normalMatrix ).normalize();
307 |
308 | for ( var i = 0; i < 3; i ++ ) {
309 |
310 | var normal = _face.vertexNormalsModel[ i ];
311 | normal.fromArray( normals, arguments[ i ] * 3 );
312 | normal.applyMatrix3( normalMatrix ).normalize();
313 |
314 | var uv = _face.uvs[ i ];
315 | uv.fromArray( uvs, arguments[ i ] * 2 );
316 |
317 | }
318 |
319 | _face.vertexNormalsLength = 3;
320 |
321 | _face.material = object.material;
322 |
323 | _renderData.elements.push( _face );
324 |
325 | }
326 |
327 | }
328 |
329 | return {
330 | setObject: setObject,
331 | projectVertex: projectVertex,
332 | checkTriangleVisibility: checkTriangleVisibility,
333 | checkBackfaceCulling: checkBackfaceCulling,
334 | pushVertex: pushVertex,
335 | pushNormal: pushNormal,
336 | pushColor: pushColor,
337 | pushUv: pushUv,
338 | pushLine: pushLine,
339 | pushTriangle: pushTriangle
340 | };
341 |
342 | };
343 |
344 | var renderList = new RenderList();
345 |
346 | function projectObject( object ) {
347 |
348 | if ( object.visible === false ) return;
349 |
350 | if ( object instanceof THREE.Light ) {
351 |
352 | _renderData.lights.push( object );
353 |
354 | } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Points ) {
355 |
356 | if ( object.material.visible === false ) return;
357 | if ( object.frustumCulled === true && _frustum.intersectsObject( object ) === false ) return;
358 |
359 | addObject( object );
360 |
361 | } else if ( object instanceof THREE.Sprite ) {
362 |
363 | if ( object.material.visible === false ) return;
364 | if ( object.frustumCulled === true && _frustum.intersectsSprite( object ) === false ) return;
365 |
366 | addObject( object );
367 |
368 | }
369 |
370 | var children = object.children;
371 |
372 | for ( var i = 0, l = children.length; i < l; i ++ ) {
373 |
374 | projectObject( children[ i ] );
375 |
376 | }
377 |
378 | }
379 |
380 | function addObject( object ) {
381 |
382 | _object = getNextObjectInPool();
383 | _object.id = object.id;
384 | _object.object = object;
385 |
386 | _vector3.setFromMatrixPosition( object.matrixWorld );
387 | _vector3.applyMatrix4( _viewProjectionMatrix );
388 | _object.z = _vector3.z;
389 | _object.renderOrder = object.renderOrder;
390 |
391 | _renderData.objects.push( _object );
392 |
393 | }
394 |
395 | this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
396 |
397 | _faceCount = 0;
398 | _lineCount = 0;
399 | _spriteCount = 0;
400 |
401 | _renderData.elements.length = 0;
402 |
403 | if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
404 | if ( camera.parent === null ) camera.updateMatrixWorld();
405 |
406 | _viewMatrix.copy( camera.matrixWorldInverse );
407 | _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
408 |
409 | _frustum.setFromMatrix( _viewProjectionMatrix );
410 |
411 | //
412 |
413 | _objectCount = 0;
414 |
415 | _renderData.objects.length = 0;
416 | _renderData.lights.length = 0;
417 |
418 | projectObject( scene );
419 |
420 | if ( sortObjects === true ) {
421 |
422 | _renderData.objects.sort( painterSort );
423 |
424 | }
425 |
426 | //
427 |
428 | var objects = _renderData.objects;
429 |
430 | for ( var o = 0, ol = objects.length; o < ol; o ++ ) {
431 |
432 | var object = objects[ o ].object;
433 | var geometry = object.geometry;
434 |
435 | renderList.setObject( object );
436 |
437 | _modelMatrix = object.matrixWorld;
438 |
439 | _vertexCount = 0;
440 |
441 | if ( object instanceof THREE.Mesh ) {
442 |
443 | if ( geometry instanceof THREE.BufferGeometry ) {
444 |
445 | var attributes = geometry.attributes;
446 | var groups = geometry.groups;
447 |
448 | if ( attributes.position === undefined ) continue;
449 |
450 | var positions = attributes.position.array;
451 |
452 | for ( var i = 0, l = positions.length; i < l; i += 3 ) {
453 |
454 | renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
455 |
456 | }
457 |
458 | if ( attributes.normal !== undefined ) {
459 |
460 | var normals = attributes.normal.array;
461 |
462 | for ( var i = 0, l = normals.length; i < l; i += 3 ) {
463 |
464 | renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] );
465 |
466 | }
467 |
468 | }
469 |
470 | if ( attributes.uv !== undefined ) {
471 |
472 | var uvs = attributes.uv.array;
473 |
474 | for ( var i = 0, l = uvs.length; i < l; i += 2 ) {
475 |
476 | renderList.pushUv( uvs[ i ], uvs[ i + 1 ] );
477 |
478 | }
479 |
480 | }
481 |
482 | if ( geometry.index !== null ) {
483 |
484 | var indices = geometry.index.array;
485 |
486 | if ( groups.length > 0 ) {
487 |
488 | for ( var g = 0; g < groups.length; g ++ ) {
489 |
490 | var group = groups[ g ];
491 |
492 | for ( var i = group.start, l = group.start + group.count; i < l; i += 3 ) {
493 |
494 | renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
495 |
496 | }
497 |
498 | }
499 |
500 | } else {
501 |
502 | for ( var i = 0, l = indices.length; i < l; i += 3 ) {
503 |
504 | renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
505 |
506 | }
507 |
508 | }
509 |
510 | } else {
511 |
512 | for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) {
513 |
514 | renderList.pushTriangle( i, i + 1, i + 2 );
515 |
516 | }
517 |
518 | }
519 |
520 | } else if ( geometry instanceof THREE.Geometry ) {
521 |
522 | var vertices = geometry.vertices;
523 | var faces = geometry.faces;
524 | var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
525 |
526 | _normalMatrix.getNormalMatrix( _modelMatrix );
527 |
528 | var material = object.material;
529 |
530 | var isMultiMaterial = Array.isArray( material );
531 |
532 | for ( var v = 0, vl = vertices.length; v < vl; v ++ ) {
533 |
534 | var vertex = vertices[ v ];
535 |
536 | _vector3.copy( vertex );
537 |
538 | if ( material.morphTargets === true ) {
539 |
540 | var morphTargets = geometry.morphTargets;
541 | var morphInfluences = object.morphTargetInfluences;
542 |
543 | for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
544 |
545 | var influence = morphInfluences[ t ];
546 |
547 | if ( influence === 0 ) continue;
548 |
549 | var target = morphTargets[ t ];
550 | var targetVertex = target.vertices[ v ];
551 |
552 | _vector3.x += ( targetVertex.x - vertex.x ) * influence;
553 | _vector3.y += ( targetVertex.y - vertex.y ) * influence;
554 | _vector3.z += ( targetVertex.z - vertex.z ) * influence;
555 |
556 | }
557 |
558 | }
559 |
560 | renderList.pushVertex( _vector3.x, _vector3.y, _vector3.z );
561 |
562 | }
563 |
564 | for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
565 |
566 | var face = faces[ f ];
567 |
568 | material = isMultiMaterial === true
569 | ? object.material[ face.materialIndex ]
570 | : object.material;
571 |
572 | if ( material === undefined ) continue;
573 |
574 | var side = material.side;
575 |
576 | var v1 = _vertexPool[ face.a ];
577 | var v2 = _vertexPool[ face.b ];
578 | var v3 = _vertexPool[ face.c ];
579 |
580 | if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue;
581 |
582 | var visible = renderList.checkBackfaceCulling( v1, v2, v3 );
583 |
584 | if ( side !== THREE.DoubleSide ) {
585 |
586 | if ( side === THREE.FrontSide && visible === false ) continue;
587 | if ( side === THREE.BackSide && visible === true ) continue;
588 |
589 | }
590 |
591 | _face = getNextFaceInPool();
592 |
593 | _face.id = object.id;
594 | _face.v1.copy( v1 );
595 | _face.v2.copy( v2 );
596 | _face.v3.copy( v3 );
597 |
598 | _face.normalModel.copy( face.normal );
599 |
600 | if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
601 |
602 | _face.normalModel.negate();
603 |
604 | }
605 |
606 | _face.normalModel.applyMatrix3( _normalMatrix ).normalize();
607 |
608 | var faceVertexNormals = face.vertexNormals;
609 |
610 | for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) {
611 |
612 | var normalModel = _face.vertexNormalsModel[ n ];
613 | normalModel.copy( faceVertexNormals[ n ] );
614 |
615 | if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
616 |
617 | normalModel.negate();
618 |
619 | }
620 |
621 | normalModel.applyMatrix3( _normalMatrix ).normalize();
622 |
623 | }
624 |
625 | _face.vertexNormalsLength = faceVertexNormals.length;
626 |
627 | var vertexUvs = faceVertexUvs[ f ];
628 |
629 | if ( vertexUvs !== undefined ) {
630 |
631 | for ( var u = 0; u < 3; u ++ ) {
632 |
633 | _face.uvs[ u ].copy( vertexUvs[ u ] );
634 |
635 | }
636 |
637 | }
638 |
639 | _face.color = face.color;
640 | _face.material = material;
641 |
642 | _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
643 | _face.renderOrder = object.renderOrder;
644 |
645 | _renderData.elements.push( _face );
646 |
647 | }
648 |
649 | }
650 |
651 | } else if ( object instanceof THREE.Line ) {
652 |
653 | _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
654 |
655 | if ( geometry instanceof THREE.BufferGeometry ) {
656 |
657 | var attributes = geometry.attributes;
658 |
659 | if ( attributes.position !== undefined ) {
660 |
661 | var positions = attributes.position.array;
662 |
663 | for ( var i = 0, l = positions.length; i < l; i += 3 ) {
664 |
665 | renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
666 |
667 | }
668 |
669 | if ( attributes.color !== undefined ) {
670 |
671 | var colors = attributes.color.array;
672 |
673 | for ( var i = 0, l = colors.length; i < l; i += 3 ) {
674 |
675 | renderList.pushColor( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] );
676 |
677 | }
678 |
679 | }
680 |
681 | if ( geometry.index !== null ) {
682 |
683 | var indices = geometry.index.array;
684 |
685 | for ( var i = 0, l = indices.length; i < l; i += 2 ) {
686 |
687 | renderList.pushLine( indices[ i ], indices[ i + 1 ] );
688 |
689 | }
690 |
691 | } else {
692 |
693 | var step = object instanceof THREE.LineSegments ? 2 : 1;
694 |
695 | for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) {
696 |
697 | renderList.pushLine( i, i + 1 );
698 |
699 | }
700 |
701 | }
702 |
703 | }
704 |
705 | } else if ( geometry instanceof THREE.Geometry ) {
706 |
707 | var vertices = object.geometry.vertices;
708 |
709 | if ( vertices.length === 0 ) continue;
710 |
711 | v1 = getNextVertexInPool();
712 | v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix );
713 |
714 | var step = object instanceof THREE.LineSegments ? 2 : 1;
715 |
716 | for ( var v = 1, vl = vertices.length; v < vl; v ++ ) {
717 |
718 | v1 = getNextVertexInPool();
719 | v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix );
720 |
721 | if ( ( v + 1 ) % step > 0 ) continue;
722 |
723 | v2 = _vertexPool[ _vertexCount - 2 ];
724 |
725 | _clippedVertex1PositionScreen.copy( v1.positionScreen );
726 | _clippedVertex2PositionScreen.copy( v2.positionScreen );
727 |
728 | if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) {
729 |
730 | // Perform the perspective divide
731 | _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );
732 | _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );
733 |
734 | _line = getNextLineInPool();
735 |
736 | _line.id = object.id;
737 | _line.v1.positionScreen.copy( _clippedVertex1PositionScreen );
738 | _line.v2.positionScreen.copy( _clippedVertex2PositionScreen );
739 |
740 | _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );
741 | _line.renderOrder = object.renderOrder;
742 |
743 | _line.material = object.material;
744 |
745 | if ( object.material.vertexColors === THREE.VertexColors ) {
746 |
747 | _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] );
748 | _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] );
749 |
750 | }
751 |
752 | _renderData.elements.push( _line );
753 |
754 | }
755 |
756 | }
757 |
758 | }
759 |
760 | } else if ( object instanceof THREE.Points ) {
761 |
762 | _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
763 |
764 | if ( geometry instanceof THREE.Geometry ) {
765 |
766 | var vertices = object.geometry.vertices;
767 |
768 | for ( var v = 0, vl = vertices.length; v < vl; v ++ ) {
769 |
770 | var vertex = vertices[ v ];
771 |
772 | _vector4.set( vertex.x, vertex.y, vertex.z, 1 );
773 | _vector4.applyMatrix4( _modelViewProjectionMatrix );
774 |
775 | pushPoint( _vector4, object, camera );
776 |
777 | }
778 |
779 | } else if ( geometry instanceof THREE.BufferGeometry ) {
780 |
781 | var attributes = geometry.attributes;
782 |
783 | if ( attributes.position !== undefined ) {
784 |
785 | var positions = attributes.position.array;
786 |
787 | for ( var i = 0, l = positions.length; i < l; i += 3 ) {
788 |
789 | _vector4.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ], 1 );
790 | _vector4.applyMatrix4( _modelViewProjectionMatrix );
791 |
792 | pushPoint( _vector4, object, camera );
793 |
794 | }
795 |
796 | }
797 |
798 | }
799 |
800 | } else if ( object instanceof THREE.Sprite ) {
801 |
802 | _vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 );
803 | _vector4.applyMatrix4( _viewProjectionMatrix );
804 |
805 | pushPoint( _vector4, object, camera );
806 |
807 | }
808 |
809 | }
810 |
811 | if ( sortElements === true ) {
812 |
813 | _renderData.elements.sort( painterSort );
814 |
815 | }
816 |
817 | return _renderData;
818 |
819 | };
820 |
821 | function pushPoint( _vector4, object, camera ) {
822 |
823 | var invW = 1 / _vector4.w;
824 |
825 | _vector4.z *= invW;
826 |
827 | if ( _vector4.z >= - 1 && _vector4.z <= 1 ) {
828 |
829 | _sprite = getNextSpriteInPool();
830 | _sprite.id = object.id;
831 | _sprite.x = _vector4.x * invW;
832 | _sprite.y = _vector4.y * invW;
833 | _sprite.z = _vector4.z;
834 | _sprite.renderOrder = object.renderOrder;
835 | _sprite.object = object;
836 |
837 | _sprite.rotation = object.rotation;
838 |
839 | _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) );
840 | _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) );
841 |
842 | _sprite.material = object.material;
843 |
844 | _renderData.elements.push( _sprite );
845 |
846 | }
847 |
848 | }
849 |
850 | // Pools
851 |
852 | function getNextObjectInPool() {
853 |
854 | if ( _objectCount === _objectPoolLength ) {
855 |
856 | var object = new THREE.RenderableObject();
857 | _objectPool.push( object );
858 | _objectPoolLength ++;
859 | _objectCount ++;
860 | return object;
861 |
862 | }
863 |
864 | return _objectPool[ _objectCount ++ ];
865 |
866 | }
867 |
868 | function getNextVertexInPool() {
869 |
870 | if ( _vertexCount === _vertexPoolLength ) {
871 |
872 | var vertex = new THREE.RenderableVertex();
873 | _vertexPool.push( vertex );
874 | _vertexPoolLength ++;
875 | _vertexCount ++;
876 | return vertex;
877 |
878 | }
879 |
880 | return _vertexPool[ _vertexCount ++ ];
881 |
882 | }
883 |
884 | function getNextFaceInPool() {
885 |
886 | if ( _faceCount === _facePoolLength ) {
887 |
888 | var face = new THREE.RenderableFace();
889 | _facePool.push( face );
890 | _facePoolLength ++;
891 | _faceCount ++;
892 | return face;
893 |
894 | }
895 |
896 | return _facePool[ _faceCount ++ ];
897 |
898 |
899 | }
900 |
901 | function getNextLineInPool() {
902 |
903 | if ( _lineCount === _linePoolLength ) {
904 |
905 | var line = new THREE.RenderableLine();
906 | _linePool.push( line );
907 | _linePoolLength ++;
908 | _lineCount ++;
909 | return line;
910 |
911 | }
912 |
913 | return _linePool[ _lineCount ++ ];
914 |
915 | }
916 |
917 | function getNextSpriteInPool() {
918 |
919 | if ( _spriteCount === _spritePoolLength ) {
920 |
921 | var sprite = new THREE.RenderableSprite();
922 | _spritePool.push( sprite );
923 | _spritePoolLength ++;
924 | _spriteCount ++;
925 | return sprite;
926 |
927 | }
928 |
929 | return _spritePool[ _spriteCount ++ ];
930 |
931 | }
932 |
933 | //
934 |
935 | function painterSort( a, b ) {
936 |
937 | if ( a.renderOrder !== b.renderOrder ) {
938 |
939 | return a.renderOrder - b.renderOrder;
940 |
941 | } else if ( a.z !== b.z ) {
942 |
943 | return b.z - a.z;
944 |
945 | } else if ( a.id !== b.id ) {
946 |
947 | return a.id - b.id;
948 |
949 | } else {
950 |
951 | return 0;
952 |
953 | }
954 |
955 | }
956 |
957 | function clipLine( s1, s2 ) {
958 |
959 | var alpha1 = 0, alpha2 = 1,
960 |
961 | // Calculate the boundary coordinate of each vertex for the near and far clip planes,
962 | // Z = -1 and Z = +1, respectively.
963 |
964 | bc1near = s1.z + s1.w,
965 | bc2near = s2.z + s2.w,
966 | bc1far = - s1.z + s1.w,
967 | bc2far = - s2.z + s2.w;
968 |
969 | if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {
970 |
971 | // Both vertices lie entirely within all clip planes.
972 | return true;
973 |
974 | } else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) {
975 |
976 | // Both vertices lie entirely outside one of the clip planes.
977 | return false;
978 |
979 | } else {
980 |
981 | // The line segment spans at least one clip plane.
982 |
983 | if ( bc1near < 0 ) {
984 |
985 | // v1 lies outside the near plane, v2 inside
986 | alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );
987 |
988 | } else if ( bc2near < 0 ) {
989 |
990 | // v2 lies outside the near plane, v1 inside
991 | alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );
992 |
993 | }
994 |
995 | if ( bc1far < 0 ) {
996 |
997 | // v1 lies outside the far plane, v2 inside
998 | alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );
999 |
1000 | } else if ( bc2far < 0 ) {
1001 |
1002 | // v2 lies outside the far plane, v2 inside
1003 | alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );
1004 |
1005 | }
1006 |
1007 | if ( alpha2 < alpha1 ) {
1008 |
1009 | // The line segment spans two boundaries, but is outside both of them.
1010 | // (This can't happen when we're only clipping against just near/far but good
1011 | // to leave the check here for future usage if other clip planes are added.)
1012 | return false;
1013 |
1014 | } else {
1015 |
1016 | // Update the s1 and s2 vertices to match the clipped line segment.
1017 | s1.lerp( s2, alpha1 );
1018 | s2.lerp( s1, 1 - alpha2 );
1019 |
1020 | return true;
1021 |
1022 | }
1023 |
1024 | }
1025 |
1026 | }
1027 |
1028 | };
1029 |
--------------------------------------------------------------------------------