├── index.html
├── js
├── ColladaLoader.js
├── FBXLoader.js
├── VRControls.js
├── inflate.min.js
├── three.ar.js
└── three.js
├── models
├── Hip Hop Dancing.fbx
├── Takashi-Thriller.fbx
├── daito
│ ├── Arm_col.jpg
│ ├── Cap_col.jpg
│ ├── HeadBase_col.jpg
│ ├── Pants_col.jpg
│ ├── Shose_col.jpg
│ ├── Tshirt_col.jpg
│ └── daito_t_low_idle_2.dae
└── porg
│ ├── Hip Hop Dancing.fbx
│ ├── body_d.png
│ ├── body_n.png
│ ├── body_s.png
│ ├── eye_d.png
│ ├── eye_d_.png
│ ├── eye_env.png
│ ├── feathers_d.png
│ └── feathers_n.png
├── webgl_dae_daito.html
├── webgl_fbx_mixamo.html
├── webgl_fbx_porg.html
└── webgl_fbx_takashi.html
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WebAR Experiments
5 |
6 |
7 |
31 |
32 |
33 | WebAR Experiments
34 |
40 |
41 | source code
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/js/ColladaLoader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | * @author Mugen87 / https://github.com/Mugen87
4 | */
5 |
6 | THREE.ColladaLoader = function ( manager ) {
7 |
8 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
9 |
10 | };
11 |
12 | THREE.ColladaLoader.prototype = {
13 |
14 | constructor: THREE.ColladaLoader,
15 |
16 | crossOrigin: 'Anonymous',
17 |
18 | load: function ( url, onLoad, onProgress, onError ) {
19 |
20 | var scope = this;
21 |
22 | var path = scope.path === undefined ? THREE.LoaderUtils.extractUrlBase( url ) : scope.path;
23 |
24 | var loader = new THREE.FileLoader( scope.manager );
25 | loader.load( url, function ( text ) {
26 |
27 | onLoad( scope.parse( text, path ) );
28 |
29 | }, onProgress, onError );
30 |
31 | },
32 |
33 | setPath: function ( value ) {
34 |
35 | this.path = value;
36 |
37 | },
38 |
39 | options: {
40 |
41 | set convertUpAxis( value ) {
42 |
43 | console.warn( 'THREE.ColladaLoader: options.convertUpAxis() has been removed. Up axis is converted automatically.' );
44 |
45 | }
46 |
47 | },
48 |
49 | setCrossOrigin: function ( value ) {
50 |
51 | this.crossOrigin = value;
52 |
53 | },
54 |
55 | parse: function ( text, path ) {
56 |
57 | function getElementsByTagName( xml, name ) {
58 |
59 | // Non recursive xml.getElementsByTagName() ...
60 |
61 | var array = [];
62 | var childNodes = xml.childNodes;
63 |
64 | for ( var i = 0, l = childNodes.length; i < l; i ++ ) {
65 |
66 | var child = childNodes[ i ];
67 |
68 | if ( child.nodeName === name ) {
69 |
70 | array.push( child );
71 |
72 | }
73 |
74 | }
75 |
76 | return array;
77 |
78 | }
79 |
80 | function parseStrings( text ) {
81 |
82 | if ( text.length === 0 ) return [];
83 |
84 | var parts = text.trim().split( /\s+/ );
85 | var array = new Array( parts.length );
86 |
87 | for ( var i = 0, l = parts.length; i < l; i ++ ) {
88 |
89 | array[ i ] = parts[ i ];
90 |
91 | }
92 |
93 | return array;
94 |
95 | }
96 |
97 | function parseFloats( text ) {
98 |
99 | if ( text.length === 0 ) return [];
100 |
101 | var parts = text.trim().split( /\s+/ );
102 | var array = new Array( parts.length );
103 |
104 | for ( var i = 0, l = parts.length; i < l; i ++ ) {
105 |
106 | array[ i ] = parseFloat( parts[ i ] );
107 |
108 | }
109 |
110 | return array;
111 |
112 | }
113 |
114 | function parseInts( text ) {
115 |
116 | if ( text.length === 0 ) return [];
117 |
118 | var parts = text.trim().split( /\s+/ );
119 | var array = new Array( parts.length );
120 |
121 | for ( var i = 0, l = parts.length; i < l; i ++ ) {
122 |
123 | array[ i ] = parseInt( parts[ i ] );
124 |
125 | }
126 |
127 | return array;
128 |
129 | }
130 |
131 | function parseId( text ) {
132 |
133 | return text.substring( 1 );
134 |
135 | }
136 |
137 | function generateId() {
138 |
139 | return 'three_default_' + ( count ++ );
140 |
141 | }
142 |
143 | function isEmpty( object ) {
144 |
145 | return Object.keys( object ).length === 0;
146 |
147 | }
148 |
149 | // asset
150 |
151 | function parseAsset( xml ) {
152 |
153 | return {
154 | unit: parseAssetUnit( getElementsByTagName( xml, 'unit' )[ 0 ] ),
155 | upAxis: parseAssetUpAxis( getElementsByTagName( xml, 'up_axis' )[ 0 ] )
156 | };
157 |
158 | }
159 |
160 | function parseAssetUnit( xml ) {
161 |
162 | return xml !== undefined ? parseFloat( xml.getAttribute( 'meter' ) ) : 1;
163 |
164 | }
165 |
166 | function parseAssetUpAxis( xml ) {
167 |
168 | return xml !== undefined ? xml.textContent : 'Y_UP';
169 |
170 | }
171 |
172 | // library
173 |
174 | function parseLibrary( xml, libraryName, nodeName, parser ) {
175 |
176 | var library = getElementsByTagName( xml, libraryName )[ 0 ];
177 |
178 | if ( library !== undefined ) {
179 |
180 | var elements = getElementsByTagName( library, nodeName );
181 |
182 | for ( var i = 0; i < elements.length; i ++ ) {
183 |
184 | parser( elements[ i ] );
185 |
186 | }
187 |
188 | }
189 |
190 | }
191 |
192 | function buildLibrary( data, builder ) {
193 |
194 | for ( var name in data ) {
195 |
196 | var object = data[ name ];
197 | object.build = builder( data[ name ] );
198 |
199 | }
200 |
201 | }
202 |
203 | // get
204 |
205 | function getBuild( data, builder ) {
206 |
207 | if ( data.build !== undefined ) return data.build;
208 |
209 | data.build = builder( data );
210 |
211 | return data.build;
212 |
213 | }
214 |
215 | // animation
216 |
217 | function parseAnimation( xml ) {
218 |
219 | var data = {
220 | sources: {},
221 | samplers: {},
222 | channels: {}
223 | };
224 |
225 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
226 |
227 | var child = xml.childNodes[ i ];
228 |
229 | if ( child.nodeType !== 1 ) continue;
230 |
231 | var id;
232 |
233 | switch ( child.nodeName ) {
234 |
235 | case 'source':
236 | id = child.getAttribute( 'id' );
237 | data.sources[ id ] = parseSource( child );
238 | break;
239 |
240 | case 'sampler':
241 | id = child.getAttribute( 'id' );
242 | data.samplers[ id ] = parseAnimationSampler( child );
243 | break;
244 |
245 | case 'channel':
246 | id = child.getAttribute( 'target' );
247 | data.channels[ id ] = parseAnimationChannel( child );
248 | break;
249 |
250 | default:
251 | console.log( child );
252 |
253 | }
254 |
255 | }
256 |
257 | library.animations[ xml.getAttribute( 'id' ) ] = data;
258 |
259 | }
260 |
261 | function parseAnimationSampler( xml ) {
262 |
263 | var data = {
264 | inputs: {},
265 | };
266 |
267 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
268 |
269 | var child = xml.childNodes[ i ];
270 |
271 | if ( child.nodeType !== 1 ) continue;
272 |
273 | switch ( child.nodeName ) {
274 |
275 | case 'input':
276 | var id = parseId( child.getAttribute( 'source' ) );
277 | var semantic = child.getAttribute( 'semantic' );
278 | data.inputs[ semantic ] = id;
279 | break;
280 |
281 | }
282 |
283 | }
284 |
285 | return data;
286 |
287 | }
288 |
289 | function parseAnimationChannel( xml ) {
290 |
291 | var data = {};
292 |
293 | var target = xml.getAttribute( 'target' );
294 |
295 | // parsing SID Addressing Syntax
296 |
297 | var parts = target.split( '/' );
298 |
299 | var id = parts.shift();
300 | var sid = parts.shift();
301 |
302 | // check selection syntax
303 |
304 | var arraySyntax = ( sid.indexOf( '(' ) !== - 1 );
305 | var memberSyntax = ( sid.indexOf( '.' ) !== - 1 );
306 |
307 | if ( memberSyntax ) {
308 |
309 | // member selection access
310 |
311 | parts = sid.split( '.' );
312 | sid = parts.shift();
313 | data.member = parts.shift();
314 |
315 | } else if ( arraySyntax ) {
316 |
317 | // array-access syntax. can be used to express fields in one-dimensional vectors or two-dimensional matrices.
318 |
319 | var indices = sid.split( '(' );
320 | sid = indices.shift();
321 |
322 | for ( var i = 0; i < indices.length; i ++ ) {
323 |
324 | indices[ i ] = parseInt( indices[ i ].replace( /\)/, '' ) );
325 |
326 | }
327 |
328 | data.indices = indices;
329 |
330 | }
331 |
332 | data.id = id;
333 | data.sid = sid;
334 |
335 | data.arraySyntax = arraySyntax;
336 | data.memberSyntax = memberSyntax;
337 |
338 | data.sampler = parseId( xml.getAttribute( 'source' ) );
339 |
340 | return data;
341 |
342 | }
343 |
344 | function buildAnimation( data ) {
345 |
346 | var tracks = [];
347 |
348 | var channels = data.channels;
349 | var samplers = data.samplers;
350 | var sources = data.sources;
351 |
352 | for ( var target in channels ) {
353 |
354 | if ( channels.hasOwnProperty( target ) ) {
355 |
356 | var channel = channels[ target ];
357 | var sampler = samplers[ channel.sampler ];
358 |
359 | var inputId = sampler.inputs.INPUT;
360 | var outputId = sampler.inputs.OUTPUT;
361 |
362 | var inputSource = sources[ inputId ];
363 | var outputSource = sources[ outputId ];
364 |
365 | var animation = buildAnimationChannel( channel, inputSource, outputSource );
366 |
367 | createKeyframeTracks( animation, tracks );
368 |
369 | }
370 |
371 | }
372 |
373 | return tracks;
374 |
375 | }
376 |
377 | function getAnimation( id ) {
378 |
379 | return getBuild( library.animations[ id ], buildAnimation );
380 |
381 | }
382 |
383 | function buildAnimationChannel( channel, inputSource, outputSource ) {
384 |
385 | var node = library.nodes[ channel.id ];
386 | var object3D = getNode( node.id );
387 |
388 | var transform = node.transforms[ channel.sid ];
389 | var defaultMatrix = node.matrix.clone().transpose();
390 |
391 | var time, stride;
392 | var i, il, j, jl;
393 |
394 | var data = {};
395 |
396 | // the collada spec allows the animation of data in various ways.
397 | // depending on the transform type (matrix, translate, rotate, scale), we execute different logic
398 |
399 | switch ( transform ) {
400 |
401 | case 'matrix':
402 |
403 | for ( i = 0, il = inputSource.array.length; i < il; i ++ ) {
404 |
405 | time = inputSource.array[ i ];
406 | stride = i * outputSource.stride;
407 |
408 | if ( data[ time ] === undefined ) data[ time ] = {};
409 |
410 | if ( channel.arraySyntax === true ) {
411 |
412 | var value = outputSource.array[ stride ];
413 | var index = channel.indices[ 0 ] + 4 * channel.indices[ 1 ];
414 |
415 | data[ time ][ index ] = value;
416 |
417 | } else {
418 |
419 | for ( j = 0, jl = outputSource.stride; j < jl; j ++ ) {
420 |
421 | data[ time ][ j ] = outputSource.array[ stride + j ];
422 |
423 | }
424 |
425 | }
426 |
427 | }
428 |
429 | break;
430 |
431 | case 'translate':
432 | console.warn( 'THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform );
433 | break;
434 |
435 | case 'rotate':
436 | console.warn( 'THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform );
437 | break;
438 |
439 | case 'scale':
440 | console.warn( 'THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform );
441 | break;
442 |
443 | }
444 |
445 | var keyframes = prepareAnimationData( data, defaultMatrix );
446 |
447 | var animation = {
448 | name: object3D.uuid,
449 | keyframes: keyframes
450 | };
451 |
452 | return animation;
453 |
454 | }
455 |
456 | function prepareAnimationData( data, defaultMatrix ) {
457 |
458 | var keyframes = [];
459 |
460 | // transfer data into a sortable array
461 |
462 | for ( var time in data ) {
463 |
464 | keyframes.push( { time: parseFloat( time ), value: data[ time ] } );
465 |
466 | }
467 |
468 | // ensure keyframes are sorted by time
469 |
470 | keyframes.sort( ascending );
471 |
472 | // now we clean up all animation data, so we can use them for keyframe tracks
473 |
474 | for ( var i = 0; i < 16; i ++ ) {
475 |
476 | transformAnimationData( keyframes, i, defaultMatrix.elements[ i ] );
477 |
478 | }
479 |
480 | return keyframes;
481 |
482 | // array sort function
483 |
484 | function ascending( a, b ) {
485 |
486 | return a.time - b.time;
487 |
488 | }
489 |
490 | }
491 |
492 | var position = new THREE.Vector3();
493 | var scale = new THREE.Vector3();
494 | var quaternion = new THREE.Quaternion();
495 |
496 | function createKeyframeTracks( animation, tracks ) {
497 |
498 | var keyframes = animation.keyframes;
499 | var name = animation.name;
500 |
501 | var times = [];
502 | var positionData = [];
503 | var quaternionData = [];
504 | var scaleData = [];
505 |
506 | for ( var i = 0, l = keyframes.length; i < l; i ++ ) {
507 |
508 | var keyframe = keyframes[ i ];
509 |
510 | var time = keyframe.time;
511 | var value = keyframe.value;
512 |
513 | matrix.fromArray( value ).transpose();
514 | matrix.decompose( position, quaternion, scale );
515 |
516 | times.push( time );
517 | positionData.push( position.x, position.y, position.z );
518 | quaternionData.push( quaternion.x, quaternion.y, quaternion.z, quaternion.w );
519 | scaleData.push( scale.x, scale.y, scale.z );
520 |
521 | }
522 |
523 | if ( positionData.length > 0 ) tracks.push( new THREE.VectorKeyframeTrack( name + '.position', times, positionData ) );
524 | if ( quaternionData.length > 0 ) tracks.push( new THREE.QuaternionKeyframeTrack( name + '.quaternion', times, quaternionData ) );
525 | if ( scaleData.length > 0 ) tracks.push( new THREE.VectorKeyframeTrack( name + '.scale', times, scaleData ) );
526 |
527 | return tracks;
528 |
529 | }
530 |
531 | function transformAnimationData( keyframes, property, defaultValue ) {
532 |
533 | var keyframe;
534 |
535 | var empty = true;
536 | var i, l;
537 |
538 | // check, if values of a property are missing in our keyframes
539 |
540 | for ( i = 0, l = keyframes.length; i < l; i ++ ) {
541 |
542 | keyframe = keyframes[ i ];
543 |
544 | if ( keyframe.value[ property ] === undefined ) {
545 |
546 | keyframe.value[ property ] = null; // mark as missing
547 |
548 | } else {
549 |
550 | empty = false;
551 |
552 | }
553 |
554 | }
555 |
556 | if ( empty === true ) {
557 |
558 | // no values at all, so we set a default value
559 |
560 | for ( i = 0, l = keyframes.length; i < l; i ++ ) {
561 |
562 | keyframe = keyframes[ i ];
563 |
564 | keyframe.value[ property ] = defaultValue;
565 |
566 | }
567 |
568 | } else {
569 |
570 | // filling gaps
571 |
572 | createMissingKeyframes( keyframes, property );
573 |
574 | }
575 |
576 | }
577 |
578 | function createMissingKeyframes( keyframes, property ) {
579 |
580 | var prev, next;
581 |
582 | for ( var i = 0, l = keyframes.length; i < l; i ++ ) {
583 |
584 | var keyframe = keyframes[ i ];
585 |
586 | if ( keyframe.value[ property ] === null ) {
587 |
588 | prev = getPrev( keyframes, i, property );
589 | next = getNext( keyframes, i, property );
590 |
591 | if ( prev === null ) {
592 |
593 | keyframe.value[ property ] = next.value[ property ];
594 | continue;
595 |
596 | }
597 |
598 | if ( next === null ) {
599 |
600 | keyframe.value[ property ] = prev.value[ property ];
601 | continue;
602 |
603 | }
604 |
605 | interpolate( keyframe, prev, next, property );
606 |
607 | }
608 |
609 | }
610 |
611 | }
612 |
613 | function getPrev( keyframes, i, property ) {
614 |
615 | while ( i >= 0 ) {
616 |
617 | var keyframe = keyframes[ i ];
618 |
619 | if ( keyframe.value[ property ] !== null ) return keyframe;
620 |
621 | i --;
622 |
623 | }
624 |
625 | return null;
626 |
627 | }
628 |
629 | function getNext( keyframes, i, property ) {
630 |
631 | while ( i < keyframes.length ) {
632 |
633 | var keyframe = keyframes[ i ];
634 |
635 | if ( keyframe.value[ property ] !== null ) return keyframe;
636 |
637 | i ++;
638 |
639 | }
640 |
641 | return null;
642 |
643 | }
644 |
645 | function interpolate( key, prev, next, property ) {
646 |
647 | if ( ( next.time - prev.time ) === 0 ) {
648 |
649 | key.value[ property ] = prev.value[ property ];
650 | return;
651 |
652 | }
653 |
654 | key.value[ property ] = ( ( key.time - prev.time ) * ( next.value[ property ] - prev.value[ property ] ) / ( next.time - prev.time ) ) + prev.value[ property ];
655 |
656 | }
657 |
658 | // animation clips
659 |
660 | function parseAnimationClip( xml ) {
661 |
662 | var data = {
663 | name: xml.getAttribute( 'id' ) || 'default',
664 | start: parseFloat( xml.getAttribute( 'start' ) || 0 ),
665 | end: parseFloat( xml.getAttribute( 'end' ) || 0 ),
666 | animations: []
667 | };
668 |
669 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
670 |
671 | var child = xml.childNodes[ i ];
672 |
673 | if ( child.nodeType !== 1 ) continue;
674 |
675 | switch ( child.nodeName ) {
676 |
677 | case 'instance_animation':
678 | data.animations.push( parseId( child.getAttribute( 'url' ) ) );
679 | break;
680 |
681 | }
682 |
683 | }
684 |
685 | library.clips[ xml.getAttribute( 'id' ) ] = data;
686 |
687 | }
688 |
689 | function buildAnimationClip( data ) {
690 |
691 | var tracks = [];
692 |
693 | var name = data.name;
694 | var duration = ( data.end - data.start ) || - 1;
695 | var animations = data.animations;
696 |
697 | for ( var i = 0, il = animations.length; i < il; i ++ ) {
698 |
699 | var animationTracks = getAnimation( animations[ i ] );
700 |
701 | for ( var j = 0, jl = animationTracks.length; j < jl; j ++ ) {
702 |
703 | tracks.push( animationTracks[ j ] );
704 |
705 | }
706 |
707 | }
708 |
709 | return new THREE.AnimationClip( name, duration, tracks );
710 |
711 | }
712 |
713 | function getAnimationClip( id ) {
714 |
715 | return getBuild( library.clips[ id ], buildAnimationClip );
716 |
717 | }
718 |
719 | // controller
720 |
721 | function parseController( xml ) {
722 |
723 | var data = {};
724 |
725 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
726 |
727 | var child = xml.childNodes[ i ];
728 |
729 | if ( child.nodeType !== 1 ) continue;
730 |
731 | switch ( child.nodeName ) {
732 |
733 | case 'skin':
734 | // there is exactly one skin per controller
735 | data.id = parseId( child.getAttribute( 'source' ) );
736 | data.skin = parseSkin( child );
737 | break;
738 |
739 | case 'morph':
740 | data.id = parseId( child.getAttribute( 'source' ) );
741 | console.warn( 'THREE.ColladaLoader: Morph target animation not supported yet.' );
742 | break;
743 |
744 | }
745 |
746 | }
747 |
748 | library.controllers[ xml.getAttribute( 'id' ) ] = data;
749 |
750 | }
751 |
752 | function parseSkin( xml ) {
753 |
754 | var data = {
755 | sources: {}
756 | };
757 |
758 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
759 |
760 | var child = xml.childNodes[ i ];
761 |
762 | if ( child.nodeType !== 1 ) continue;
763 |
764 | switch ( child.nodeName ) {
765 |
766 | case 'bind_shape_matrix':
767 | data.bindShapeMatrix = parseFloats( child.textContent );
768 | break;
769 |
770 | case 'source':
771 | var id = child.getAttribute( 'id' );
772 | data.sources[ id ] = parseSource( child );
773 | break;
774 |
775 | case 'joints':
776 | data.joints = parseJoints( child );
777 | break;
778 |
779 | case 'vertex_weights':
780 | data.vertexWeights = parseVertexWeights( child );
781 | break;
782 |
783 | }
784 |
785 | }
786 |
787 | return data;
788 |
789 | }
790 |
791 | function parseJoints( xml ) {
792 |
793 | var data = {
794 | inputs: {}
795 | };
796 |
797 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
798 |
799 | var child = xml.childNodes[ i ];
800 |
801 | if ( child.nodeType !== 1 ) continue;
802 |
803 | switch ( child.nodeName ) {
804 |
805 | case 'input':
806 | var semantic = child.getAttribute( 'semantic' );
807 | var id = parseId( child.getAttribute( 'source' ) );
808 | data.inputs[ semantic ] = id;
809 | break;
810 |
811 | }
812 |
813 | }
814 |
815 | return data;
816 |
817 | }
818 |
819 | function parseVertexWeights( xml ) {
820 |
821 | var data = {
822 | inputs: {}
823 | };
824 |
825 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
826 |
827 | var child = xml.childNodes[ i ];
828 |
829 | if ( child.nodeType !== 1 ) continue;
830 |
831 | switch ( child.nodeName ) {
832 |
833 | case 'input':
834 | var semantic = child.getAttribute( 'semantic' );
835 | var id = parseId( child.getAttribute( 'source' ) );
836 | var offset = parseInt( child.getAttribute( 'offset' ) );
837 | data.inputs[ semantic ] = { id: id, offset: offset };
838 | break;
839 |
840 | case 'vcount':
841 | data.vcount = parseInts( child.textContent );
842 | break;
843 |
844 | case 'v':
845 | data.v = parseInts( child.textContent );
846 | break;
847 |
848 | }
849 |
850 | }
851 |
852 | return data;
853 |
854 | }
855 |
856 | function buildController( data ) {
857 |
858 | var build = {
859 | id: data.id
860 | };
861 |
862 | var geometry = library.geometries[ build.id ];
863 |
864 | if ( data.skin !== undefined ) {
865 |
866 | build.skin = buildSkin( data.skin );
867 |
868 | // we enhance the 'sources' property of the corresponding geometry with our skin data
869 |
870 | geometry.sources.skinIndices = build.skin.indices;
871 | geometry.sources.skinWeights = build.skin.weights;
872 |
873 | }
874 |
875 | return build;
876 |
877 | }
878 |
879 | function buildSkin( data ) {
880 |
881 | var BONE_LIMIT = 4;
882 |
883 | var build = {
884 | joints: [], // this must be an array to preserve the joint order
885 | indices: {
886 | array: [],
887 | stride: BONE_LIMIT
888 | },
889 | weights: {
890 | array: [],
891 | stride: BONE_LIMIT
892 | }
893 | };
894 |
895 | var sources = data.sources;
896 | var vertexWeights = data.vertexWeights;
897 |
898 | var vcount = vertexWeights.vcount;
899 | var v = vertexWeights.v;
900 | var jointOffset = vertexWeights.inputs.JOINT.offset;
901 | var weightOffset = vertexWeights.inputs.WEIGHT.offset;
902 |
903 | var jointSource = data.sources[ data.joints.inputs.JOINT ];
904 | var inverseSource = data.sources[ data.joints.inputs.INV_BIND_MATRIX ];
905 |
906 | var weights = sources[ vertexWeights.inputs.WEIGHT.id ].array;
907 | var stride = 0;
908 |
909 | var i, j, l;
910 |
911 | // procces skin data for each vertex
912 |
913 | for ( i = 0, l = vcount.length; i < l; i ++ ) {
914 |
915 | var jointCount = vcount[ i ]; // this is the amount of joints that affect a single vertex
916 | var vertexSkinData = [];
917 |
918 | for ( j = 0; j < jointCount; j ++ ) {
919 |
920 | var skinIndex = v[ stride + jointOffset ];
921 | var weightId = v[ stride + weightOffset ];
922 | var skinWeight = weights[ weightId ];
923 |
924 | vertexSkinData.push( { index: skinIndex, weight: skinWeight } );
925 |
926 | stride += 2;
927 |
928 | }
929 |
930 | // we sort the joints in descending order based on the weights.
931 | // this ensures, we only procced the most important joints of the vertex
932 |
933 | vertexSkinData.sort( descending );
934 |
935 | // now we provide for each vertex a set of four index and weight values.
936 | // the order of the skin data matches the order of vertices
937 |
938 | for ( j = 0; j < BONE_LIMIT; j ++ ) {
939 |
940 | var d = vertexSkinData[ j ];
941 |
942 | if ( d !== undefined ) {
943 |
944 | build.indices.array.push( d.index );
945 | build.weights.array.push( d.weight );
946 |
947 | } else {
948 |
949 | build.indices.array.push( 0 );
950 | build.weights.array.push( 0 );
951 |
952 | }
953 |
954 | }
955 |
956 | }
957 |
958 | // setup bind matrix
959 |
960 | build.bindMatrix = new THREE.Matrix4().fromArray( data.bindShapeMatrix ).transpose();
961 |
962 | // process bones and inverse bind matrix data
963 |
964 | for ( i = 0, l = jointSource.array.length; i < l; i ++ ) {
965 |
966 | var name = jointSource.array[ i ];
967 | var boneInverse = new THREE.Matrix4().fromArray( inverseSource.array, i * inverseSource.stride ).transpose();
968 |
969 | build.joints.push( { name: name, boneInverse: boneInverse } );
970 |
971 | }
972 |
973 | return build;
974 |
975 | // array sort function
976 |
977 | function descending( a, b ) {
978 |
979 | return b.weight - a.weight;
980 |
981 | }
982 |
983 | }
984 |
985 | function getController( id ) {
986 |
987 | return getBuild( library.controllers[ id ], buildController );
988 |
989 | }
990 |
991 | // image
992 |
993 | function parseImage( xml ) {
994 |
995 | var data = {
996 | init_from: getElementsByTagName( xml, 'init_from' )[ 0 ].textContent
997 | };
998 |
999 | library.images[ xml.getAttribute( 'id' ) ] = data;
1000 |
1001 | }
1002 |
1003 | function buildImage( data ) {
1004 |
1005 | if ( data.build !== undefined ) return data.build;
1006 |
1007 | return data.init_from;
1008 |
1009 | }
1010 |
1011 | function getImage( id ) {
1012 |
1013 | return getBuild( library.images[ id ], buildImage );
1014 |
1015 | }
1016 |
1017 | // effect
1018 |
1019 | function parseEffect( xml ) {
1020 |
1021 | var data = {};
1022 |
1023 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1024 |
1025 | var child = xml.childNodes[ i ];
1026 |
1027 | if ( child.nodeType !== 1 ) continue;
1028 |
1029 | switch ( child.nodeName ) {
1030 |
1031 | case 'profile_COMMON':
1032 | data.profile = parseEffectProfileCOMMON( child );
1033 | break;
1034 |
1035 | }
1036 |
1037 | }
1038 |
1039 | library.effects[ xml.getAttribute( 'id' ) ] = data;
1040 |
1041 | }
1042 |
1043 | function parseEffectProfileCOMMON( xml ) {
1044 |
1045 | var data = {
1046 | surfaces: {},
1047 | samplers: {}
1048 | };
1049 |
1050 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1051 |
1052 | var child = xml.childNodes[ i ];
1053 |
1054 | if ( child.nodeType !== 1 ) continue;
1055 |
1056 | switch ( child.nodeName ) {
1057 |
1058 | case 'newparam':
1059 | parseEffectNewparam( child, data );
1060 | break;
1061 |
1062 | case 'technique':
1063 | data.technique = parseEffectTechnique( child );
1064 | break;
1065 |
1066 | }
1067 |
1068 | }
1069 |
1070 | return data;
1071 |
1072 | }
1073 |
1074 | function parseEffectNewparam( xml, data ) {
1075 |
1076 | var sid = xml.getAttribute( 'sid' );
1077 |
1078 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1079 |
1080 | var child = xml.childNodes[ i ];
1081 |
1082 | if ( child.nodeType !== 1 ) continue;
1083 |
1084 | switch ( child.nodeName ) {
1085 |
1086 | case 'surface':
1087 | data.surfaces[ sid ] = parseEffectSurface( child );
1088 | break;
1089 |
1090 | case 'sampler2D':
1091 | data.samplers[ sid ] = parseEffectSampler( child );
1092 | break;
1093 |
1094 | }
1095 |
1096 | }
1097 |
1098 | }
1099 |
1100 | function parseEffectSurface( xml ) {
1101 |
1102 | var data = {};
1103 |
1104 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1105 |
1106 | var child = xml.childNodes[ i ];
1107 |
1108 | if ( child.nodeType !== 1 ) continue;
1109 |
1110 | switch ( child.nodeName ) {
1111 |
1112 | case 'init_from':
1113 | data.init_from = child.textContent;
1114 | break;
1115 |
1116 | }
1117 |
1118 | }
1119 |
1120 | return data;
1121 |
1122 | }
1123 |
1124 | function parseEffectSampler( xml ) {
1125 |
1126 | var data = {};
1127 |
1128 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1129 |
1130 | var child = xml.childNodes[ i ];
1131 |
1132 | if ( child.nodeType !== 1 ) continue;
1133 |
1134 | switch ( child.nodeName ) {
1135 |
1136 | case 'source':
1137 | data.source = child.textContent;
1138 | break;
1139 |
1140 | }
1141 |
1142 | }
1143 |
1144 | return data;
1145 |
1146 | }
1147 |
1148 | function parseEffectTechnique( xml ) {
1149 |
1150 | var data = {};
1151 |
1152 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1153 |
1154 | var child = xml.childNodes[ i ];
1155 |
1156 | if ( child.nodeType !== 1 ) continue;
1157 |
1158 | switch ( child.nodeName ) {
1159 |
1160 | case 'constant':
1161 | case 'lambert':
1162 | case 'blinn':
1163 | case 'phong':
1164 | data.type = child.nodeName;
1165 | data.parameters = parseEffectParameters( child );
1166 | break;
1167 |
1168 | }
1169 |
1170 | }
1171 |
1172 | return data;
1173 |
1174 | }
1175 |
1176 | function parseEffectParameters( xml ) {
1177 |
1178 | var data = {};
1179 |
1180 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1181 |
1182 | var child = xml.childNodes[ i ];
1183 |
1184 | if ( child.nodeType !== 1 ) continue;
1185 |
1186 | switch ( child.nodeName ) {
1187 |
1188 | case 'emission':
1189 | case 'diffuse':
1190 | case 'specular':
1191 | case 'shininess':
1192 | case 'transparency':
1193 | data[ child.nodeName ] = parseEffectParameter( child );
1194 | break;
1195 | case 'transparent':
1196 | data[ child.nodeName ] = {
1197 | opaque: child.getAttribute( 'opaque' ),
1198 | data: parseEffectParameter( child )
1199 | };
1200 | break;
1201 |
1202 | }
1203 |
1204 | }
1205 |
1206 | return data;
1207 |
1208 | }
1209 |
1210 | function parseEffectParameter( xml ) {
1211 |
1212 | var data = {};
1213 |
1214 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1215 |
1216 | var child = xml.childNodes[ i ];
1217 |
1218 | if ( child.nodeType !== 1 ) continue;
1219 |
1220 | switch ( child.nodeName ) {
1221 |
1222 | case 'color':
1223 | data[ child.nodeName ] = parseFloats( child.textContent );
1224 | break;
1225 |
1226 | case 'float':
1227 | data[ child.nodeName ] = parseFloat( child.textContent );
1228 | break;
1229 |
1230 | case 'texture':
1231 | data[ child.nodeName ] = { id: child.getAttribute( 'texture' ), extra: parseEffectParameterTexture( child ) };
1232 | break;
1233 |
1234 | }
1235 |
1236 | }
1237 |
1238 | return data;
1239 |
1240 | }
1241 |
1242 | function parseEffectParameterTexture( xml ) {
1243 |
1244 | var data = {
1245 | technique: {}
1246 | };
1247 |
1248 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1249 |
1250 | var child = xml.childNodes[ i ];
1251 |
1252 | if ( child.nodeType !== 1 ) continue;
1253 |
1254 | switch ( child.nodeName ) {
1255 |
1256 | case 'extra':
1257 | parseEffectParameterTextureExtra( child, data );
1258 | break;
1259 |
1260 | }
1261 |
1262 | }
1263 |
1264 | return data;
1265 |
1266 | }
1267 |
1268 | function parseEffectParameterTextureExtra( xml, data ) {
1269 |
1270 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1271 |
1272 | var child = xml.childNodes[ i ];
1273 |
1274 | if ( child.nodeType !== 1 ) continue;
1275 |
1276 | switch ( child.nodeName ) {
1277 |
1278 | case 'technique':
1279 | parseEffectParameterTextureExtraTechnique( child, data );
1280 | break;
1281 |
1282 | }
1283 |
1284 | }
1285 |
1286 | }
1287 |
1288 | function parseEffectParameterTextureExtraTechnique( xml, data ) {
1289 |
1290 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1291 |
1292 | var child = xml.childNodes[ i ];
1293 |
1294 | if ( child.nodeType !== 1 ) continue;
1295 |
1296 | switch ( child.nodeName ) {
1297 |
1298 | case 'repeatU':
1299 | case 'repeatV':
1300 | case 'offsetU':
1301 | case 'offsetV':
1302 | data.technique[ child.nodeName ] = parseFloat( child.textContent );
1303 | break;
1304 |
1305 | case 'wrapU':
1306 | case 'wrapV':
1307 |
1308 | // some files have values for wrapU/wrapV which become NaN via parseInt
1309 |
1310 | if ( child.textContent.toUpperCase() === 'TRUE' ) {
1311 |
1312 | data.technique[ child.nodeName ] = 1;
1313 |
1314 | } else if ( child.textContent.toUpperCase() === 'FALSE' ) {
1315 |
1316 | data.technique[ child.nodeName ] = 0;
1317 |
1318 | } else {
1319 |
1320 | data.technique[ child.nodeName ] = parseInt( child.textContent );
1321 |
1322 | }
1323 |
1324 | break;
1325 |
1326 | }
1327 |
1328 | }
1329 |
1330 | }
1331 |
1332 | function buildEffect( data ) {
1333 |
1334 | return data;
1335 |
1336 | }
1337 |
1338 | function getEffect( id ) {
1339 |
1340 | return getBuild( library.effects[ id ], buildEffect );
1341 |
1342 | }
1343 |
1344 | // material
1345 |
1346 | function parseMaterial( xml ) {
1347 |
1348 | var data = {
1349 | name: xml.getAttribute( 'name' )
1350 | };
1351 |
1352 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1353 |
1354 | var child = xml.childNodes[ i ];
1355 |
1356 | if ( child.nodeType !== 1 ) continue;
1357 |
1358 | switch ( child.nodeName ) {
1359 |
1360 | case 'instance_effect':
1361 | data.url = parseId( child.getAttribute( 'url' ) );
1362 | break;
1363 |
1364 | }
1365 |
1366 | }
1367 |
1368 | library.materials[ xml.getAttribute( 'id' ) ] = data;
1369 |
1370 | }
1371 |
1372 | function buildMaterial( data ) {
1373 |
1374 | var effect = getEffect( data.url );
1375 | var technique = effect.profile.technique;
1376 |
1377 | var material;
1378 |
1379 | switch ( technique.type ) {
1380 |
1381 | case 'phong':
1382 | case 'blinn':
1383 | material = new THREE.MeshPhongMaterial();
1384 | break;
1385 |
1386 | case 'lambert':
1387 | material = new THREE.MeshLambertMaterial();
1388 | break;
1389 |
1390 | default:
1391 | material = new THREE.MeshBasicMaterial();
1392 | break;
1393 |
1394 | }
1395 |
1396 | material.name = data.name;
1397 |
1398 | function getTexture( textureObject ) {
1399 |
1400 | var sampler = effect.profile.samplers[ textureObject.id ];
1401 | var image;
1402 |
1403 | // get image
1404 |
1405 | if ( sampler !== undefined ) {
1406 |
1407 | var surface = effect.profile.surfaces[ sampler.source ];
1408 | image = getImage( surface.init_from );
1409 |
1410 | } else {
1411 |
1412 | console.warn( 'THREE.ColladaLoader: Undefined sampler. Access image directly (see #12530).' );
1413 | image = getImage( textureObject.id );
1414 |
1415 | }
1416 |
1417 | // create texture if image is avaiable
1418 |
1419 | if ( image !== undefined ) {
1420 |
1421 | var texture = textureLoader.load( image );
1422 |
1423 | var extra = textureObject.extra;
1424 |
1425 | if ( extra !== undefined && extra.technique !== undefined && isEmpty( extra.technique ) === false ) {
1426 |
1427 | var technique = extra.technique;
1428 |
1429 | texture.wrapS = technique.wrapU ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
1430 | texture.wrapT = technique.wrapV ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
1431 |
1432 | texture.offset.set( technique.offsetU || 0, technique.offsetV || 0 );
1433 | texture.repeat.set( technique.repeatU || 1, technique.repeatV || 1 );
1434 |
1435 | } else {
1436 |
1437 | texture.wrapS = THREE.RepeatWrapping;
1438 | texture.wrapT = THREE.RepeatWrapping;
1439 |
1440 | }
1441 |
1442 | return texture;
1443 |
1444 | } else {
1445 |
1446 | console.error( 'THREE.ColladaLoader: Unable to load texture with ID:', textureObject.id );
1447 |
1448 | return null;
1449 |
1450 | }
1451 |
1452 | }
1453 |
1454 | var parameters = technique.parameters;
1455 |
1456 | for ( var key in parameters ) {
1457 |
1458 | var parameter = parameters[ key ];
1459 |
1460 | switch ( key ) {
1461 |
1462 | case 'diffuse':
1463 | if ( parameter.color ) material.color.fromArray( parameter.color );
1464 | if ( parameter.texture ) material.map = getTexture( parameter.texture );
1465 | break;
1466 | case 'specular':
1467 | if ( parameter.color && material.specular ) material.specular.fromArray( parameter.color );
1468 | if ( parameter.texture ) material.specularMap = getTexture( parameter.texture );
1469 | break;
1470 | case 'shininess':
1471 | if ( parameter.float && material.shininess )
1472 | material.shininess = parameter.float;
1473 | break;
1474 | case 'emission':
1475 | if ( parameter.color && material.emissive )
1476 | material.emissive.fromArray( parameter.color );
1477 | break;
1478 |
1479 | }
1480 |
1481 | }
1482 |
1483 | //
1484 |
1485 | var transparent = parameters[ 'transparent' ];
1486 | var transparency = parameters[ 'transparency' ];
1487 |
1488 | // does not exist but
1489 |
1490 | if ( transparency === undefined && transparent ) {
1491 |
1492 | transparency = {
1493 | float: 1
1494 | };
1495 |
1496 | }
1497 |
1498 | // does not exist but
1499 |
1500 | if ( transparent === undefined && transparency ) {
1501 |
1502 | transparent = {
1503 | opaque: 'A_ONE',
1504 | data: {
1505 | color: [ 1, 1, 1, 1 ]
1506 | } };
1507 |
1508 | }
1509 |
1510 | if ( transparent && transparency ) {
1511 |
1512 | // handle case if a texture exists but no color
1513 |
1514 | if ( transparent.data.texture ) {
1515 |
1516 | material.alphaMap = getTexture( transparent.data.texture );
1517 | material.transparent = true;
1518 |
1519 | } else {
1520 |
1521 | var color = transparent.data.color;
1522 |
1523 | switch ( transparent.opaque ) {
1524 |
1525 | case 'A_ONE':
1526 | material.opacity = color[ 3 ] * transparency.float;
1527 | break;
1528 | case 'RGB_ZERO':
1529 | material.opacity = 1 - ( color[ 0 ] * transparency.float );
1530 | break;
1531 | case 'A_ZERO':
1532 | material.opacity = 1 - ( color[ 3 ] * transparency.float );
1533 | break;
1534 | case 'RGB_ONE':
1535 | material.opacity = color[ 0 ] * transparency.float;
1536 | break;
1537 | default:
1538 | console.warn( 'THREE.ColladaLoader: Invalid opaque type "%s" of transparent tag.', transparent.opaque );
1539 |
1540 | }
1541 |
1542 | if ( material.opacity < 1 ) material.transparent = true;
1543 |
1544 | }
1545 |
1546 | }
1547 |
1548 | return material;
1549 |
1550 | }
1551 |
1552 | function getMaterial( id ) {
1553 |
1554 | return getBuild( library.materials[ id ], buildMaterial );
1555 |
1556 | }
1557 |
1558 | // camera
1559 |
1560 | function parseCamera( xml ) {
1561 |
1562 | var data = {
1563 | name: xml.getAttribute( 'name' )
1564 | };
1565 |
1566 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1567 |
1568 | var child = xml.childNodes[ i ];
1569 |
1570 | if ( child.nodeType !== 1 ) continue;
1571 |
1572 | switch ( child.nodeName ) {
1573 |
1574 | case 'optics':
1575 | data.optics = parseCameraOptics( child );
1576 | break;
1577 |
1578 | }
1579 |
1580 | }
1581 |
1582 | library.cameras[ xml.getAttribute( 'id' ) ] = data;
1583 |
1584 | }
1585 |
1586 | function parseCameraOptics( xml ) {
1587 |
1588 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
1589 |
1590 | var child = xml.childNodes[ i ];
1591 |
1592 | switch ( child.nodeName ) {
1593 |
1594 | case 'technique_common':
1595 | return parseCameraTechnique( child );
1596 |
1597 | }
1598 |
1599 | }
1600 |
1601 | return {};
1602 |
1603 | }
1604 |
1605 | function parseCameraTechnique( xml ) {
1606 |
1607 | var data = {};
1608 |
1609 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
1610 |
1611 | var child = xml.childNodes[ i ];
1612 |
1613 | switch ( child.nodeName ) {
1614 |
1615 | case 'perspective':
1616 | case 'orthographic':
1617 |
1618 | data.technique = child.nodeName;
1619 | data.parameters = parseCameraParameters( child );
1620 |
1621 | break;
1622 |
1623 | }
1624 |
1625 | }
1626 |
1627 | return data;
1628 |
1629 | }
1630 |
1631 | function parseCameraParameters( xml ) {
1632 |
1633 | var data = {};
1634 |
1635 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
1636 |
1637 | var child = xml.childNodes[ i ];
1638 |
1639 | switch ( child.nodeName ) {
1640 |
1641 | case 'xfov':
1642 | case 'yfov':
1643 | case 'xmag':
1644 | case 'ymag':
1645 | case 'znear':
1646 | case 'zfar':
1647 | case 'aspect_ratio':
1648 | data[ child.nodeName ] = parseFloat( child.textContent );
1649 | break;
1650 |
1651 | }
1652 |
1653 | }
1654 |
1655 | return data;
1656 |
1657 | }
1658 |
1659 | function buildCamera( data ) {
1660 |
1661 | var camera;
1662 |
1663 | switch ( data.optics.technique ) {
1664 |
1665 | case 'perspective':
1666 | camera = new THREE.PerspectiveCamera(
1667 | data.optics.parameters.yfov,
1668 | data.optics.parameters.aspect_ratio,
1669 | data.optics.parameters.znear,
1670 | data.optics.parameters.zfar
1671 | );
1672 | break;
1673 |
1674 | case 'orthographic':
1675 | var ymag = data.optics.parameters.ymag;
1676 | var xmag = data.optics.parameters.xmag;
1677 | var aspectRatio = data.optics.parameters.aspect_ratio;
1678 |
1679 | xmag = ( xmag === undefined ) ? ( ymag * aspectRatio ) : xmag;
1680 | ymag = ( ymag === undefined ) ? ( xmag / aspectRatio ) : ymag;
1681 |
1682 | xmag *= 0.5;
1683 | ymag *= 0.5;
1684 |
1685 | camera = new THREE.OrthographicCamera(
1686 | - xmag, xmag, ymag, - ymag, // left, right, top, bottom
1687 | data.optics.parameters.znear,
1688 | data.optics.parameters.zfar
1689 | );
1690 | break;
1691 |
1692 | default:
1693 | camera = new THREE.PerspectiveCamera();
1694 | break;
1695 |
1696 | }
1697 |
1698 | camera.name = data.name;
1699 |
1700 | return camera;
1701 |
1702 | }
1703 |
1704 | function getCamera( id ) {
1705 |
1706 | var data = library.cameras[ id ];
1707 |
1708 | if ( data !== undefined ) {
1709 |
1710 | return getBuild( data, buildCamera );
1711 |
1712 | }
1713 |
1714 | console.warn( 'THREE.ColladaLoader: Couldn\'t find camera with ID:', id );
1715 |
1716 | return null;
1717 |
1718 | }
1719 |
1720 | // light
1721 |
1722 | function parseLight( xml ) {
1723 |
1724 | var data = {};
1725 |
1726 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1727 |
1728 | var child = xml.childNodes[ i ];
1729 |
1730 | if ( child.nodeType !== 1 ) continue;
1731 |
1732 | switch ( child.nodeName ) {
1733 |
1734 | case 'technique_common':
1735 | data = parseLightTechnique( child );
1736 | break;
1737 |
1738 | }
1739 |
1740 | }
1741 |
1742 | library.lights[ xml.getAttribute( 'id' ) ] = data;
1743 |
1744 | }
1745 |
1746 | function parseLightTechnique( xml ) {
1747 |
1748 | var data = {};
1749 |
1750 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1751 |
1752 | var child = xml.childNodes[ i ];
1753 |
1754 | if ( child.nodeType !== 1 ) continue;
1755 |
1756 | switch ( child.nodeName ) {
1757 |
1758 | case 'directional':
1759 | case 'point':
1760 | case 'spot':
1761 | case 'ambient':
1762 |
1763 | data.technique = child.nodeName;
1764 | data.parameters = parseLightParameters( child );
1765 |
1766 | }
1767 |
1768 | }
1769 |
1770 | return data;
1771 |
1772 | }
1773 |
1774 | function parseLightParameters( xml ) {
1775 |
1776 | var data = {};
1777 |
1778 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1779 |
1780 | var child = xml.childNodes[ i ];
1781 |
1782 | if ( child.nodeType !== 1 ) continue;
1783 |
1784 | switch ( child.nodeName ) {
1785 |
1786 | case 'color':
1787 | var array = parseFloats( child.textContent );
1788 | data.color = new THREE.Color().fromArray( array );
1789 | break;
1790 |
1791 | case 'falloff_angle':
1792 | data.falloffAngle = parseFloat( child.textContent );
1793 | break;
1794 |
1795 | case 'quadratic_attenuation':
1796 | var f = parseFloat( child.textContent );
1797 | data.distance = f ? Math.sqrt( 1 / f ) : 0;
1798 | break;
1799 |
1800 | }
1801 |
1802 | }
1803 |
1804 | return data;
1805 |
1806 | }
1807 |
1808 | function buildLight( data ) {
1809 |
1810 | var light;
1811 |
1812 | switch ( data.technique ) {
1813 |
1814 | case 'directional':
1815 | light = new THREE.DirectionalLight();
1816 | break;
1817 |
1818 | case 'point':
1819 | light = new THREE.PointLight();
1820 | break;
1821 |
1822 | case 'spot':
1823 | light = new THREE.SpotLight();
1824 | break;
1825 |
1826 | case 'ambient':
1827 | light = new THREE.AmbientLight();
1828 | break;
1829 |
1830 | }
1831 |
1832 | if ( data.parameters.color ) light.color.copy( data.parameters.color );
1833 | if ( data.parameters.distance ) light.distance = data.parameters.distance;
1834 |
1835 | return light;
1836 |
1837 | }
1838 |
1839 | function getLight( id ) {
1840 |
1841 | var data = library.lights[ id ];
1842 |
1843 | if ( data !== undefined ) {
1844 |
1845 | return getBuild( data, buildLight );
1846 |
1847 | }
1848 |
1849 | console.warn( 'THREE.ColladaLoader: Couldn\'t find light with ID:', id );
1850 |
1851 | return null;
1852 |
1853 | }
1854 |
1855 | // geometry
1856 |
1857 | function parseGeometry( xml ) {
1858 |
1859 | var data = {
1860 | name: xml.getAttribute( 'name' ),
1861 | sources: {},
1862 | vertices: {},
1863 | primitives: []
1864 | };
1865 |
1866 | var mesh = getElementsByTagName( xml, 'mesh' )[ 0 ];
1867 |
1868 | // the following tags inside geometry are not supported yet (see https://github.com/mrdoob/three.js/pull/12606): convex_mesh, spline, brep
1869 | if ( mesh === undefined ) return;
1870 |
1871 | for ( var i = 0; i < mesh.childNodes.length; i ++ ) {
1872 |
1873 | var child = mesh.childNodes[ i ];
1874 |
1875 | if ( child.nodeType !== 1 ) continue;
1876 |
1877 | var id = child.getAttribute( 'id' );
1878 |
1879 | switch ( child.nodeName ) {
1880 |
1881 | case 'source':
1882 | data.sources[ id ] = parseSource( child );
1883 | break;
1884 |
1885 | case 'vertices':
1886 | // data.sources[ id ] = data.sources[ parseId( getElementsByTagName( child, 'input' )[ 0 ].getAttribute( 'source' ) ) ];
1887 | data.vertices = parseGeometryVertices( child );
1888 | break;
1889 |
1890 | case 'polygons':
1891 | console.warn( 'THREE.ColladaLoader: Unsupported primitive type: ', child.nodeName );
1892 | break;
1893 |
1894 | case 'lines':
1895 | case 'linestrips':
1896 | case 'polylist':
1897 | case 'triangles':
1898 | data.primitives.push( parseGeometryPrimitive( child ) );
1899 | break;
1900 |
1901 | default:
1902 | console.log( child );
1903 |
1904 | }
1905 |
1906 | }
1907 |
1908 | library.geometries[ xml.getAttribute( 'id' ) ] = data;
1909 |
1910 | }
1911 |
1912 | function parseSource( xml ) {
1913 |
1914 | var data = {
1915 | array: [],
1916 | stride: 3
1917 | };
1918 |
1919 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
1920 |
1921 | var child = xml.childNodes[ i ];
1922 |
1923 | if ( child.nodeType !== 1 ) continue;
1924 |
1925 | switch ( child.nodeName ) {
1926 |
1927 | case 'float_array':
1928 | data.array = parseFloats( child.textContent );
1929 | break;
1930 |
1931 | case 'Name_array':
1932 | data.array = parseStrings( child.textContent );
1933 | break;
1934 |
1935 | case 'technique_common':
1936 | var accessor = getElementsByTagName( child, 'accessor' )[ 0 ];
1937 |
1938 | if ( accessor !== undefined ) {
1939 |
1940 | data.stride = parseInt( accessor.getAttribute( 'stride' ) );
1941 |
1942 | }
1943 | break;
1944 |
1945 | }
1946 |
1947 | }
1948 |
1949 | return data;
1950 |
1951 | }
1952 |
1953 | function parseGeometryVertices( xml ) {
1954 |
1955 | var data = {};
1956 |
1957 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
1958 |
1959 | var child = xml.childNodes[ i ];
1960 |
1961 | if ( child.nodeType !== 1 ) continue;
1962 |
1963 | data[ child.getAttribute( 'semantic' ) ] = parseId( child.getAttribute( 'source' ) );
1964 |
1965 | }
1966 |
1967 | return data;
1968 |
1969 | }
1970 |
1971 | function parseGeometryPrimitive( xml ) {
1972 |
1973 | var primitive = {
1974 | type: xml.nodeName,
1975 | material: xml.getAttribute( 'material' ),
1976 | count: parseInt( xml.getAttribute( 'count' ) ),
1977 | inputs: {},
1978 | stride: 0
1979 | };
1980 |
1981 | for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
1982 |
1983 | var child = xml.childNodes[ i ];
1984 |
1985 | if ( child.nodeType !== 1 ) continue;
1986 |
1987 | switch ( child.nodeName ) {
1988 |
1989 | case 'input':
1990 | var id = parseId( child.getAttribute( 'source' ) );
1991 | var semantic = child.getAttribute( 'semantic' );
1992 | var offset = parseInt( child.getAttribute( 'offset' ) );
1993 | primitive.inputs[ semantic ] = { id: id, offset: offset };
1994 | primitive.stride = Math.max( primitive.stride, offset + 1 );
1995 | break;
1996 |
1997 | case 'vcount':
1998 | primitive.vcount = parseInts( child.textContent );
1999 | break;
2000 |
2001 | case 'p':
2002 | primitive.p = parseInts( child.textContent );
2003 | break;
2004 |
2005 | }
2006 |
2007 | }
2008 |
2009 | return primitive;
2010 |
2011 | }
2012 |
2013 | function groupPrimitives( primitives ) {
2014 |
2015 | var build = {};
2016 |
2017 | for ( var i = 0; i < primitives.length; i ++ ) {
2018 |
2019 | var primitive = primitives[ i ];
2020 |
2021 | if ( build[ primitive.type ] === undefined ) build[ primitive.type ] = [];
2022 |
2023 | build[ primitive.type ].push( primitive );
2024 |
2025 | }
2026 |
2027 | return build;
2028 |
2029 | }
2030 |
2031 | function buildGeometry( data ) {
2032 |
2033 | var build = {};
2034 |
2035 | var sources = data.sources;
2036 | var vertices = data.vertices;
2037 | var primitives = data.primitives;
2038 |
2039 | if ( primitives.length === 0 ) return {};
2040 |
2041 | // our goal is to create one buffer geoemtry for a single type of primitives
2042 | // first, we group all primitives by their type
2043 |
2044 | var groupedPrimitives = groupPrimitives( primitives );
2045 |
2046 | for ( var type in groupedPrimitives ) {
2047 |
2048 | // second, we create for each type of primitives (polylist,triangles or lines) a buffer geometry
2049 |
2050 | build[ type ] = buildGeometryType( groupedPrimitives[ type ], sources, vertices );
2051 |
2052 | }
2053 |
2054 | return build;
2055 |
2056 | }
2057 |
2058 | function buildGeometryType( primitives, sources, vertices ) {
2059 |
2060 | var build = {};
2061 |
2062 | var position = { array: [], stride: 0 };
2063 | var normal = { array: [], stride: 0 };
2064 | var uv = { array: [], stride: 0 };
2065 | var color = { array: [], stride: 0 };
2066 |
2067 | var skinIndex = { array: [], stride: 4 };
2068 | var skinWeight = { array: [], stride: 4 };
2069 |
2070 | var geometry = new THREE.BufferGeometry();
2071 |
2072 | var materialKeys = [];
2073 |
2074 | var start = 0, count = 0;
2075 |
2076 | for ( var p = 0; p < primitives.length; p ++ ) {
2077 |
2078 | var primitive = primitives[ p ];
2079 | var inputs = primitive.inputs;
2080 | var triangleCount = 1;
2081 |
2082 | if ( primitive.vcount && primitive.vcount[ 0 ] === 4 ) {
2083 |
2084 | triangleCount = 2; // one quad -> two triangles
2085 |
2086 | }
2087 |
2088 | // groups
2089 |
2090 | if ( primitive.type === 'lines' || primitive.type === 'linestrips' ) {
2091 |
2092 | count = primitive.count * 2;
2093 |
2094 | } else {
2095 |
2096 | count = primitive.count * 3 * triangleCount;
2097 |
2098 | }
2099 |
2100 | geometry.addGroup( start, count, p );
2101 | start += count;
2102 |
2103 | // material
2104 |
2105 | if ( primitive.material ) {
2106 |
2107 | materialKeys.push( primitive.material );
2108 |
2109 | }
2110 |
2111 | // geometry data
2112 |
2113 | for ( var name in inputs ) {
2114 |
2115 | var input = inputs[ name ];
2116 |
2117 | switch ( name ) {
2118 |
2119 | case 'VERTEX':
2120 | for ( var key in vertices ) {
2121 |
2122 | var id = vertices[ key ];
2123 |
2124 | switch ( key ) {
2125 |
2126 | case 'POSITION':
2127 | buildGeometryData( primitive, sources[ id ], input.offset, position.array );
2128 | position.stride = sources[ id ].stride;
2129 |
2130 | if ( sources.skinWeights && sources.skinIndices ) {
2131 |
2132 | buildGeometryData( primitive, sources.skinIndices, input.offset, skinIndex.array );
2133 | buildGeometryData( primitive, sources.skinWeights, input.offset, skinWeight.array );
2134 |
2135 | }
2136 | break;
2137 |
2138 | case 'NORMAL':
2139 | buildGeometryData( primitive, sources[ id ], input.offset, normal.array );
2140 | normal.stride = sources[ id ].stride;
2141 | break;
2142 |
2143 | case 'COLOR':
2144 | buildGeometryData( primitive, sources[ id ], input.offset, color.array );
2145 | color.stride = sources[ id ].stride;
2146 | break;
2147 |
2148 | case 'TEXCOORD':
2149 | buildGeometryData( primitive, sources[ id ], input.offset, uv.array );
2150 | uv.stride = sources[ id ].stride;
2151 | break;
2152 |
2153 | default:
2154 | console.warn( 'THREE.ColladaLoader: Semantic "%s" not handled in geometry build process.', key );
2155 |
2156 | }
2157 |
2158 | }
2159 | break;
2160 |
2161 | case 'NORMAL':
2162 | buildGeometryData( primitive, sources[ input.id ], input.offset, normal.array );
2163 | normal.stride = sources[ input.id ].stride;
2164 | break;
2165 |
2166 | case 'COLOR':
2167 | buildGeometryData( primitive, sources[ input.id ], input.offset, color.array );
2168 | color.stride = sources[ input.id ].stride;
2169 | break;
2170 |
2171 | case 'TEXCOORD':
2172 | buildGeometryData( primitive, sources[ input.id ], input.offset, uv.array );
2173 | uv.stride = sources[ input.id ].stride;
2174 | break;
2175 |
2176 | }
2177 |
2178 | }
2179 |
2180 | }
2181 |
2182 | // build geometry
2183 |
2184 | if ( position.array.length > 0 ) geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( position.array, position.stride ) );
2185 | if ( normal.array.length > 0 ) geometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( normal.array, normal.stride ) );
2186 | if ( color.array.length > 0 ) geometry.addAttribute( 'color', new THREE.Float32BufferAttribute( color.array, color.stride ) );
2187 | if ( uv.array.length > 0 ) geometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( uv.array, uv.stride ) );
2188 |
2189 | if ( skinIndex.array.length > 0 ) geometry.addAttribute( 'skinIndex', new THREE.Float32BufferAttribute( skinIndex.array, skinIndex.stride ) );
2190 | if ( skinWeight.array.length > 0 ) geometry.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( skinWeight.array, skinWeight.stride ) );
2191 |
2192 | build.data = geometry;
2193 | build.type = primitives[ 0 ].type;
2194 | build.materialKeys = materialKeys;
2195 |
2196 | return build;
2197 |
2198 | }
2199 |
2200 | function buildGeometryData( primitive, source, offset, array ) {
2201 |
2202 | var indices = primitive.p;
2203 | var stride = primitive.stride;
2204 | var vcount = primitive.vcount;
2205 |
2206 | function pushVector( i ) {
2207 |
2208 | var index = indices[ i + offset ] * sourceStride;
2209 | var length = index + sourceStride;
2210 |
2211 | for ( ; index < length; index ++ ) {
2212 |
2213 | array.push( sourceArray[ index ] );
2214 |
2215 | }
2216 |
2217 | }
2218 |
2219 | var maxcount = 0;
2220 |
2221 | var sourceArray = source.array;
2222 | var sourceStride = source.stride;
2223 |
2224 | if ( primitive.vcount !== undefined ) {
2225 |
2226 | var index = 0;
2227 |
2228 | for ( var i = 0, l = vcount.length; i < l; i ++ ) {
2229 |
2230 | var count = vcount[ i ];
2231 |
2232 | if ( count === 4 ) {
2233 |
2234 | var a = index + stride * 0;
2235 | var b = index + stride * 1;
2236 | var c = index + stride * 2;
2237 | var d = index + stride * 3;
2238 |
2239 | pushVector( a ); pushVector( b ); pushVector( d );
2240 | pushVector( b ); pushVector( c ); pushVector( d );
2241 |
2242 | } else if ( count === 3 ) {
2243 |
2244 | var a = index + stride * 0;
2245 | var b = index + stride * 1;
2246 | var c = index + stride * 2;
2247 |
2248 | pushVector( a ); pushVector( b ); pushVector( c );
2249 |
2250 | } else {
2251 |
2252 | maxcount = Math.max( maxcount, count );
2253 |
2254 | }
2255 |
2256 | index += stride * count;
2257 |
2258 | }
2259 |
2260 | if ( maxcount > 0 ) {
2261 |
2262 | console.log( 'THREE.ColladaLoader: Geometry has faces with more than 4 vertices.' );
2263 |
2264 | }
2265 |
2266 | } else {
2267 |
2268 | for ( var i = 0, l = indices.length; i < l; i += stride ) {
2269 |
2270 | pushVector( i );
2271 |
2272 | }
2273 |
2274 | }
2275 |
2276 | }
2277 |
2278 | function getGeometry( id ) {
2279 |
2280 | return getBuild( library.geometries[ id ], buildGeometry );
2281 |
2282 | }
2283 |
2284 | // kinematics
2285 |
2286 | function parseKinematicsModel( xml ) {
2287 |
2288 | var data = {
2289 | name: xml.getAttribute( 'name' ) || '',
2290 | joints: {},
2291 | links: []
2292 | };
2293 |
2294 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
2295 |
2296 | var child = xml.childNodes[ i ];
2297 |
2298 | if ( child.nodeType !== 1 ) continue;
2299 |
2300 | switch ( child.nodeName ) {
2301 |
2302 | case 'technique_common':
2303 | parseKinematicsTechniqueCommon( child, data );
2304 | break;
2305 |
2306 | }
2307 |
2308 | }
2309 |
2310 | library.kinematicsModels[ xml.getAttribute( 'id' ) ] = data;
2311 |
2312 | }
2313 |
2314 | function buildKinematicsModel( data ) {
2315 |
2316 | if ( data.build !== undefined ) return data.build;
2317 |
2318 | return data;
2319 |
2320 | }
2321 |
2322 | function getKinematicsModel( id ) {
2323 |
2324 | return getBuild( library.kinematicsModels[ id ], buildKinematicsModel );
2325 |
2326 | }
2327 |
2328 | function parseKinematicsTechniqueCommon( xml, data ) {
2329 |
2330 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
2331 |
2332 | var child = xml.childNodes[ i ];
2333 |
2334 | if ( child.nodeType !== 1 ) continue;
2335 |
2336 | switch ( child.nodeName ) {
2337 |
2338 | case 'joint':
2339 | data.joints[ child.getAttribute( 'sid' ) ] = parseKinematicsJoint( child );
2340 | break;
2341 |
2342 | case 'link':
2343 | data.links.push( parseKinematicsLink( child ) );
2344 | break;
2345 |
2346 | }
2347 |
2348 | }
2349 |
2350 | }
2351 |
2352 | function parseKinematicsJoint( xml ) {
2353 |
2354 | var data;
2355 |
2356 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
2357 |
2358 | var child = xml.childNodes[ i ];
2359 |
2360 | if ( child.nodeType !== 1 ) continue;
2361 |
2362 | switch ( child.nodeName ) {
2363 |
2364 | case 'prismatic':
2365 | case 'revolute':
2366 | data = parseKinematicsJointParameter( child );
2367 | break;
2368 |
2369 | }
2370 |
2371 | }
2372 |
2373 | return data;
2374 |
2375 | }
2376 |
2377 | function parseKinematicsJointParameter( xml, data ) {
2378 |
2379 | var data = {
2380 | sid: xml.getAttribute( 'sid' ),
2381 | name: xml.getAttribute( 'name' ) || '',
2382 | axis: new THREE.Vector3(),
2383 | limits: {
2384 | min: 0,
2385 | max: 0
2386 | },
2387 | type: xml.nodeName,
2388 | static: false,
2389 | zeroPosition: 0,
2390 | middlePosition: 0
2391 | };
2392 |
2393 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
2394 |
2395 | var child = xml.childNodes[ i ];
2396 |
2397 | if ( child.nodeType !== 1 ) continue;
2398 |
2399 | switch ( child.nodeName ) {
2400 |
2401 | case 'axis':
2402 | var array = parseFloats( child.textContent );
2403 | data.axis.fromArray( array );
2404 | break;
2405 | case 'limits':
2406 | var max = child.getElementsByTagName( 'max' )[ 0 ];
2407 | var min = child.getElementsByTagName( 'min' )[ 0 ];
2408 |
2409 | data.limits.max = parseFloat( max.textContent );
2410 | data.limits.min = parseFloat( min.textContent );
2411 | break;
2412 |
2413 | }
2414 |
2415 | }
2416 |
2417 | // if min is equal to or greater than max, consider the joint static
2418 |
2419 | if ( data.limits.min >= data.limits.max ) {
2420 |
2421 | data.static = true;
2422 |
2423 | }
2424 |
2425 | // calculate middle position
2426 |
2427 | data.middlePosition = ( data.limits.min + data.limits.max ) / 2.0;
2428 |
2429 | return data;
2430 |
2431 | }
2432 |
2433 | function parseKinematicsLink( xml ) {
2434 |
2435 | var data = {
2436 | sid: xml.getAttribute( 'sid' ),
2437 | name: xml.getAttribute( 'name' ) || '',
2438 | attachments: [],
2439 | transforms: []
2440 | };
2441 |
2442 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
2443 |
2444 | var child = xml.childNodes[ i ];
2445 |
2446 | if ( child.nodeType !== 1 ) continue;
2447 |
2448 | switch ( child.nodeName ) {
2449 |
2450 | case 'attachment_full':
2451 | data.attachments.push( parseKinematicsAttachment( child ) );
2452 | break;
2453 |
2454 | case 'matrix':
2455 | case 'translate':
2456 | case 'rotate':
2457 | data.transforms.push( parseKinematicsTransform( child ) );
2458 | break;
2459 |
2460 | }
2461 |
2462 | }
2463 |
2464 | return data;
2465 |
2466 | }
2467 |
2468 | function parseKinematicsAttachment( xml ) {
2469 |
2470 | var data = {
2471 | joint: xml.getAttribute( 'joint' ).split( '/' ).pop(),
2472 | transforms: [],
2473 | links: []
2474 | };
2475 |
2476 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
2477 |
2478 | var child = xml.childNodes[ i ];
2479 |
2480 | if ( child.nodeType !== 1 ) continue;
2481 |
2482 | switch ( child.nodeName ) {
2483 |
2484 | case 'link':
2485 | data.links.push( parseKinematicsLink( child ) );
2486 | break;
2487 |
2488 | case 'matrix':
2489 | case 'translate':
2490 | case 'rotate':
2491 | data.transforms.push( parseKinematicsTransform( child ) );
2492 | break;
2493 |
2494 | }
2495 |
2496 | }
2497 |
2498 | return data;
2499 |
2500 | }
2501 |
2502 | function parseKinematicsTransform( xml ) {
2503 |
2504 | var data = {
2505 | type: xml.nodeName
2506 | };
2507 |
2508 | var array = parseFloats( xml.textContent );
2509 |
2510 | switch ( data.type ) {
2511 |
2512 | case 'matrix':
2513 | data.obj = new THREE.Matrix4();
2514 | data.obj.fromArray( array ).transpose();
2515 | break;
2516 |
2517 | case 'translate':
2518 | data.obj = new THREE.Vector3();
2519 | data.obj.fromArray( array );
2520 | break;
2521 |
2522 | case 'rotate':
2523 | data.obj = new THREE.Vector3();
2524 | data.obj.fromArray( array );
2525 | data.angle = THREE.Math.degToRad( array[ 3 ] );
2526 | break;
2527 |
2528 | }
2529 |
2530 | return data;
2531 |
2532 | }
2533 |
2534 | function parseKinematicsScene( xml ) {
2535 |
2536 | var data = {
2537 | bindJointAxis: []
2538 | };
2539 |
2540 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
2541 |
2542 | var child = xml.childNodes[ i ];
2543 |
2544 | if ( child.nodeType !== 1 ) continue;
2545 |
2546 | switch ( child.nodeName ) {
2547 |
2548 | case 'bind_joint_axis':
2549 | data.bindJointAxis.push( parseKinematicsBindJointAxis( child ) );
2550 | break;
2551 |
2552 | }
2553 |
2554 | }
2555 |
2556 | library.kinematicsScenes[ parseId( xml.getAttribute( 'url' ) ) ] = data;
2557 |
2558 | }
2559 |
2560 | function parseKinematicsBindJointAxis( xml ) {
2561 |
2562 | var data = {
2563 | target: xml.getAttribute( 'target' ).split( '/' ).pop()
2564 | };
2565 |
2566 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
2567 |
2568 | var child = xml.childNodes[ i ];
2569 |
2570 | if ( child.nodeType !== 1 ) continue;
2571 |
2572 | switch ( child.nodeName ) {
2573 |
2574 | case 'axis':
2575 | var param = child.getElementsByTagName( 'param' )[ 0 ];
2576 | data.axis = param.textContent;
2577 | var tmpJointIndex = data.axis.split( 'inst_' ).pop().split( 'axis' )[ 0 ];
2578 | data.jointIndex = tmpJointIndex.substr( 0, tmpJointIndex.length - 1 );
2579 | break;
2580 |
2581 | }
2582 |
2583 | }
2584 |
2585 | return data;
2586 |
2587 | }
2588 |
2589 | function buildKinematicsScene( data ) {
2590 |
2591 | if ( data.build !== undefined ) return data.build;
2592 |
2593 | return data;
2594 |
2595 | }
2596 |
2597 | function getKinematicsScene( id ) {
2598 |
2599 | return getBuild( library.kinematicsScenes[ id ], buildKinematicsScene );
2600 |
2601 | }
2602 |
2603 | function setupKinematics() {
2604 |
2605 | var kinematicsModelId = Object.keys( library.kinematicsModels )[ 0 ];
2606 | var kinematicsSceneId = Object.keys( library.kinematicsScenes )[ 0 ];
2607 | var visualSceneId = Object.keys( library.visualScenes )[ 0 ];
2608 |
2609 | if ( kinematicsModelId === undefined || kinematicsSceneId === undefined ) return;
2610 |
2611 | var kinematicsModel = getKinematicsModel( kinematicsModelId );
2612 | var kinematicsScene = getKinematicsScene( kinematicsSceneId );
2613 | var visualScene = getVisualScene( visualSceneId );
2614 |
2615 | var bindJointAxis = kinematicsScene.bindJointAxis;
2616 | var jointMap = {};
2617 |
2618 | for ( var i = 0, l = bindJointAxis.length; i < l; i ++ ) {
2619 |
2620 | var axis = bindJointAxis[ i ];
2621 |
2622 | // the result of the following query is an element of type 'translate', 'rotate','scale' or 'matrix'
2623 |
2624 | var targetElement = collada.querySelector( '[sid="' + axis.target + '"]' );
2625 |
2626 | if ( targetElement ) {
2627 |
2628 | // get the parent of the transfrom element
2629 |
2630 | var parentVisualElement = targetElement.parentElement;
2631 |
2632 | // connect the joint of the kinematics model with the element in the visual scene
2633 |
2634 | connect( axis.jointIndex, parentVisualElement );
2635 |
2636 | }
2637 |
2638 | }
2639 |
2640 | function connect( jointIndex, visualElement ) {
2641 |
2642 | var visualElementName = visualElement.getAttribute( 'name' );
2643 | var joint = kinematicsModel.joints[ jointIndex ];
2644 |
2645 | visualScene.traverse( function ( object ) {
2646 |
2647 | if ( object.name === visualElementName ) {
2648 |
2649 | jointMap[ jointIndex ] = {
2650 | object: object,
2651 | transforms: buildTransformList( visualElement ),
2652 | joint: joint,
2653 | position: joint.zeroPosition
2654 | };
2655 |
2656 | }
2657 |
2658 | } );
2659 |
2660 | }
2661 |
2662 | var m0 = new THREE.Matrix4();
2663 |
2664 | kinematics = {
2665 |
2666 | joints: kinematicsModel && kinematicsModel.joints,
2667 |
2668 | getJointValue: function ( jointIndex ) {
2669 |
2670 | var jointData = jointMap[ jointIndex ];
2671 |
2672 | if ( jointData ) {
2673 |
2674 | return jointData.position;
2675 |
2676 | } else {
2677 |
2678 | console.warn( 'THREE.ColladaLoader: Joint ' + jointIndex + ' doesn\'t exist.' );
2679 |
2680 | }
2681 |
2682 | },
2683 |
2684 | setJointValue: function ( jointIndex, value ) {
2685 |
2686 | var jointData = jointMap[ jointIndex ];
2687 |
2688 | if ( jointData ) {
2689 |
2690 | var joint = jointData.joint;
2691 |
2692 | if ( value > joint.limits.max || value < joint.limits.min ) {
2693 |
2694 | console.warn( 'THREE.ColladaLoader: Joint ' + jointIndex + ' value ' + value + ' outside of limits (min: ' + joint.limits.min + ', max: ' + joint.limits.max + ').' );
2695 |
2696 | } else if ( joint.static ) {
2697 |
2698 | console.warn( 'THREE.ColladaLoader: Joint ' + jointIndex + ' is static.' );
2699 |
2700 | } else {
2701 |
2702 | var object = jointData.object;
2703 | var axis = joint.axis;
2704 | var transforms = jointData.transforms;
2705 |
2706 | matrix.identity();
2707 |
2708 | // each update, we have to apply all transforms in the correct order
2709 |
2710 | for ( var i = 0; i < transforms.length; i ++ ) {
2711 |
2712 | var transform = transforms[ i ];
2713 |
2714 | // if there is a connection of the transform node with a joint, apply the joint value
2715 |
2716 | if ( transform.sid && transform.sid.indexOf( jointIndex ) !== - 1 ) {
2717 |
2718 | switch ( joint.type ) {
2719 |
2720 | case 'revolute':
2721 | matrix.multiply( m0.makeRotationAxis( axis, THREE.Math.degToRad( value ) ) );
2722 | break;
2723 |
2724 | case 'prismatic':
2725 | matrix.multiply( m0.makeTranslation( axis.x * value, axis.y * value, axis.z * value ) );
2726 | break;
2727 |
2728 | default:
2729 | console.warn( 'THREE.ColladaLoader: Unknown joint type: ' + joint.type );
2730 | break;
2731 |
2732 | }
2733 |
2734 | } else {
2735 |
2736 | switch ( transform.type ) {
2737 |
2738 | case 'matrix':
2739 | matrix.multiply( transform.obj );
2740 | break;
2741 |
2742 | case 'translate':
2743 | matrix.multiply( m0.makeTranslation( transform.obj.x, transform.obj.y, transform.obj.z ) );
2744 | break;
2745 |
2746 | case 'scale':
2747 | matrix.scale( transform.obj );
2748 | break;
2749 |
2750 | case 'rotate':
2751 | matrix.multiply( m0.makeRotationAxis( transform.obj, transform.angle ) );
2752 | break;
2753 |
2754 | }
2755 |
2756 | }
2757 |
2758 | }
2759 |
2760 | object.matrix.copy( matrix );
2761 | object.matrix.decompose( object.position, object.quaternion, object.scale );
2762 |
2763 | jointMap[ jointIndex ].position = value;
2764 |
2765 | }
2766 |
2767 | } else {
2768 |
2769 | console.log( 'THREE.ColladaLoader: ' + jointIndex + ' does not exist.' );
2770 |
2771 | }
2772 |
2773 | }
2774 |
2775 | };
2776 |
2777 | }
2778 |
2779 | function buildTransformList( node ) {
2780 |
2781 | var transforms = [];
2782 |
2783 | var xml = collada.querySelector( '[id="' + node.id + '"]' );
2784 |
2785 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
2786 |
2787 | var child = xml.childNodes[ i ];
2788 |
2789 | if ( child.nodeType !== 1 ) continue;
2790 |
2791 | switch ( child.nodeName ) {
2792 |
2793 | case 'matrix':
2794 | var array = parseFloats( child.textContent );
2795 | var matrix = new THREE.Matrix4().fromArray( array ).transpose();
2796 | transforms.push( {
2797 | sid: child.getAttribute( 'sid' ),
2798 | type: child.nodeName,
2799 | obj: matrix
2800 | } );
2801 | break;
2802 |
2803 | case 'translate':
2804 | case 'scale':
2805 | var array = parseFloats( child.textContent );
2806 | var vector = new THREE.Vector3().fromArray( array );
2807 | transforms.push( {
2808 | sid: child.getAttribute( 'sid' ),
2809 | type: child.nodeName,
2810 | obj: vector
2811 | } );
2812 | break;
2813 |
2814 | case 'rotate':
2815 | var array = parseFloats( child.textContent );
2816 | var vector = new THREE.Vector3().fromArray( array );
2817 | var angle = THREE.Math.degToRad( array[ 3 ] );
2818 | transforms.push( {
2819 | sid: child.getAttribute( 'sid' ),
2820 | type: child.nodeName,
2821 | obj: vector,
2822 | angle: angle
2823 | } );
2824 | break;
2825 |
2826 | }
2827 |
2828 | }
2829 |
2830 | return transforms;
2831 |
2832 | }
2833 |
2834 | // nodes
2835 |
2836 | function prepareNodes( xml ) {
2837 |
2838 | var elements = xml.getElementsByTagName( 'node' );
2839 |
2840 | // ensure all node elements have id attributes
2841 |
2842 | for ( var i = 0; i < elements.length; i ++ ) {
2843 |
2844 | var element = elements[ i ];
2845 |
2846 | if ( element.hasAttribute( 'id' ) === false ) {
2847 |
2848 | element.setAttribute( 'id', generateId() );
2849 |
2850 | }
2851 |
2852 | }
2853 |
2854 | }
2855 |
2856 | var matrix = new THREE.Matrix4();
2857 | var vector = new THREE.Vector3();
2858 |
2859 | function parseNode( xml ) {
2860 |
2861 | var data = {
2862 | name: xml.getAttribute( 'name' ) || '',
2863 | type: xml.getAttribute( 'type' ),
2864 | id: xml.getAttribute( 'id' ),
2865 | sid: xml.getAttribute( 'sid' ),
2866 | matrix: new THREE.Matrix4(),
2867 | nodes: [],
2868 | instanceCameras: [],
2869 | instanceControllers: [],
2870 | instanceLights: [],
2871 | instanceGeometries: [],
2872 | instanceNodes: [],
2873 | transforms: {}
2874 | };
2875 |
2876 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
2877 |
2878 | var child = xml.childNodes[ i ];
2879 |
2880 | if ( child.nodeType !== 1 ) continue;
2881 |
2882 | switch ( child.nodeName ) {
2883 |
2884 | case 'node':
2885 | data.nodes.push( child.getAttribute( 'id' ) );
2886 | parseNode( child );
2887 | break;
2888 |
2889 | case 'instance_camera':
2890 | data.instanceCameras.push( parseId( child.getAttribute( 'url' ) ) );
2891 | break;
2892 |
2893 | case 'instance_controller':
2894 | data.instanceControllers.push( parseNodeInstance( child ) );
2895 | break;
2896 |
2897 | case 'instance_light':
2898 | data.instanceLights.push( parseId( child.getAttribute( 'url' ) ) );
2899 | break;
2900 |
2901 | case 'instance_geometry':
2902 | data.instanceGeometries.push( parseNodeInstance( child ) );
2903 | break;
2904 |
2905 | case 'instance_node':
2906 | data.instanceNodes.push( parseId( child.getAttribute( 'url' ) ) );
2907 | break;
2908 |
2909 | case 'matrix':
2910 | var array = parseFloats( child.textContent );
2911 | data.matrix.multiply( matrix.fromArray( array ).transpose() );
2912 | data.transforms[ child.getAttribute( 'sid' ) ] = child.nodeName;
2913 | break;
2914 |
2915 | case 'translate':
2916 | var array = parseFloats( child.textContent );
2917 | vector.fromArray( array );
2918 | data.matrix.multiply( matrix.makeTranslation( vector.x, vector.y, vector.z ) );
2919 | data.transforms[ child.getAttribute( 'sid' ) ] = child.nodeName;
2920 | break;
2921 |
2922 | case 'rotate':
2923 | var array = parseFloats( child.textContent );
2924 | var angle = THREE.Math.degToRad( array[ 3 ] );
2925 | data.matrix.multiply( matrix.makeRotationAxis( vector.fromArray( array ), angle ) );
2926 | data.transforms[ child.getAttribute( 'sid' ) ] = child.nodeName;
2927 | break;
2928 |
2929 | case 'scale':
2930 | var array = parseFloats( child.textContent );
2931 | data.matrix.scale( vector.fromArray( array ) );
2932 | data.transforms[ child.getAttribute( 'sid' ) ] = child.nodeName;
2933 | break;
2934 |
2935 | case 'extra':
2936 | break;
2937 |
2938 | default:
2939 | console.log( child );
2940 |
2941 | }
2942 |
2943 | }
2944 |
2945 | library.nodes[ data.id ] = data;
2946 |
2947 | return data;
2948 |
2949 | }
2950 |
2951 | function parseNodeInstance( xml ) {
2952 |
2953 | var data = {
2954 | id: parseId( xml.getAttribute( 'url' ) ),
2955 | materials: {},
2956 | skeletons: []
2957 | };
2958 |
2959 | for ( var i = 0; i < xml.childNodes.length; i ++ ) {
2960 |
2961 | var child = xml.childNodes[ i ];
2962 |
2963 | switch ( child.nodeName ) {
2964 |
2965 | case 'bind_material':
2966 | var instances = child.getElementsByTagName( 'instance_material' );
2967 |
2968 | for ( var j = 0; j < instances.length; j ++ ) {
2969 |
2970 | var instance = instances[ j ];
2971 | var symbol = instance.getAttribute( 'symbol' );
2972 | var target = instance.getAttribute( 'target' );
2973 |
2974 | data.materials[ symbol ] = parseId( target );
2975 |
2976 | }
2977 |
2978 | break;
2979 |
2980 | case 'skeleton':
2981 | data.skeletons.push( parseId( child.textContent ) );
2982 | break;
2983 |
2984 | default:
2985 | break;
2986 |
2987 | }
2988 |
2989 | }
2990 |
2991 | return data;
2992 |
2993 | }
2994 |
2995 | function buildSkeleton( skeletons, joints ) {
2996 |
2997 | var boneData = [];
2998 | var sortedBoneData = [];
2999 |
3000 | var i, j, data;
3001 |
3002 | // a skeleton can have multiple root bones. collada expresses this
3003 | // situtation with multiple "skeleton" tags per controller instance
3004 |
3005 | for ( i = 0; i < skeletons.length; i ++ ) {
3006 |
3007 | var skeleton = skeletons[ i ];
3008 | var root = getNode( skeleton );
3009 |
3010 | // setup bone data for a single bone hierarchy
3011 |
3012 | buildBoneHierarchy( root, joints, boneData );
3013 |
3014 | }
3015 |
3016 | // sort bone data (the order is defined in the corresponding controller)
3017 |
3018 | for ( i = 0; i < joints.length; i ++ ) {
3019 |
3020 | for ( j = 0; j < boneData.length; j ++ ) {
3021 |
3022 | data = boneData[ j ];
3023 |
3024 | if ( data.bone.name === joints[ i ].name ) {
3025 |
3026 | sortedBoneData[ i ] = data;
3027 | data.processed = true;
3028 | break;
3029 |
3030 | }
3031 |
3032 | }
3033 |
3034 | }
3035 |
3036 | // add unprocessed bone data at the end of the list
3037 |
3038 | for ( i = 0; i < boneData.length; i ++ ) {
3039 |
3040 | data = boneData[ i ];
3041 |
3042 | if ( data.processed === false ) {
3043 |
3044 | sortedBoneData.push( data );
3045 | data.processed = true;
3046 |
3047 | }
3048 |
3049 | }
3050 |
3051 | // setup arrays for skeleton creation
3052 |
3053 | var bones = [];
3054 | var boneInverses = [];
3055 |
3056 | for ( i = 0; i < sortedBoneData.length; i ++ ) {
3057 |
3058 | data = sortedBoneData[ i ];
3059 |
3060 | bones.push( data.bone );
3061 | boneInverses.push( data.boneInverse );
3062 |
3063 | }
3064 |
3065 | return new THREE.Skeleton( bones, boneInverses );
3066 |
3067 | }
3068 |
3069 | function buildBoneHierarchy( root, joints, boneData ) {
3070 |
3071 | // setup bone data from visual scene
3072 |
3073 | root.traverse( function ( object ) {
3074 |
3075 | if ( object.isBone === true ) {
3076 |
3077 | var boneInverse;
3078 |
3079 | // retrieve the boneInverse from the controller data
3080 |
3081 | for ( var i = 0; i < joints.length; i ++ ) {
3082 |
3083 | var joint = joints[ i ];
3084 |
3085 | if ( joint.name === object.name ) {
3086 |
3087 | boneInverse = joint.boneInverse;
3088 | break;
3089 |
3090 | }
3091 |
3092 | }
3093 |
3094 | if ( boneInverse === undefined ) {
3095 |
3096 | // Unfortunately, there can be joints in the visual scene that are not part of the
3097 | // corresponding controller. In this case, we have to create a dummy boneInverse matrix
3098 | // for the respective bone. This bone won't affect any vertices, because there are no skin indices
3099 | // and weights defined for it. But we still have to add the bone to the sorted bone list in order to
3100 | // ensure a correct animation of the model.
3101 |
3102 | boneInverse = new THREE.Matrix4();
3103 |
3104 | }
3105 |
3106 | boneData.push( { bone: object, boneInverse: boneInverse, processed: false } );
3107 |
3108 | }
3109 |
3110 | } );
3111 |
3112 | }
3113 |
3114 | function buildNode( data ) {
3115 |
3116 | var objects = [];
3117 |
3118 | var matrix = data.matrix;
3119 | var nodes = data.nodes;
3120 | var type = data.type;
3121 | var instanceCameras = data.instanceCameras;
3122 | var instanceControllers = data.instanceControllers;
3123 | var instanceLights = data.instanceLights;
3124 | var instanceGeometries = data.instanceGeometries;
3125 | var instanceNodes = data.instanceNodes;
3126 |
3127 | // nodes
3128 |
3129 | for ( var i = 0, l = nodes.length; i < l; i ++ ) {
3130 |
3131 | objects.push( getNode( nodes[ i ] ) );
3132 |
3133 | }
3134 |
3135 | // instance cameras
3136 |
3137 | for ( var i = 0, l = instanceCameras.length; i < l; i ++ ) {
3138 |
3139 | var instanceCamera = getCamera( instanceCameras[ i ] );
3140 |
3141 | if ( instanceCamera !== null ) {
3142 |
3143 | objects.push( instanceCamera.clone() );
3144 |
3145 | }
3146 |
3147 | }
3148 |
3149 | // instance controllers
3150 |
3151 | for ( var i = 0, l = instanceControllers.length; i < l; i ++ ) {
3152 |
3153 | var instance = instanceControllers[ i ];
3154 | var controller = getController( instance.id );
3155 | var geometries = getGeometry( controller.id );
3156 | var newObjects = buildObjects( geometries, instance.materials );
3157 |
3158 | var skeletons = instance.skeletons;
3159 | var joints = controller.skin.joints;
3160 |
3161 | var skeleton = buildSkeleton( skeletons, joints );
3162 |
3163 | for ( var j = 0, jl = newObjects.length; j < jl; j ++ ) {
3164 |
3165 | var object = newObjects[ j ];
3166 |
3167 | if ( object.isSkinnedMesh ) {
3168 |
3169 | object.bind( skeleton, controller.skin.bindMatrix );
3170 | object.normalizeSkinWeights();
3171 |
3172 | }
3173 |
3174 | objects.push( object );
3175 |
3176 | }
3177 |
3178 | }
3179 |
3180 | // instance lights
3181 |
3182 | for ( var i = 0, l = instanceLights.length; i < l; i ++ ) {
3183 |
3184 | var instanceLight = getLight( instanceLights[ i ] );
3185 |
3186 | if ( instanceLight !== null ) {
3187 |
3188 | objects.push( instanceLight.clone() );
3189 |
3190 | }
3191 |
3192 | }
3193 |
3194 | // instance geometries
3195 |
3196 | for ( var i = 0, l = instanceGeometries.length; i < l; i ++ ) {
3197 |
3198 | var instance = instanceGeometries[ i ];
3199 |
3200 | // a single geometry instance in collada can lead to multiple object3Ds.
3201 | // this is the case when primitives are combined like triangles and lines
3202 |
3203 | var geometries = getGeometry( instance.id );
3204 | var newObjects = buildObjects( geometries, instance.materials );
3205 |
3206 | for ( var j = 0, jl = newObjects.length; j < jl; j ++ ) {
3207 |
3208 | objects.push( newObjects[ j ] );
3209 |
3210 | }
3211 |
3212 | }
3213 |
3214 | // instance nodes
3215 |
3216 | for ( var i = 0, l = instanceNodes.length; i < l; i ++ ) {
3217 |
3218 | objects.push( getNode( instanceNodes[ i ] ).clone() );
3219 |
3220 | }
3221 |
3222 | var object;
3223 |
3224 | if ( nodes.length === 0 && objects.length === 1 ) {
3225 |
3226 | object = objects[ 0 ];
3227 |
3228 | } else {
3229 |
3230 | object = ( type === 'JOINT' ) ? new THREE.Bone() : new THREE.Group();
3231 |
3232 | for ( var i = 0; i < objects.length; i ++ ) {
3233 |
3234 | object.add( objects[ i ] );
3235 |
3236 | }
3237 |
3238 | }
3239 |
3240 | object.name = ( type === 'JOINT' ) ? data.sid : data.name;
3241 | object.matrix.copy( matrix );
3242 | object.matrix.decompose( object.position, object.quaternion, object.scale );
3243 |
3244 | return object;
3245 |
3246 | }
3247 |
3248 | function resolveMaterialBinding( keys, instanceMaterials ) {
3249 |
3250 | var materials = [];
3251 |
3252 | for ( var i = 0, l = keys.length; i < l; i ++ ) {
3253 |
3254 | var id = instanceMaterials[ keys[ i ] ];
3255 | materials.push( getMaterial( id ) );
3256 |
3257 | }
3258 |
3259 | return materials;
3260 |
3261 | }
3262 |
3263 | function buildObjects( geometries, instanceMaterials ) {
3264 |
3265 | var objects = [];
3266 |
3267 | for ( var type in geometries ) {
3268 |
3269 | var geometry = geometries[ type ];
3270 |
3271 | var materials = resolveMaterialBinding( geometry.materialKeys, instanceMaterials );
3272 |
3273 | // handle case if no materials are defined
3274 |
3275 | if ( materials.length === 0 ) {
3276 |
3277 | if ( type === 'lines' || type === 'linestrips' ) {
3278 |
3279 | materials.push( new THREE.LineBasicMaterial() );
3280 |
3281 | } else {
3282 |
3283 | materials.push( new THREE.MeshPhongMaterial() );
3284 |
3285 | }
3286 |
3287 | }
3288 |
3289 | // regard skinning
3290 |
3291 | var skinning = ( geometry.data.attributes.skinIndex !== undefined );
3292 |
3293 | if ( skinning ) {
3294 |
3295 | for ( var i = 0, l = materials.length; i < l; i ++ ) {
3296 |
3297 | materials[ i ].skinning = true;
3298 |
3299 | }
3300 |
3301 | }
3302 |
3303 | // choose between a single or multi materials (material array)
3304 |
3305 | var material = ( materials.length === 1 ) ? materials[ 0 ] : materials;
3306 |
3307 | // now create a specific 3D object
3308 |
3309 | var object;
3310 |
3311 | switch ( type ) {
3312 |
3313 | case 'lines':
3314 | object = new THREE.LineSegments( geometry.data, material );
3315 | break;
3316 |
3317 | case 'linestrips':
3318 | object = new THREE.Line( geometry.data, material );
3319 | break;
3320 |
3321 | case 'triangles':
3322 | case 'polylist':
3323 | if ( skinning ) {
3324 |
3325 | object = new THREE.SkinnedMesh( geometry.data, material );
3326 |
3327 | } else {
3328 |
3329 | object = new THREE.Mesh( geometry.data, material );
3330 |
3331 | }
3332 | break;
3333 |
3334 | }
3335 |
3336 | objects.push( object );
3337 |
3338 | }
3339 |
3340 | return objects;
3341 |
3342 | }
3343 |
3344 | function getNode( id ) {
3345 |
3346 | return getBuild( library.nodes[ id ], buildNode );
3347 |
3348 | }
3349 |
3350 | // visual scenes
3351 |
3352 | function parseVisualScene( xml ) {
3353 |
3354 | var data = {
3355 | name: xml.getAttribute( 'name' ),
3356 | children: []
3357 | };
3358 |
3359 | prepareNodes( xml );
3360 |
3361 | var elements = getElementsByTagName( xml, 'node' );
3362 |
3363 | for ( var i = 0; i < elements.length; i ++ ) {
3364 |
3365 | data.children.push( parseNode( elements[ i ] ) );
3366 |
3367 | }
3368 |
3369 | library.visualScenes[ xml.getAttribute( 'id' ) ] = data;
3370 |
3371 | }
3372 |
3373 | function buildVisualScene( data ) {
3374 |
3375 | var group = new THREE.Group();
3376 | group.name = data.name;
3377 |
3378 | var children = data.children;
3379 |
3380 | for ( var i = 0; i < children.length; i ++ ) {
3381 |
3382 | var child = children[ i ];
3383 |
3384 | if ( child.id === null ) {
3385 |
3386 | group.add( buildNode( child ) );
3387 |
3388 | } else {
3389 |
3390 | // if there is an ID, let's try to get the finished build (e.g. joints are already build)
3391 |
3392 | group.add( getNode( child.id ) );
3393 |
3394 | }
3395 |
3396 | }
3397 |
3398 | return group;
3399 |
3400 | }
3401 |
3402 | function getVisualScene( id ) {
3403 |
3404 | return getBuild( library.visualScenes[ id ], buildVisualScene );
3405 |
3406 | }
3407 |
3408 | // scenes
3409 |
3410 | function parseScene( xml ) {
3411 |
3412 | var instance = getElementsByTagName( xml, 'instance_visual_scene' )[ 0 ];
3413 | return getVisualScene( parseId( instance.getAttribute( 'url' ) ) );
3414 |
3415 | }
3416 |
3417 | function setupAnimations() {
3418 |
3419 | var clips = library.clips;
3420 |
3421 | if ( isEmpty( clips ) === true ) {
3422 |
3423 | if ( isEmpty( library.animations ) === false ) {
3424 |
3425 | // if there are animations but no clips, we create a default clip for playback
3426 |
3427 | var tracks = [];
3428 |
3429 | for ( var id in library.animations ) {
3430 |
3431 | var animationTracks = getAnimation( id );
3432 |
3433 | for ( var i = 0, l = animationTracks.length; i < l; i ++ ) {
3434 |
3435 | tracks.push( animationTracks[ i ] );
3436 |
3437 | }
3438 |
3439 | }
3440 |
3441 | animations.push( new THREE.AnimationClip( 'default', - 1, tracks ) );
3442 |
3443 | }
3444 |
3445 | } else {
3446 |
3447 | for ( var id in clips ) {
3448 |
3449 | animations.push( getAnimationClip( id ) );
3450 |
3451 | }
3452 |
3453 | }
3454 |
3455 | }
3456 |
3457 | console.time( 'THREE.ColladaLoader' );
3458 |
3459 | if ( text.length === 0 ) {
3460 |
3461 | return { scene: new THREE.Scene() };
3462 |
3463 | }
3464 |
3465 | console.time( 'THREE.ColladaLoader: DOMParser' );
3466 |
3467 | var xml = new DOMParser().parseFromString( text, 'application/xml' );
3468 |
3469 | console.timeEnd( 'THREE.ColladaLoader: DOMParser' );
3470 |
3471 | var collada = getElementsByTagName( xml, 'COLLADA' )[ 0 ];
3472 |
3473 | // metadata
3474 |
3475 | var version = collada.getAttribute( 'version' );
3476 | console.log( 'THREE.ColladaLoader: File version', version );
3477 |
3478 | var asset = parseAsset( getElementsByTagName( collada, 'asset' )[ 0 ] );
3479 | var textureLoader = new THREE.TextureLoader( this.manager );
3480 | textureLoader.setPath( path ).setCrossOrigin( this.crossOrigin );
3481 |
3482 | //
3483 |
3484 | var animations = [];
3485 | var kinematics = {};
3486 | var count = 0;
3487 |
3488 | //
3489 |
3490 | var library = {
3491 | animations: {},
3492 | clips: {},
3493 | controllers: {},
3494 | images: {},
3495 | effects: {},
3496 | materials: {},
3497 | cameras: {},
3498 | lights: {},
3499 | geometries: {},
3500 | nodes: {},
3501 | visualScenes: {},
3502 | kinematicsModels: {},
3503 | kinematicsScenes: {}
3504 | };
3505 |
3506 | console.time( 'THREE.ColladaLoader: Parse' );
3507 |
3508 | parseLibrary( collada, 'library_animations', 'animation', parseAnimation );
3509 | parseLibrary( collada, 'library_animation_clips', 'animation_clip', parseAnimationClip );
3510 | parseLibrary( collada, 'library_controllers', 'controller', parseController );
3511 | parseLibrary( collada, 'library_images', 'image', parseImage );
3512 | parseLibrary( collada, 'library_effects', 'effect', parseEffect );
3513 | parseLibrary( collada, 'library_materials', 'material', parseMaterial );
3514 | parseLibrary( collada, 'library_cameras', 'camera', parseCamera );
3515 | parseLibrary( collada, 'library_lights', 'light', parseLight );
3516 | parseLibrary( collada, 'library_geometries', 'geometry', parseGeometry );
3517 | parseLibrary( collada, 'library_nodes', 'node', parseNode );
3518 | parseLibrary( collada, 'library_visual_scenes', 'visual_scene', parseVisualScene );
3519 | parseLibrary( collada, 'library_kinematics_models', 'kinematics_model', parseKinematicsModel );
3520 | parseLibrary( collada, 'scene', 'instance_kinematics_scene', parseKinematicsScene );
3521 |
3522 | console.timeEnd( 'THREE.ColladaLoader: Parse' );
3523 |
3524 | console.time( 'THREE.ColladaLoader: Build' );
3525 |
3526 | buildLibrary( library.animations, buildAnimation );
3527 | buildLibrary( library.clips, buildAnimationClip );
3528 | buildLibrary( library.controllers, buildController );
3529 | buildLibrary( library.images, buildImage );
3530 | buildLibrary( library.effects, buildEffect );
3531 | buildLibrary( library.materials, buildMaterial );
3532 | buildLibrary( library.cameras, buildCamera );
3533 | buildLibrary( library.lights, buildLight );
3534 | buildLibrary( library.geometries, buildGeometry );
3535 | buildLibrary( library.visualScenes, buildVisualScene );
3536 |
3537 | console.timeEnd( 'THREE.ColladaLoader: Build' );
3538 |
3539 | setupAnimations();
3540 | setupKinematics();
3541 |
3542 | var scene = parseScene( getElementsByTagName( collada, 'scene' )[ 0 ] );
3543 |
3544 | if ( asset.upAxis === 'Z_UP' ) {
3545 |
3546 | scene.rotation.x = - Math.PI / 2;
3547 |
3548 | }
3549 |
3550 | scene.scale.multiplyScalar( asset.unit );
3551 |
3552 | console.timeEnd( 'THREE.ColladaLoader' );
3553 |
3554 | return {
3555 | animations: animations,
3556 | kinematics: kinematics,
3557 | library: library,
3558 | scene: scene
3559 | };
3560 |
3561 | }
3562 |
3563 | };
3564 |
--------------------------------------------------------------------------------
/js/VRControls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author dmarcos / https://github.com/dmarcos
3 | * @author mrdoob / http://mrdoob.com
4 | */
5 |
6 | THREE.VRControls = function ( object, onError ) {
7 |
8 | var scope = this;
9 |
10 | var vrDisplay, vrDisplays;
11 |
12 | var standingMatrix = new THREE.Matrix4();
13 |
14 | var frameData = null;
15 |
16 | if ( 'VRFrameData' in window ) {
17 |
18 | frameData = new VRFrameData();
19 |
20 | }
21 |
22 | function gotVRDisplays( displays ) {
23 |
24 | vrDisplays = displays;
25 |
26 | if ( displays.length > 0 ) {
27 |
28 | vrDisplay = displays[ 0 ];
29 |
30 | } else {
31 |
32 | if ( onError ) onError( 'VR input not available.' );
33 |
34 | }
35 |
36 | }
37 |
38 | if ( navigator.getVRDisplays ) {
39 |
40 | navigator.getVRDisplays().then( gotVRDisplays ).catch( function () {
41 |
42 | console.warn( 'THREE.VRControls: Unable to get VR Displays' );
43 |
44 | } );
45 |
46 | }
47 |
48 | // the Rift SDK returns the position in meters
49 | // this scale factor allows the user to define how meters
50 | // are converted to scene units.
51 |
52 | this.scale = 1;
53 |
54 | // If true will use "standing space" coordinate system where y=0 is the
55 | // floor and x=0, z=0 is the center of the room.
56 | this.standing = false;
57 |
58 | // Distance from the users eyes to the floor in meters. Used when
59 | // standing=true but the VRDisplay doesn't provide stageParameters.
60 | this.userHeight = 1.6;
61 |
62 | this.getVRDisplay = function () {
63 |
64 | return vrDisplay;
65 |
66 | };
67 |
68 | this.setVRDisplay = function ( value ) {
69 |
70 | vrDisplay = value;
71 |
72 | };
73 |
74 | this.getVRDisplays = function () {
75 |
76 | console.warn( 'THREE.VRControls: getVRDisplays() is being deprecated.' );
77 | return vrDisplays;
78 |
79 | };
80 |
81 | this.getStandingMatrix = function () {
82 |
83 | return standingMatrix;
84 |
85 | };
86 |
87 | this.update = function () {
88 |
89 | if ( vrDisplay ) {
90 |
91 | var pose;
92 |
93 | if ( vrDisplay.getFrameData ) {
94 |
95 | vrDisplay.getFrameData( frameData );
96 | pose = frameData.pose;
97 |
98 | } else if ( vrDisplay.getPose ) {
99 |
100 | pose = vrDisplay.getPose();
101 |
102 | }
103 |
104 | if ( pose.orientation !== null ) {
105 |
106 | object.quaternion.fromArray( pose.orientation );
107 |
108 | }
109 |
110 | if ( pose.position !== null ) {
111 |
112 | object.position.fromArray( pose.position );
113 |
114 | } else {
115 |
116 | object.position.set( 0, 0, 0 );
117 |
118 | }
119 |
120 | if ( this.standing ) {
121 |
122 | if ( vrDisplay.stageParameters ) {
123 |
124 | object.updateMatrix();
125 |
126 | standingMatrix.fromArray( vrDisplay.stageParameters.sittingToStandingTransform );
127 | object.applyMatrix( standingMatrix );
128 |
129 | } else {
130 |
131 | object.position.setY( object.position.y + this.userHeight );
132 |
133 | }
134 |
135 | }
136 |
137 | object.position.multiplyScalar( scope.scale );
138 |
139 | }
140 |
141 | };
142 |
143 | this.dispose = function () {
144 |
145 | vrDisplay = null;
146 |
147 | };
148 |
149 | };
150 |
--------------------------------------------------------------------------------
/js/inflate.min.js:
--------------------------------------------------------------------------------
1 | /** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */(function() {'use strict';var l=void 0,aa=this;function r(c,d){var a=c.split("."),b=aa;!(a[0]in b)&&b.execScript&&b.execScript("var "+a[0]);for(var e;a.length&&(e=a.shift());)!a.length&&d!==l?b[e]=d:b=b[e]?b[e]:b[e]={}};var t="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array&&"undefined"!==typeof DataView;function v(c){var d=c.length,a=0,b=Number.POSITIVE_INFINITY,e,f,g,h,k,m,n,p,s,x;for(p=0;pa&&(a=c[p]),c[p]>=1;x=g<<16|p;for(s=m;s>>=1;switch(c){case 0:var d=this.input,a=this.a,b=this.c,e=this.b,f=d.length,g=l,h=l,k=b.length,m=l;this.d=this.f=0;if(a+1>=f)throw Error("invalid uncompressed block header: LEN");g=d[a++]|d[a++]<<8;if(a+1>=f)throw Error("invalid uncompressed block header: NLEN");h=d[a++]|d[a++]<<8;if(g===~h)throw Error("invalid uncompressed block header: length verify");if(a+g>d.length)throw Error("input buffer is broken");switch(this.i){case A:for(;e+
4 | g>b.length;){m=k-e;g-=m;if(t)b.set(d.subarray(a,a+m),e),e+=m,a+=m;else for(;m--;)b[e++]=d[a++];this.b=e;b=this.e();e=this.b}break;case y:for(;e+g>b.length;)b=this.e({p:2});break;default:throw Error("invalid inflate mode");}if(t)b.set(d.subarray(a,a+g),e),e+=g,a+=g;else for(;g--;)b[e++]=d[a++];this.a=a;this.b=e;this.c=b;break;case 1:this.j(ba,ca);break;case 2:for(var n=C(this,5)+257,p=C(this,5)+1,s=C(this,4)+4,x=new (t?Uint8Array:Array)(D.length),S=l,T=l,U=l,u=l,M=l,F=l,z=l,q=l,V=l,q=0;q=P?8:255>=P?9:279>=P?7:8;var ba=v(O),Q=new (t?Uint8Array:Array)(30),R,ga;R=0;for(ga=Q.length;R=g)throw Error("input buffer is broken");a|=e[f++]<>>d;c.d=b-d;c.a=f;return h}
8 | function E(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h=d[0],k=d[1],m,n;b=g);)a|=e[f++]<>>16;if(n>b)throw Error("invalid code length: "+n);c.f=a>>n;c.d=b-n;c.a=f;return m&65535}
9 | w.prototype.j=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length-258,f,g,h,k;256!==(f=E(this,c));)if(256>f)b>=e&&(this.b=b,a=this.e(),b=this.b),a[b++]=f;else{g=f-257;k=I[g];0=e&&(this.b=b,a=this.e(),b=this.b);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b};
10 | w.prototype.w=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length,f,g,h,k;256!==(f=E(this,c));)if(256>f)b>=e&&(a=this.e(),e=a.length),a[b++]=f;else{g=f-257;k=I[g];0e&&(a=this.e(),e=a.length);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b};
11 | w.prototype.e=function(){var c=new (t?Uint8Array:Array)(this.b-32768),d=this.b-32768,a,b,e=this.c;if(t)c.set(e.subarray(32768,c.length));else{a=0;for(b=c.length;aa;++a)e[a]=e[d+a];this.b=32768;return e};
12 | w.prototype.z=function(c){var d,a=this.input.length/this.a+1|0,b,e,f,g=this.input,h=this.c;c&&("number"===typeof c.p&&(a=c.p),"number"===typeof c.u&&(a+=c.u));2>a?(b=(g.length-this.a)/this.o[2],f=258*(b/2)|0,e=fd&&(this.c.length=d),c=this.c);return this.buffer=c};function W(c,d){var a,b;this.input=c;this.a=0;if(d||!(d={}))d.index&&(this.a=d.index),d.verify&&(this.A=d.verify);a=c[this.a++];b=c[this.a++];switch(a&15){case ha:this.method=ha;break;default:throw Error("unsupported compression method");}if(0!==((a<<8)+b)%31)throw Error("invalid fcheck flag:"+((a<<8)+b)%31);if(b&32)throw Error("fdict flag is not supported");this.q=new w(c,{index:this.a,bufferSize:d.bufferSize,bufferType:d.bufferType,resize:d.resize})}
15 | W.prototype.k=function(){var c=this.input,d,a;d=this.q.k();this.a=this.q.a;if(this.A){a=(c[this.a++]<<24|c[this.a++]<<16|c[this.a++]<<8|c[this.a++])>>>0;var b=d;if("string"===typeof b){var e=b.split(""),f,g;f=0;for(g=e.length;f>>0;b=e}for(var h=1,k=0,m=b.length,n,p=0;0>>0)throw Error("invalid adler-32 checksum");}return d};var ha=8;r("Zlib.Inflate",W);r("Zlib.Inflate.prototype.decompress",W.prototype.k);var X={ADAPTIVE:B.s,BLOCK:B.t},Y,Z,$,ia;if(Object.keys)Y=Object.keys(X);else for(Z in Y=[],$=0,X)Y[$++]=Z;$=0;for(ia=Y.length;$Google Developers site.';
84 | var ARUtils = Object.create(null);
85 | ARUtils.isTango = function (display) {
86 | return display && display.displayName.toLowerCase().includes('tango');
87 | };
88 | var isTango = ARUtils.isTango;
89 | ARUtils.isARKit = function (display) {
90 | return display && display.displayName.toLowerCase().includes('arkit');
91 | };
92 | var isARKit = ARUtils.isARKit;
93 | ARUtils.isARDisplay = function (display) {
94 | return isARKit(display) || isTango(display);
95 | };
96 | var isARDisplay = ARUtils.isARDisplay;
97 | ARUtils.getARDisplay = function () {
98 | return new Promise(function (resolve, reject) {
99 | if (!navigator.getVRDisplays) {
100 | resolve(null);
101 | return;
102 | }
103 | navigator.getVRDisplays().then(function (displays) {
104 | if (!displays && displays.length === 0) {
105 | resolve(null);
106 | return;
107 | }
108 | var _iteratorNormalCompletion = true;
109 | var _didIteratorError = false;
110 | var _iteratorError = undefined;
111 | try {
112 | for (var _iterator = displays[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
113 | var display = _step.value;
114 | if (isARDisplay(display)) {
115 | resolve(display);
116 | return;
117 | }
118 | }
119 | } catch (err) {
120 | _didIteratorError = true;
121 | _iteratorError = err;
122 | } finally {
123 | try {
124 | if (!_iteratorNormalCompletion && _iterator.return) {
125 | _iterator.return();
126 | }
127 | } finally {
128 | if (_didIteratorError) {
129 | throw _iteratorError;
130 | }
131 | }
132 | }
133 | resolve(null);
134 | });
135 | });
136 | };
137 |
138 | ARUtils.loadModel = function () {
139 | var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
140 | return new Promise(function (resolve, reject) {
141 | var mtlPath = config.mtlPath,
142 | objPath = config.objPath;
143 | var OBJLoader = config.OBJLoader || (global$1.THREE ? global$1.THREE.OBJLoader : null);
144 | var MTLLoader = config.MTLLoader || (global$1.THREE ? global$1.THREE.MTLLoader : null);
145 | if (!config.objPath) {
146 | reject(new Error('`objPath` must be specified.'));
147 | return;
148 | }
149 | if (!OBJLoader) {
150 | reject(new Error('Missing OBJLoader as third argument, or window.THREE.OBJLoader existence'));
151 | return;
152 | }
153 | if (config.mtlPath && !MTLLoader) {
154 | reject(new Error('Missing MTLLoader as fourth argument, or window.THREE.MTLLoader existence'));
155 | return;
156 | }
157 | var p = Promise.resolve();
158 | if (mtlPath) {
159 | p = loadMtl(mtlPath, MTLLoader);
160 | }
161 | p.then(function (materialCreator) {
162 | if (materialCreator) {
163 | materialCreator.preload();
164 | }
165 | return loadObj(objPath, materialCreator, OBJLoader);
166 | }).then(resolve, reject);
167 | });
168 | };
169 |
170 | var model = new three.Matrix4();
171 | var tempPos = new three.Vector3();
172 | var tempQuat = new three.Quaternion();
173 | var tempScale = new three.Vector3();
174 | ARUtils.placeObjectAtHit = function (object, hit) {
175 | var easing = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
176 | var applyOrientation = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
177 | if (!hit || !hit.modelMatrix) {
178 | throw new Error('placeObjectAtHit requires a VRHit object');
179 | }
180 | model.fromArray(hit.modelMatrix);
181 | model.decompose(tempPos, tempQuat, tempScale);
182 | if (easing === 1) {
183 | object.position.copy(tempPos);
184 | if (applyOrientation) {
185 | object.quaternion.copy(tempQuat);
186 | }
187 | } else {
188 | object.position.lerp(tempPos, easing);
189 | if (applyOrientation) {
190 | object.quaternion.slerp(tempQuat, easing);
191 | }
192 | }
193 | };
194 | var placeObjectAtHit = ARUtils.placeObjectAtHit;
195 | ARUtils.getRandomPaletteColor = function () {
196 | return colors[Math.floor(Math.random() * colors.length)];
197 | };
198 | var getRandomPaletteColor = ARUtils.getRandomPaletteColor;
199 | ARUtils.displayUnsupportedMessage = function (customMessage) {
200 | var element = document.createElement('div');
201 | element.id = 'webgl-error-message';
202 | element.style.fontFamily = 'monospace';
203 | element.style.fontSize = '13px';
204 | element.style.fontWeight = 'normal';
205 | element.style.textAlign = 'center';
206 | element.style.background = '#fff';
207 | element.style.border = '1px solid black';
208 | element.style.color = '#000';
209 | element.style.padding = '1.5em';
210 | element.style.width = '400px';
211 | element.style.margin = '5em auto 0';
212 | element.innerHTML = typeof customMessage === 'string' ? customMessage : UNSUPPORTED_MESSAGE;
213 | document.body.appendChild(element);
214 | };
215 |
216 | var vertexShader = "precision mediump float;precision mediump int;uniform mat4 modelViewMatrix;uniform mat4 modelMatrix;uniform mat4 projectionMatrix;attribute vec3 position;varying vec3 vPosition;void main(){vPosition=(modelMatrix*vec4(position,1.0)).xyz;gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0);}";
217 |
218 | var fragmentShader = "precision highp float;varying vec3 vPosition;\n#define countX 7.0\n#define countY 4.0\n#define gridAlpha 0.75\nuniform float dotRadius;uniform vec3 dotColor;uniform vec3 lineColor;uniform vec3 backgroundColor;uniform float alpha;float Circle(in vec2 p,float r){return length(p)-r;}float Line(in vec2 p,in vec2 a,in vec2 b){vec2 pa=p-a;vec2 ba=b-a;float t=clamp(dot(pa,ba)/dot(ba,ba),0.0,1.0);vec2 pt=a+t*ba;return length(pt-p);}float Union(float a,float b){return min(a,b);}void main(){vec2 count=vec2(countX,countY);vec2 size=vec2(1.0)/count;vec2 halfSize=size*0.5;vec2 uv=mod(vPosition.xz*1.5,size)-halfSize;float dots=Circle(uv-vec2(halfSize.x,0.0),dotRadius);dots=Union(dots,Circle(uv+vec2(halfSize.x,0.0),dotRadius));dots=Union(dots,Circle(uv+vec2(0.0,halfSize.y),dotRadius));dots=Union(dots,Circle(uv-vec2(0.0,halfSize.y),dotRadius));float lines=Line(uv,vec2(0.0,halfSize.y),-vec2(halfSize.x,0.0));lines=Union(lines,Line(uv,vec2(0.0,-halfSize.y),-vec2(halfSize.x,0.0)));lines=Union(lines,Line(uv,vec2(0.0,-halfSize.y),vec2(halfSize.x,0.0)));lines=Union(lines,Line(uv,vec2(0.0,halfSize.y),vec2(halfSize.x,0.0)));lines=Union(lines,Line(uv,vec2(-halfSize.x,halfSize.y),vec2(halfSize.x,halfSize.y)));lines=Union(lines,Line(uv,vec2(-halfSize.x,-halfSize.y),vec2(halfSize.x,-halfSize.y)));lines=Union(lines,Line(uv,vec2(-halfSize.x,0.0),vec2(halfSize.x,0.0)));lines=clamp(smoothstep(0.0,0.0035,lines),0.0,1.0);dots=clamp(smoothstep(0.0,0.001,dots),0.0,1.0);float result=Union(dots,lines);gl_FragColor=vec4(mix(backgroundColor+mix(dotColor,lineColor,dots),backgroundColor,result),mix(gridAlpha,alpha,result));}";
219 |
220 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
221 | return typeof obj;
222 | } : function (obj) {
223 | return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
224 | };
225 |
226 |
227 |
228 |
229 |
230 | var asyncGenerator = function () {
231 | function AwaitValue(value) {
232 | this.value = value;
233 | }
234 |
235 | function AsyncGenerator(gen) {
236 | var front, back;
237 |
238 | function send(key, arg) {
239 | return new Promise(function (resolve, reject) {
240 | var request = {
241 | key: key,
242 | arg: arg,
243 | resolve: resolve,
244 | reject: reject,
245 | next: null
246 | };
247 |
248 | if (back) {
249 | back = back.next = request;
250 | } else {
251 | front = back = request;
252 | resume(key, arg);
253 | }
254 | });
255 | }
256 |
257 | function resume(key, arg) {
258 | try {
259 | var result = gen[key](arg);
260 | var value = result.value;
261 |
262 | if (value instanceof AwaitValue) {
263 | Promise.resolve(value.value).then(function (arg) {
264 | resume("next", arg);
265 | }, function (arg) {
266 | resume("throw", arg);
267 | });
268 | } else {
269 | settle(result.done ? "return" : "normal", result.value);
270 | }
271 | } catch (err) {
272 | settle("throw", err);
273 | }
274 | }
275 |
276 | function settle(type, value) {
277 | switch (type) {
278 | case "return":
279 | front.resolve({
280 | value: value,
281 | done: true
282 | });
283 | break;
284 |
285 | case "throw":
286 | front.reject(value);
287 | break;
288 |
289 | default:
290 | front.resolve({
291 | value: value,
292 | done: false
293 | });
294 | break;
295 | }
296 |
297 | front = front.next;
298 |
299 | if (front) {
300 | resume(front.key, front.arg);
301 | } else {
302 | back = null;
303 | }
304 | }
305 |
306 | this._invoke = send;
307 |
308 | if (typeof gen.return !== "function") {
309 | this.return = undefined;
310 | }
311 | }
312 |
313 | if (typeof Symbol === "function" && Symbol.asyncIterator) {
314 | AsyncGenerator.prototype[Symbol.asyncIterator] = function () {
315 | return this;
316 | };
317 | }
318 |
319 | AsyncGenerator.prototype.next = function (arg) {
320 | return this._invoke("next", arg);
321 | };
322 |
323 | AsyncGenerator.prototype.throw = function (arg) {
324 | return this._invoke("throw", arg);
325 | };
326 |
327 | AsyncGenerator.prototype.return = function (arg) {
328 | return this._invoke("return", arg);
329 | };
330 |
331 | return {
332 | wrap: function (fn) {
333 | return function () {
334 | return new AsyncGenerator(fn.apply(this, arguments));
335 | };
336 | },
337 | await: function (value) {
338 | return new AwaitValue(value);
339 | }
340 | };
341 | }();
342 |
343 |
344 |
345 |
346 |
347 | var classCallCheck = function (instance, Constructor) {
348 | if (!(instance instanceof Constructor)) {
349 | throw new TypeError("Cannot call a class as a function");
350 | }
351 | };
352 |
353 | var createClass = function () {
354 | function defineProperties(target, props) {
355 | for (var i = 0; i < props.length; i++) {
356 | var descriptor = props[i];
357 | descriptor.enumerable = descriptor.enumerable || false;
358 | descriptor.configurable = true;
359 | if ("value" in descriptor) descriptor.writable = true;
360 | Object.defineProperty(target, descriptor.key, descriptor);
361 | }
362 | }
363 |
364 | return function (Constructor, protoProps, staticProps) {
365 | if (protoProps) defineProperties(Constructor.prototype, protoProps);
366 | if (staticProps) defineProperties(Constructor, staticProps);
367 | return Constructor;
368 | };
369 | }();
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 | var get = function get(object, property, receiver) {
378 | if (object === null) object = Function.prototype;
379 | var desc = Object.getOwnPropertyDescriptor(object, property);
380 |
381 | if (desc === undefined) {
382 | var parent = Object.getPrototypeOf(object);
383 |
384 | if (parent === null) {
385 | return undefined;
386 | } else {
387 | return get(parent, property, receiver);
388 | }
389 | } else if ("value" in desc) {
390 | return desc.value;
391 | } else {
392 | var getter = desc.get;
393 |
394 | if (getter === undefined) {
395 | return undefined;
396 | }
397 |
398 | return getter.call(receiver);
399 | }
400 | };
401 |
402 | var inherits = function (subClass, superClass) {
403 | if (typeof superClass !== "function" && superClass !== null) {
404 | throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
405 | }
406 |
407 | subClass.prototype = Object.create(superClass && superClass.prototype, {
408 | constructor: {
409 | value: subClass,
410 | enumerable: false,
411 | writable: true,
412 | configurable: true
413 | }
414 | });
415 | if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
416 | };
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 | var possibleConstructorReturn = function (self, call) {
429 | if (!self) {
430 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
431 | }
432 |
433 | return call && (typeof call === "object" || typeof call === "function") ? call : self;
434 | };
435 |
436 |
437 |
438 |
439 |
440 | var slicedToArray = function () {
441 | function sliceIterator(arr, i) {
442 | var _arr = [];
443 | var _n = true;
444 | var _d = false;
445 | var _e = undefined;
446 |
447 | try {
448 | for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
449 | _arr.push(_s.value);
450 |
451 | if (i && _arr.length === i) break;
452 | }
453 | } catch (err) {
454 | _d = true;
455 | _e = err;
456 | } finally {
457 | try {
458 | if (!_n && _i["return"]) _i["return"]();
459 | } finally {
460 | if (_d) throw _e;
461 | }
462 | }
463 |
464 | return _arr;
465 | }
466 |
467 | return function (arr, i) {
468 | if (Array.isArray(arr)) {
469 | return arr;
470 | } else if (Symbol.iterator in Object(arr)) {
471 | return sliceIterator(arr, i);
472 | } else {
473 | throw new TypeError("Invalid attempt to destructure non-iterable instance");
474 | }
475 | };
476 | }();
477 |
478 | var DEFAULT_MATERIAL = new three.RawShaderMaterial({
479 | side: three.DoubleSide,
480 | transparent: true,
481 | uniforms: {
482 | dotColor: {
483 | value: new three.Color(0xffffff)
484 | },
485 | lineColor: {
486 | value: new three.Color(0x707070)
487 | },
488 | backgroundColor: {
489 | value: new three.Color(0x404040)
490 | },
491 | dotRadius: {
492 | value: 0.006666666667
493 | },
494 | alpha: {
495 | value: 0.4
496 | }
497 | },
498 | vertexShader: vertexShader,
499 | fragmentShader: fragmentShader
500 | });
501 | var ARPlanes = function (_Object3D) {
502 | inherits(ARPlanes, _Object3D);
503 | function ARPlanes(vrDisplay) {
504 | classCallCheck(this, ARPlanes);
505 | var _this = possibleConstructorReturn(this, (ARPlanes.__proto__ || Object.getPrototypeOf(ARPlanes)).call(this));
506 | _this.addPlane_ = function (plane) {
507 | var planeObj = _this.createPlane(plane);
508 | if (planeObj) {
509 | _this.add(planeObj);
510 | _this.planes.set(plane.identifier, planeObj);
511 | }
512 | };
513 | _this.removePlane_ = function (identifier) {
514 | var existing = _this.planes.get(identifier);
515 | if (existing) {
516 | _this.remove(existing);
517 | }
518 | _this.planes.delete(identifier);
519 | };
520 | _this.onPlaneAdded_ = function (event) {
521 | event.planes.forEach(function (plane) {
522 | return _this.addPlane_(plane);
523 | });
524 | };
525 | _this.onPlaneUpdated_ = function (event) {
526 | var _iteratorNormalCompletion = true;
527 | var _didIteratorError = false;
528 | var _iteratorError = undefined;
529 | try {
530 | for (var _iterator = event.planes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
531 | var plane = _step.value;
532 | _this.removePlane_(plane.identifier);
533 | _this.addPlane_(plane);
534 | }
535 | } catch (err) {
536 | _didIteratorError = true;
537 | _iteratorError = err;
538 | } finally {
539 | try {
540 | if (!_iteratorNormalCompletion && _iterator.return) {
541 | _iterator.return();
542 | }
543 | } finally {
544 | if (_didIteratorError) {
545 | throw _iteratorError;
546 | }
547 | }
548 | }
549 | };
550 | _this.onPlaneRemoved_ = function (event) {
551 | var _iteratorNormalCompletion2 = true;
552 | var _didIteratorError2 = false;
553 | var _iteratorError2 = undefined;
554 | try {
555 | for (var _iterator2 = event.planes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
556 | var plane = _step2.value;
557 | _this.removePlane_(plane.identifier);
558 | }
559 | } catch (err) {
560 | _didIteratorError2 = true;
561 | _iteratorError2 = err;
562 | } finally {
563 | try {
564 | if (!_iteratorNormalCompletion2 && _iterator2.return) {
565 | _iterator2.return();
566 | }
567 | } finally {
568 | if (_didIteratorError2) {
569 | throw _iteratorError2;
570 | }
571 | }
572 | }
573 | };
574 | _this.vrDisplay = vrDisplay;
575 | _this.planes = new Map();
576 | _this.materials = new Map();
577 | return _this;
578 | }
579 | createClass(ARPlanes, [{
580 | key: 'enable',
581 | value: function enable() {
582 | this.vrDisplay.getPlanes().forEach(this.addPlane_);
583 | this.vrDisplay.addEventListener('planesadded', this.onPlaneAdded_);
584 | this.vrDisplay.addEventListener('planesupdated', this.onPlaneUpdated_);
585 | this.vrDisplay.addEventListener('planesremoved', this.onPlaneRemoved_);
586 | }
587 | }, {
588 | key: 'disable',
589 | value: function disable() {
590 | this.vrDisplay.removeEventListener('planesadded', this.onPlaneAdded_);
591 | this.vrDisplay.removeEventListener('planesupdated', this.onPlaneUpdated_);
592 | this.vrDisplay.removeEventListener('planesremoved', this.onPlaneRemoved_);
593 | var _iteratorNormalCompletion3 = true;
594 | var _didIteratorError3 = false;
595 | var _iteratorError3 = undefined;
596 | try {
597 | for (var _iterator3 = this.planes.keys()[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
598 | var identifier = _step3.value;
599 | this.removePlane_(identifier);
600 | }
601 | } catch (err) {
602 | _didIteratorError3 = true;
603 | _iteratorError3 = err;
604 | } finally {
605 | try {
606 | if (!_iteratorNormalCompletion3 && _iterator3.return) {
607 | _iterator3.return();
608 | }
609 | } finally {
610 | if (_didIteratorError3) {
611 | throw _iteratorError3;
612 | }
613 | }
614 | }
615 | this.materials.clear();
616 | }
617 | }, {
618 | key: 'createPlane',
619 | value: function createPlane(plane) {
620 | if (plane.vertices.length == 0) {
621 | return null;
622 | }
623 | var geo = new three.Geometry();
624 | for (var pt = 0; pt < plane.vertices.length / 3; pt++) {
625 | geo.vertices.push(new three.Vector3(plane.vertices[pt * 3], plane.vertices[pt * 3 + 1], plane.vertices[pt * 3 + 2]));
626 | }
627 | for (var face = 0; face < geo.vertices.length - 2; face++) {
628 | geo.faces.push(new three.Face3(0, face + 1, face + 2));
629 | }
630 | var material = void 0;
631 | if (this.materials.has(plane.identifier)) {
632 | material = this.materials.get(plane.identifier);
633 | } else {
634 | var color = getRandomPaletteColor();
635 | material = DEFAULT_MATERIAL.clone();
636 | material.uniforms.backgroundColor.value = color;
637 | this.materials.set(plane.identifier, material);
638 | }
639 | var planeObj = new three.Mesh(geo, material);
640 | var mm = plane.modelMatrix;
641 | planeObj.matrixAutoUpdate = false;
642 | planeObj.matrix.set(mm[0], mm[4], mm[8], mm[12], mm[1], mm[5], mm[9], mm[13], mm[2], mm[6], mm[10], mm[14], mm[3], mm[7], mm[11], mm[15]);
643 | this.add(planeObj);
644 | return planeObj;
645 | }
646 | }, {
647 | key: 'size',
648 | value: function size() {
649 | return this.planes.size;
650 | }
651 | }]);
652 | return ARPlanes;
653 | }(three.Object3D);
654 |
655 | var DEFAULTS = {
656 | open: true,
657 | showLastHit: true,
658 | showPoseStatus: true,
659 | showPlanes: false
660 | };
661 | var SUCCESS_COLOR = '#00ff00';
662 | var FAILURE_COLOR = '#ff0077';
663 | var PLANES_POLLING_TIMER = 500;
664 | var THROTTLE_SPEED = 500;
665 | var cachedVRDisplayMethods = new Map();
666 | function throttle(fn, timer, scope) {
667 | var lastFired = void 0;
668 | var timeout = void 0;
669 | return function () {
670 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
671 | args[_key] = arguments[_key];
672 | }
673 | var current = +new Date();
674 | var until = void 0;
675 | if (lastFired) {
676 | until = lastFired + timer - current;
677 | }
678 | if (until == undefined || until < 0) {
679 | lastFired = current;
680 | fn.apply(scope, args);
681 | } else if (until >= 0) {
682 | clearTimeout(timeout);
683 | timeout = setTimeout(function () {
684 | lastFired = current;
685 | fn.apply(scope, args);
686 | }, until);
687 | }
688 | };
689 | }
690 | var ARDebug = function () {
691 | function ARDebug(vrDisplay, scene, config) {
692 | classCallCheck(this, ARDebug);
693 | if (typeof config === 'undefined' && scene && scene.type !== 'Scene') {
694 | config = scene;
695 | scene = null;
696 | }
697 | this.config = Object.assign({}, DEFAULTS, config);
698 | this.vrDisplay = vrDisplay;
699 | this._view = new ARDebugView({ open: this.config.open });
700 | if (this.config.showLastHit && this.vrDisplay.hitTest) {
701 | this._view.addRow('hit-test', new ARDebugHitTestRow(vrDisplay));
702 | }
703 | if (this.config.showPoseStatus && this.vrDisplay.getFrameData) {
704 | this._view.addRow('pose-status', new ARDebugPoseRow(vrDisplay));
705 | }
706 | if (this.config.showPlanes && this.vrDisplay.getPlanes) {
707 | if (!scene) {
708 | console.warn('ARDebug `{ showPlanes: true }` option requires ' + 'passing in a THREE.Scene as the second parameter ' + 'in the constructor.');
709 | } else {
710 | this._view.addRow('show-planes', new ARDebugPlanesRow(vrDisplay, scene));
711 | }
712 | }
713 | }
714 | createClass(ARDebug, [{
715 | key: 'open',
716 | value: function open() {
717 | this._view.open();
718 | }
719 | }, {
720 | key: 'close',
721 | value: function close() {
722 | this._view.close();
723 | }
724 | }, {
725 | key: 'getElement',
726 | value: function getElement() {
727 | return this._view.getElement();
728 | }
729 | }]);
730 | return ARDebug;
731 | }();
732 | var ARDebugView = function () {
733 | function ARDebugView() {
734 | var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
735 | classCallCheck(this, ARDebugView);
736 | this.rows = new Map();
737 | this.el = document.createElement('div');
738 | this.el.style.backgroundColor = '#333';
739 | this.el.style.padding = '5px';
740 | this.el.style.fontFamily = 'Roboto, Ubuntu, Arial, sans-serif';
741 | this.el.style.color = 'rgb(165, 165, 165)';
742 | this.el.style.position = 'absolute';
743 | this.el.style.right = '20px';
744 | this.el.style.top = '0px';
745 | this.el.style.width = '200px';
746 | this.el.style.fontSize = '12px';
747 | this.el.style.zIndex = 9999;
748 | this._rowsEl = document.createElement('div');
749 | this._rowsEl.style.transitionProperty = 'max-height';
750 | this._rowsEl.style.transitionDuration = '0.5s';
751 | this._rowsEl.style.transitionDelay = '0s';
752 | this._rowsEl.style.transitionTimingFunction = 'ease-out';
753 | this._rowsEl.style.overflow = 'hidden';
754 | this._controls = document.createElement('div');
755 | this._controls.style.fontSize = '13px';
756 | this._controls.style.fontWeight = 'bold';
757 | this._controls.style.paddingTop = '5px';
758 | this._controls.style.textAlign = 'center';
759 | this._controls.style.cursor = 'pointer';
760 | this._controls.addEventListener('click', this.toggleControls.bind(this));
761 | config.open ? this.open() : this.close();
762 | this.el.appendChild(this._rowsEl);
763 | this.el.appendChild(this._controls);
764 | }
765 | createClass(ARDebugView, [{
766 | key: 'toggleControls',
767 | value: function toggleControls() {
768 | if (this._isOpen) {
769 | this.close();
770 | } else {
771 | this.open();
772 | }
773 | }
774 | }, {
775 | key: 'open',
776 | value: function open() {
777 | this._rowsEl.style.maxHeight = '100px';
778 | this._isOpen = true;
779 | this._controls.textContent = 'Close ARDebug';
780 | var _iteratorNormalCompletion = true;
781 | var _didIteratorError = false;
782 | var _iteratorError = undefined;
783 | try {
784 | for (var _iterator = this.rows[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
785 | var _ref = _step.value;
786 | var _ref2 = slicedToArray(_ref, 2);
787 | var row = _ref2[1];
788 | row.enable();
789 | }
790 | } catch (err) {
791 | _didIteratorError = true;
792 | _iteratorError = err;
793 | } finally {
794 | try {
795 | if (!_iteratorNormalCompletion && _iterator.return) {
796 | _iterator.return();
797 | }
798 | } finally {
799 | if (_didIteratorError) {
800 | throw _iteratorError;
801 | }
802 | }
803 | }
804 | }
805 | }, {
806 | key: 'close',
807 | value: function close() {
808 | this._rowsEl.style.maxHeight = '0px';
809 | this._isOpen = false;
810 | this._controls.textContent = 'Open ARDebug';
811 | var _iteratorNormalCompletion2 = true;
812 | var _didIteratorError2 = false;
813 | var _iteratorError2 = undefined;
814 | try {
815 | for (var _iterator2 = this.rows[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
816 | var _ref3 = _step2.value;
817 | var _ref4 = slicedToArray(_ref3, 2);
818 | var row = _ref4[1];
819 | row.disable();
820 | }
821 | } catch (err) {
822 | _didIteratorError2 = true;
823 | _iteratorError2 = err;
824 | } finally {
825 | try {
826 | if (!_iteratorNormalCompletion2 && _iterator2.return) {
827 | _iterator2.return();
828 | }
829 | } finally {
830 | if (_didIteratorError2) {
831 | throw _iteratorError2;
832 | }
833 | }
834 | }
835 | }
836 | }, {
837 | key: 'getElement',
838 | value: function getElement() {
839 | return this.el;
840 | }
841 | }, {
842 | key: 'addRow',
843 | value: function addRow(id, row) {
844 | this.rows.set(id, row);
845 | if (this._isOpen) {
846 | row.enable();
847 | }
848 | this._rowsEl.appendChild(row.getElement());
849 | }
850 | }]);
851 | return ARDebugView;
852 | }();
853 | var ARDebugRow = function () {
854 | function ARDebugRow(title) {
855 | classCallCheck(this, ARDebugRow);
856 | this.el = document.createElement('div');
857 | this.el.style.width = '100%';
858 | this.el.style.borderTop = '1px solid rgb(54, 54, 54)';
859 | this.el.style.borderBottom = '1px solid #14171A';
860 | this.el.style.position = 'relative';
861 | this.el.style.padding = '3px 0px';
862 | this.el.style.overflow = 'hidden';
863 | this._titleEl = document.createElement('span');
864 | this._titleEl.style.fontWeight = 'bold';
865 | this._titleEl.textContent = title;
866 | this._dataEl = document.createElement('span');
867 | this._dataEl.style.position = 'absolute';
868 | this._dataEl.style.left = '40px';
869 | this._dataElText = document.createTextNode('');
870 | this._dataEl.appendChild(this._dataElText);
871 | this.el.appendChild(this._titleEl);
872 | this.el.appendChild(this._dataEl);
873 | this._throttledWriteToDOM = throttle(this._writeToDOM, THROTTLE_SPEED, this);
874 | }
875 | createClass(ARDebugRow, [{
876 | key: 'enable',
877 | value: function enable() {
878 | throw new Error('Implement in child class');
879 | }
880 | }, {
881 | key: 'disable',
882 | value: function disable() {
883 | throw new Error('Implement in child class');
884 | }
885 | }, {
886 | key: 'getElement',
887 | value: function getElement() {
888 | return this.el;
889 | }
890 | }, {
891 | key: 'update',
892 | value: function update(value, isSuccess, renderImmediately) {
893 | if (renderImmediately) {
894 | this._writeToDOM(value, isSuccess);
895 | } else {
896 | this._throttledWriteToDOM(value, isSuccess);
897 | }
898 | }
899 | }, {
900 | key: '_writeToDOM',
901 | value: function _writeToDOM(value, isSuccess) {
902 | this._dataElText.nodeValue = value;
903 | this._dataEl.style.color = isSuccess ? SUCCESS_COLOR : FAILURE_COLOR;
904 | }
905 | }]);
906 | return ARDebugRow;
907 | }();
908 | var ARDebugHitTestRow = function (_ARDebugRow) {
909 | inherits(ARDebugHitTestRow, _ARDebugRow);
910 | function ARDebugHitTestRow(vrDisplay) {
911 | classCallCheck(this, ARDebugHitTestRow);
912 | var _this = possibleConstructorReturn(this, (ARDebugHitTestRow.__proto__ || Object.getPrototypeOf(ARDebugHitTestRow)).call(this, 'Hit'));
913 | _this.vrDisplay = vrDisplay;
914 | _this._onHitTest = _this._onHitTest.bind(_this);
915 | _this._nativeHitTest = cachedVRDisplayMethods.get('hitTest') || _this.vrDisplay.hitTest;
916 | cachedVRDisplayMethods.set('hitTest', _this._nativeHitTest);
917 | _this._didPreviouslyHit = null;
918 | return _this;
919 | }
920 | createClass(ARDebugHitTestRow, [{
921 | key: 'enable',
922 | value: function enable() {
923 | this.vrDisplay.hitTest = this._onHitTest;
924 | }
925 | }, {
926 | key: 'disable',
927 | value: function disable() {
928 | this.vrDisplay.hitTest = this._nativeHitTest;
929 | }
930 | }, {
931 | key: '_hitToString',
932 | value: function _hitToString(hit) {
933 | var mm = hit.modelMatrix;
934 | return mm[12].toFixed(2) + ', ' + mm[13].toFixed(2) + ', ' + mm[14].toFixed(2);
935 | }
936 | }, {
937 | key: '_onHitTest',
938 | value: function _onHitTest(x, y) {
939 | var hits = this._nativeHitTest.call(this.vrDisplay, x, y);
940 | var t = (parseInt(performance.now(), 10) / 1000).toFixed(1);
941 | var didHit = hits && hits.length;
942 | var value = (didHit ? this._hitToString(hits[0]) : 'MISS') + ' @ ' + t + 's';
943 | this.update(value, didHit, didHit !== this._didPreviouslyHit);
944 | this._didPreviouslyHit = didHit;
945 | return hits;
946 | }
947 | }]);
948 | return ARDebugHitTestRow;
949 | }(ARDebugRow);
950 | var ARDebugPoseRow = function (_ARDebugRow2) {
951 | inherits(ARDebugPoseRow, _ARDebugRow2);
952 | function ARDebugPoseRow(vrDisplay) {
953 | classCallCheck(this, ARDebugPoseRow);
954 | var _this2 = possibleConstructorReturn(this, (ARDebugPoseRow.__proto__ || Object.getPrototypeOf(ARDebugPoseRow)).call(this, 'Pose'));
955 | _this2.vrDisplay = vrDisplay;
956 | _this2._onGetFrameData = _this2._onGetFrameData.bind(_this2);
957 | _this2._nativeGetFrameData = cachedVRDisplayMethods.get('getFrameData') || _this2.vrDisplay.getFrameData;
958 | cachedVRDisplayMethods.set('getFrameData', _this2._nativeGetFrameData);
959 | _this2.update('Looking for position...', false, true);
960 | _this2._initialPose = false;
961 | return _this2;
962 | }
963 | createClass(ARDebugPoseRow, [{
964 | key: 'enable',
965 | value: function enable() {
966 | this.vrDisplay.getFrameData = this._onGetFrameData;
967 | }
968 | }, {
969 | key: 'disable',
970 | value: function disable() {
971 | this.vrDisplay.getFrameData = this._nativeGetFrameData;
972 | }
973 | }, {
974 | key: '_poseToString',
975 | value: function _poseToString(pose) {
976 | return pose[0].toFixed(2) + ', ' + pose[1].toFixed(2) + ', ' + pose[2].toFixed(2);
977 | }
978 | }, {
979 | key: '_onGetFrameData',
980 | value: function _onGetFrameData(frameData) {
981 | var results = this._nativeGetFrameData.call(this.vrDisplay, frameData);
982 | var pose = frameData && frameData.pose && frameData.pose.position;
983 | var isValidPose = pose && typeof pose[0] === 'number' && typeof pose[1] === 'number' && typeof pose[2] === 'number' && !(pose[0] === 0 && pose[1] === 0 && pose[2] === 0);
984 | if (!this._initialPose && !isValidPose) {
985 | return results;
986 | }
987 | var renderImmediately = isValidPose !== this._lastPoseValid;
988 | if (isValidPose) {
989 | this.update(this._poseToString(pose), true, renderImmediately);
990 | } else if (!isValidPose && this._lastPoseValid !== false) {
991 | this.update('Position lost', false, renderImmediately);
992 | }
993 | this._lastPoseValid = isValidPose;
994 | this._initialPose = true;
995 | return results;
996 | }
997 | }]);
998 | return ARDebugPoseRow;
999 | }(ARDebugRow);
1000 | var ARDebugPlanesRow = function (_ARDebugRow3) {
1001 | inherits(ARDebugPlanesRow, _ARDebugRow3);
1002 | function ARDebugPlanesRow(vrDisplay, scene) {
1003 | classCallCheck(this, ARDebugPlanesRow);
1004 | var _this3 = possibleConstructorReturn(this, (ARDebugPlanesRow.__proto__ || Object.getPrototypeOf(ARDebugPlanesRow)).call(this, 'Planes'));
1005 | _this3.vrDisplay = vrDisplay;
1006 | _this3.planes = new ARPlanes(_this3.vrDisplay);
1007 | _this3._onPoll = _this3._onPoll.bind(_this3);
1008 | _this3.update('Looking for planes...', false, true);
1009 | if (scene) {
1010 | scene.add(_this3.planes);
1011 | }
1012 | return _this3;
1013 | }
1014 | createClass(ARDebugPlanesRow, [{
1015 | key: 'enable',
1016 | value: function enable() {
1017 | if (this._timer) {
1018 | this.disable();
1019 | }
1020 | this._timer = setInterval(this._onPoll, PLANES_POLLING_TIMER);
1021 | this.planes.enable();
1022 | }
1023 | }, {
1024 | key: 'disable',
1025 | value: function disable() {
1026 | clearInterval(this._timer);
1027 | this._timer = null;
1028 | this.planes.disable();
1029 | }
1030 | }, {
1031 | key: '_planesToString',
1032 | value: function _planesToString(count) {
1033 | return count + ' plane' + (count === 1 ? '' : 's') + ' found';
1034 | }
1035 | }, {
1036 | key: '_onPoll',
1037 | value: function _onPoll() {
1038 | var planeCount = this.planes.size();
1039 | if (this._lastPlaneCount !== planeCount) {
1040 | this.update(this._planesToString(planeCount), planeCount > 0, true);
1041 | }
1042 | this._lastPlaneCount = planeCount;
1043 | }
1044 | }]);
1045 | return ARDebugPlanesRow;
1046 | }(ARDebugRow);
1047 |
1048 | var frameData = void 0;
1049 | var ARPerspectiveCamera = function (_PerspectiveCamera) {
1050 | inherits(ARPerspectiveCamera, _PerspectiveCamera);
1051 | function ARPerspectiveCamera(vrDisplay, fov, aspect, near, far) {
1052 | classCallCheck(this, ARPerspectiveCamera);
1053 | var _this = possibleConstructorReturn(this, (ARPerspectiveCamera.__proto__ || Object.getPrototypeOf(ARPerspectiveCamera)).call(this, fov, aspect, near, far));
1054 | _this.isARPerpsectiveCamera = true;
1055 | _this.vrDisplay = vrDisplay;
1056 | _this.updateProjectionMatrix();
1057 | if (!vrDisplay || !vrDisplay.capabilities.hasPassThroughCamera) {
1058 | console.warn('ARPerspectiveCamera does not a VRDisplay with\n a pass through camera. Using supplied values and defaults\n instead of device camera intrinsics');
1059 | }
1060 | return _this;
1061 | }
1062 | createClass(ARPerspectiveCamera, [{
1063 | key: 'updateProjectionMatrix',
1064 | value: function updateProjectionMatrix() {
1065 | var projMatrix = this.getProjectionMatrix();
1066 | if (!projMatrix) {
1067 | get(ARPerspectiveCamera.prototype.__proto__ || Object.getPrototypeOf(ARPerspectiveCamera.prototype), 'updateProjectionMatrix', this).call(this);
1068 | return;
1069 | }
1070 | this.projectionMatrix.fromArray(projMatrix);
1071 | }
1072 | }, {
1073 | key: 'getProjectionMatrix',
1074 | value: function getProjectionMatrix() {
1075 | if (this.vrDisplay && this.vrDisplay.getFrameData) {
1076 | if (!frameData) {
1077 | frameData = new VRFrameData();
1078 | }
1079 | this.vrDisplay.getFrameData(frameData);
1080 | return frameData.leftProjectionMatrix;
1081 | }
1082 | return null;
1083 | }
1084 | }]);
1085 | return ARPerspectiveCamera;
1086 | }(three.PerspectiveCamera);
1087 |
1088 | var ARReticle = function (_Mesh) {
1089 | inherits(ARReticle, _Mesh);
1090 | function ARReticle(vrDisplay) {
1091 | var innerRadius = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.02;
1092 | var outerRadius = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0.05;
1093 | var color = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0xff0077;
1094 | var easing = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0.25;
1095 | classCallCheck(this, ARReticle);
1096 | var geometry = new three.RingGeometry(innerRadius, outerRadius, 36, 64);
1097 | var material = new three.MeshBasicMaterial({ color: color });
1098 | geometry.applyMatrix(new three.Matrix4().makeRotationX(three.Math.degToRad(-90)));
1099 | var _this = possibleConstructorReturn(this, (ARReticle.__proto__ || Object.getPrototypeOf(ARReticle)).call(this, geometry, material));
1100 | _this.visible = false;
1101 | _this.easing = easing;
1102 | _this.applyOrientation = true;
1103 | _this.vrDisplay = vrDisplay;
1104 | _this._planeDir = new three.Vector3();
1105 | return _this;
1106 | }
1107 | createClass(ARReticle, [{
1108 | key: 'update',
1109 | value: function update() {
1110 | var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.5;
1111 | var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.5;
1112 | if (!this.vrDisplay || !this.vrDisplay.hitTest) {
1113 | return;
1114 | }
1115 | var hit = this.vrDisplay.hitTest(x, y);
1116 | if (hit && hit.length > 0) {
1117 | this.visible = true;
1118 | placeObjectAtHit(this, hit[0], this.applyOrientation, this.easing);
1119 | }
1120 | }
1121 | }]);
1122 | return ARReticle;
1123 | }(three.Mesh);
1124 |
1125 | var vertexSource = "attribute vec3 aVertexPosition;attribute vec2 aTextureCoord;varying vec2 vTextureCoord;void main(void){gl_Position=vec4(aVertexPosition,1.0);vTextureCoord=aTextureCoord;}";
1126 |
1127 | var fragmentSource = "\n#extension GL_OES_EGL_image_external : require\nprecision mediump float;varying vec2 vTextureCoord;uniform samplerExternalOES uSampler;void main(void){gl_FragColor=texture2D(uSampler,vTextureCoord);}";
1128 |
1129 | function WGLUPreserveGLState(gl, bindings, callback) {
1130 | if (!bindings) {
1131 | callback(gl);
1132 | return;
1133 | }
1134 | var boundValues = [];
1135 | var activeTexture = null;
1136 | for (var i = 0; i < bindings.length; ++i) {
1137 | var binding = bindings[i];
1138 | switch (binding) {
1139 | case gl.TEXTURE_BINDING_2D:
1140 | case gl.TEXTURE_BINDING_CUBE_MAP:
1141 | var textureUnit = bindings[++i];
1142 | if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) {
1143 | console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit");
1144 | boundValues.push(null, null);
1145 | break;
1146 | }
1147 | if (!activeTexture) {
1148 | activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
1149 | }
1150 | gl.activeTexture(textureUnit);
1151 | boundValues.push(gl.getParameter(binding), null);
1152 | break;
1153 | case gl.ACTIVE_TEXTURE:
1154 | activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
1155 | boundValues.push(null);
1156 | break;
1157 | default:
1158 | boundValues.push(gl.getParameter(binding));
1159 | break;
1160 | }
1161 | }
1162 | callback(gl);
1163 | for (var i = 0; i < bindings.length; ++i) {
1164 | var binding = bindings[i];
1165 | var boundValue = boundValues[i];
1166 | switch (binding) {
1167 | case gl.ACTIVE_TEXTURE:
1168 | break;
1169 | case gl.ARRAY_BUFFER_BINDING:
1170 | gl.bindBuffer(gl.ARRAY_BUFFER, boundValue);
1171 | break;
1172 | case gl.COLOR_CLEAR_VALUE:
1173 | gl.clearColor(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
1174 | break;
1175 | case gl.COLOR_WRITEMASK:
1176 | gl.colorMask(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
1177 | break;
1178 | case gl.CURRENT_PROGRAM:
1179 | gl.useProgram(boundValue);
1180 | break;
1181 | case gl.ELEMENT_ARRAY_BUFFER_BINDING:
1182 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boundValue);
1183 | break;
1184 | case gl.FRAMEBUFFER_BINDING:
1185 | gl.bindFramebuffer(gl.FRAMEBUFFER, boundValue);
1186 | break;
1187 | case gl.RENDERBUFFER_BINDING:
1188 | gl.bindRenderbuffer(gl.RENDERBUFFER, boundValue);
1189 | break;
1190 | case gl.TEXTURE_BINDING_2D:
1191 | var textureUnit = bindings[++i];
1192 | if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31)
1193 | break;
1194 | gl.activeTexture(textureUnit);
1195 | gl.bindTexture(gl.TEXTURE_2D, boundValue);
1196 | break;
1197 | case gl.TEXTURE_BINDING_CUBE_MAP:
1198 | var textureUnit = bindings[++i];
1199 | if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31)
1200 | break;
1201 | gl.activeTexture(textureUnit);
1202 | gl.bindTexture(gl.TEXTURE_CUBE_MAP, boundValue);
1203 | break;
1204 | case gl.VIEWPORT:
1205 | gl.viewport(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
1206 | break;
1207 | case gl.BLEND:
1208 | case gl.CULL_FACE:
1209 | case gl.DEPTH_TEST:
1210 | case gl.SCISSOR_TEST:
1211 | case gl.STENCIL_TEST:
1212 | if (boundValue) {
1213 | gl.enable(binding);
1214 | } else {
1215 | gl.disable(binding);
1216 | }
1217 | break;
1218 | default:
1219 | console.log("No GL restore behavior for 0x" + binding.toString(16));
1220 | break;
1221 | }
1222 | if (activeTexture) {
1223 | gl.activeTexture(activeTexture);
1224 | }
1225 | }
1226 | }
1227 | var glPreserveState = WGLUPreserveGLState;
1228 |
1229 | function getShader(gl, str, type) {
1230 | var shader = void 0;
1231 | if (type == 'fragment') {
1232 | shader = gl.createShader(gl.FRAGMENT_SHADER);
1233 | } else if (type == 'vertex') {
1234 | shader = gl.createShader(gl.VERTEX_SHADER);
1235 | } else {
1236 | return null;
1237 | }
1238 | gl.shaderSource(shader, str);
1239 | gl.compileShader(shader);
1240 | var result = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
1241 | if (!result) {
1242 | alert(gl.getShaderInfoLog(shader));
1243 | return null;
1244 | }
1245 | return shader;
1246 | }
1247 | function getProgram(gl, vs, fs) {
1248 | var vertexShader = getShader(gl, vs, 'vertex');
1249 | var fragmentShader = getShader(gl, fs, 'fragment');
1250 | if (!fragmentShader) {
1251 | return null;
1252 | }
1253 | var shaderProgram = gl.createProgram();
1254 | gl.attachShader(shaderProgram, vertexShader);
1255 | gl.attachShader(shaderProgram, fragmentShader);
1256 | gl.linkProgram(shaderProgram);
1257 | var result = gl.getProgramParameter(shaderProgram, gl.LINK_STATUS);
1258 | if (!result) {
1259 | alert('Could not initialise arview shaders');
1260 | }
1261 | return shaderProgram;
1262 | }
1263 | function combineOrientations(screenOrientation, seeThroughCameraOrientation) {
1264 | var seeThroughCameraOrientationIndex = 0;
1265 | switch (seeThroughCameraOrientation) {
1266 | case 90:
1267 | seeThroughCameraOrientationIndex = 1;
1268 | break;
1269 | case 180:
1270 | seeThroughCameraOrientationIndex = 2;
1271 | break;
1272 | case 270:
1273 | seeThroughCameraOrientationIndex = 3;
1274 | break;
1275 | default:
1276 | seeThroughCameraOrientationIndex = 0;
1277 | break;
1278 | }
1279 | var screenOrientationIndex = 0;
1280 | switch (screenOrientation) {
1281 | case 90:
1282 | screenOrientationIndex = 1;
1283 | break;
1284 | case 180:
1285 | screenOrientationIndex = 2;
1286 | break;
1287 | case 270:
1288 | screenOrientationIndex = 3;
1289 | break;
1290 | default:
1291 | screenOrientationIndex = 0;
1292 | break;
1293 | }
1294 | var ret = screenOrientationIndex - seeThroughCameraOrientationIndex;
1295 | if (ret < 0) {
1296 | ret += 4;
1297 | }
1298 | return ret % 4;
1299 | }
1300 | var ARVideoRenderer = function () {
1301 | function ARVideoRenderer(vrDisplay, gl) {
1302 | classCallCheck(this, ARVideoRenderer);
1303 | this.vrDisplay = vrDisplay;
1304 | this.gl = gl;
1305 | if (this.vrDisplay) {
1306 | this.passThroughCamera = vrDisplay.getPassThroughCamera();
1307 | this.program = getProgram(gl, vertexSource, fragmentSource);
1308 | }
1309 | gl.useProgram(this.program);
1310 | this.vertexPositionAttribute = gl.getAttribLocation(this.program, 'aVertexPosition');
1311 | this.textureCoordAttribute = gl.getAttribLocation(this.program, 'aTextureCoord');
1312 | this.samplerUniform = gl.getUniformLocation(this.program, 'uSampler');
1313 | this.vertexPositionBuffer = gl.createBuffer();
1314 | gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBuffer);
1315 | var vertices = [-1.0, 1.0, 0.0, -1.0, -1.0, 0.0, 1.0, 1.0, 0.0, 1.0, -1.0, 0.0];
1316 | var f32Vertices = new Float32Array(vertices);
1317 | gl.bufferData(gl.ARRAY_BUFFER, f32Vertices, gl.STATIC_DRAW);
1318 | this.vertexPositionBuffer.itemSize = 3;
1319 | this.vertexPositionBuffer.numItems = 12;
1320 | this.textureCoordBuffer = gl.createBuffer();
1321 | gl.bindBuffer(gl.ARRAY_BUFFER, this.textureCoordBuffer);
1322 | var textureCoords = null;
1323 | if (this.vrDisplay) {
1324 | var u = this.passThroughCamera.width / this.passThroughCamera.textureWidth;
1325 | var v = this.passThroughCamera.height / this.passThroughCamera.textureHeight;
1326 | textureCoords = [[0.0, 0.0, 0.0, v, u, 0.0, u, v], [u, 0.0, 0.0, 0.0, u, v, 0.0, v], [u, v, u, 0.0, 0.0, v, 0.0, 0.0], [0.0, v, u, v, 0.0, 0.0, u, 0.0]];
1327 | } else {
1328 | textureCoords = [[0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0], [1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0], [1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0], [0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0]];
1329 | }
1330 | this.f32TextureCoords = [];
1331 | for (var i = 0; i < textureCoords.length; i++) {
1332 | this.f32TextureCoords.push(new Float32Array(textureCoords[i]));
1333 | }
1334 | this.combinedOrientation = combineOrientations(screen.orientation.angle, this.passThroughCamera.orientation);
1335 | gl.bufferData(gl.ARRAY_BUFFER, this.f32TextureCoords[this.combinedOrientation], gl.STATIC_DRAW);
1336 | this.textureCoordBuffer.itemSize = 2;
1337 | this.textureCoordBuffer.numItems = 8;
1338 | gl.bindBuffer(gl.ARRAY_BUFFER, null);
1339 | this.indexBuffer = gl.createBuffer();
1340 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
1341 | var indices = [0, 1, 2, 2, 1, 3];
1342 | var ui16Indices = new Uint16Array(indices);
1343 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, ui16Indices, gl.STATIC_DRAW);
1344 | this.indexBuffer.itemSize = 1;
1345 | this.indexBuffer.numItems = 6;
1346 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
1347 | this.texture = gl.createTexture();
1348 | gl.useProgram(null);
1349 | this.projectionMatrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
1350 | this.mvMatrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
1351 | return this;
1352 | }
1353 | createClass(ARVideoRenderer, [{
1354 | key: 'render',
1355 | value: function render() {
1356 | var _this = this;
1357 | var gl = this.gl;
1358 | var bindings = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING, gl.CURRENT_PROGRAM];
1359 | glPreserveState(gl, bindings, function () {
1360 | gl.useProgram(_this.program);
1361 | gl.bindBuffer(gl.ARRAY_BUFFER, _this.vertexPositionBuffer);
1362 | gl.enableVertexAttribArray(_this.vertexPositionAttribute);
1363 | gl.vertexAttribPointer(_this.vertexPositionAttribute, _this.vertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
1364 | gl.bindBuffer(gl.ARRAY_BUFFER, _this.textureCoordBuffer);
1365 | var combinedOrientation = combineOrientations(screen.orientation.angle, _this.passThroughCamera.orientation);
1366 | if (combinedOrientation !== _this.combinedOrientation) {
1367 | _this.combinedOrientation = combinedOrientation;
1368 | gl.bufferData(gl.ARRAY_BUFFER, _this.f32TextureCoords[_this.combinedOrientation], gl.STATIC_DRAW);
1369 | }
1370 | gl.enableVertexAttribArray(_this.textureCoordAttribute);
1371 | gl.vertexAttribPointer(_this.textureCoordAttribute, _this.textureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
1372 | gl.activeTexture(gl.TEXTURE0);
1373 | gl.bindTexture(gl.TEXTURE_EXTERNAL_OES, _this.texture);
1374 | gl.texImage2D(gl.TEXTURE_EXTERNAL_OES, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, _this.passThroughCamera);
1375 | gl.uniform1i(_this.samplerUniform, 0);
1376 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, _this.indexBuffer);
1377 | gl.drawElements(gl.TRIANGLES, _this.indexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
1378 | });
1379 | }
1380 | }]);
1381 | return ARVideoRenderer;
1382 | }();
1383 | var ARView = function () {
1384 | function ARView(vrDisplay, renderer) {
1385 | classCallCheck(this, ARView);
1386 | this.vrDisplay = vrDisplay;
1387 | if (isARKit(this.vrDisplay)) {
1388 | return;
1389 | }
1390 | this.renderer = renderer;
1391 | this.gl = renderer.context;
1392 | this.videoRenderer = new ARVideoRenderer(vrDisplay, this.gl);
1393 | this.width = window.innerWidth;
1394 | this.height = window.innerHeight;
1395 | window.addEventListener('resize', this.onWindowResize.bind(this), false);
1396 | }
1397 | createClass(ARView, [{
1398 | key: 'onWindowResize',
1399 | value: function onWindowResize() {
1400 | this.width = window.innerWidth;
1401 | this.height = window.innerHeight;
1402 | }
1403 | }, {
1404 | key: 'render',
1405 | value: function render() {
1406 | if (isARKit(this.vrDisplay)) {
1407 | return;
1408 | }
1409 | var gl = this.gl;
1410 | var dpr = window.devicePixelRatio;
1411 | var width = this.width * dpr;
1412 | var height = this.height * dpr;
1413 | if (gl.viewportWidth !== width) {
1414 | gl.viewportWidth = width;
1415 | }
1416 | if (gl.viewportHeight !== height) {
1417 | gl.viewportHeight = height;
1418 | }
1419 | this.gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
1420 | this.videoRenderer.render();
1421 | }
1422 | }]);
1423 | return ARView;
1424 | }();
1425 |
1426 | var ARAnchorManager = function (_EventDispatcher) {
1427 | inherits(ARAnchorManager, _EventDispatcher);
1428 | function ARAnchorManager(vrDisplay) {
1429 | classCallCheck(this, ARAnchorManager);
1430 | var _this = possibleConstructorReturn(this, (ARAnchorManager.__proto__ || Object.getPrototypeOf(ARAnchorManager)).call(this));
1431 | if (!(vrDisplay instanceof window.VRDisplay)) {
1432 | throw new Error('A correct VRDisplay instance is required to ' + 'initialize an ARAnchorManager.');
1433 | }
1434 | if (typeof vrDisplay.getAnchors !== 'function') {
1435 | throw new Error('VRDisplay does not support anchors. Upgrade ' + 'to latest AR browser to get anchor support.');
1436 | }
1437 | _this.vrDisplay_ = vrDisplay;
1438 | _this.anchorsToObject3Ds_ = new Map();
1439 | _this.object3DsToAnchors_ = new Map();
1440 | _this.vrDisplay_.addEventListener('anchorsupdated', function (event) {
1441 | return _this.onAnchorsUpdated_(event);
1442 | });
1443 | _this.scale_ = new three.Vector3();
1444 | _this.matrix_ = new three.Matrix4();
1445 | return _this;
1446 | }
1447 | createClass(ARAnchorManager, [{
1448 | key: 'add',
1449 | value: function add(object3d) {
1450 | if (!(object3d instanceof three.Object3D)) {
1451 | throw new Error('Invalid Object3D trying to add an anchor');
1452 | }
1453 | if (this.object3DsToAnchors_.has(object3d)) {
1454 | return this;
1455 | }
1456 | this.scale_.set(1, 1, 1);
1457 | this.matrix_.compose(object3d.position, object3d.quaternion, this.scale_);
1458 | var anchor = this.vrDisplay_.addAnchor(this.matrix_.elements);
1459 | this.anchorsToObject3Ds_.set(anchor, object3d);
1460 | this.object3DsToAnchors_.set(object3d, anchor);
1461 | return this;
1462 | }
1463 | }, {
1464 | key: 'remove',
1465 | value: function remove(object3d) {
1466 | if (!(object3d instanceof three.Object3D)) {
1467 | throw new Error('Invalid Object3D trying to remove anchor');
1468 | }
1469 | var anchor = this.object3DsToAnchors_.get(object3d);
1470 | if (!anchor) {
1471 | return false;
1472 | }
1473 | this.anchorsToObject3Ds_.delete(anchor);
1474 | this.object3DsToAnchors_.delete(object3d);
1475 | this.vrDisplay_.removeAnchor(anchor);
1476 | return true;
1477 | }
1478 | }, {
1479 | key: 'onAnchorsUpdated_',
1480 | value: function onAnchorsUpdated_(event) {
1481 | var updatedObject3Ds = [];
1482 | var _iteratorNormalCompletion = true;
1483 | var _didIteratorError = false;
1484 | var _iteratorError = undefined;
1485 | try {
1486 | for (var _iterator = event.anchors[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
1487 | var anchor = _step.value;
1488 | var object3d = this.anchorsToObject3Ds_.get(anchor);
1489 | if (!object3d) {
1490 | continue;
1491 | }
1492 | object3d.matrix.fromArray(anchor.modelMatrix);
1493 | object3d.matrix.decompose(object3d.position, object3d.quaternion, this.scale_);
1494 | updatedObject3Ds.push(object3d);
1495 | }
1496 | } catch (err) {
1497 | _didIteratorError = true;
1498 | _iteratorError = err;
1499 | } finally {
1500 | try {
1501 | if (!_iteratorNormalCompletion && _iterator.return) {
1502 | _iterator.return();
1503 | }
1504 | } finally {
1505 | if (_didIteratorError) {
1506 | throw _iteratorError;
1507 | }
1508 | }
1509 | }
1510 | this.dispatchEvent({ type: 'anchorsupdated', anchors: updatedObject3Ds });
1511 | }
1512 | }]);
1513 | return ARAnchorManager;
1514 | }(three.EventDispatcher);
1515 |
1516 | (function () {
1517 | if (window.webarSpeechRecognitionInstance) {
1518 | var addEventHandlingToObject = function addEventHandlingToObject(object) {
1519 | object.listeners = {};
1520 | object.addEventListener = function (eventType, callback) {
1521 | if (!callback) {
1522 | return this;
1523 | }
1524 | var listeners = this.listeners[eventType];
1525 | if (!listeners) {
1526 | this.listeners[eventType] = listeners = [];
1527 | }
1528 | if (listeners.indexOf(callback) < 0) {
1529 | listeners.push(callback);
1530 | }
1531 | return this;
1532 | };
1533 | object.removeEventListener = function (eventType, callback) {
1534 | if (!callback) {
1535 | return this;
1536 | }
1537 | var listeners = this.listeners[eventType];
1538 | if (listeners) {
1539 | var i = listeners.indexOf(callback);
1540 | if (i >= 0) {
1541 | this.listeners[eventType] = listeners.splice(i, 1);
1542 | }
1543 | }
1544 | return this;
1545 | };
1546 | object.callEventListeners = function (eventType, event) {
1547 | if (!event) {
1548 | event = { target: this };
1549 | }
1550 | if (!event.target) {
1551 | event.target = this;
1552 | }
1553 | event.type = eventType;
1554 | var onEventType = 'on' + eventType;
1555 | if (typeof this[onEventType] === 'function') {
1556 | this[onEventType](event);
1557 | }
1558 | var listeners = this.listeners[eventType];
1559 | if (listeners) {
1560 | for (var i = 0; i < listeners.length; i++) {
1561 | var typeofListener = _typeof(listeners[i]);
1562 | if (typeofListener === 'object') {
1563 | listeners[i].handleEvent(event);
1564 | } else if (typeofListener === 'function') {
1565 | listeners[i](event);
1566 | }
1567 | }
1568 | }
1569 | return this;
1570 | };
1571 | };
1572 | addEventHandlingToObject(window.webarSpeechRecognitionInstance);
1573 | window.webkitSpeechRecognition = function () {
1574 | return window.webarSpeechRecognitionInstance;
1575 | };
1576 | }
1577 | })();
1578 |
1579 | if (typeof window !== 'undefined' && _typeof(window.THREE) === 'object') {
1580 | window.THREE.ARDebug = ARDebug;
1581 | window.THREE.ARPerspectiveCamera = ARPerspectiveCamera;
1582 | window.THREE.ARReticle = ARReticle;
1583 | window.THREE.ARUtils = ARUtils;
1584 | window.THREE.ARView = ARView;
1585 | window.THREE.ARAnchorManager = ARAnchorManager;
1586 | }
1587 |
1588 | exports.ARDebug = ARDebug;
1589 | exports.ARPerspectiveCamera = ARPerspectiveCamera;
1590 | exports.ARReticle = ARReticle;
1591 | exports.ARUtils = ARUtils;
1592 | exports.ARView = ARView;
1593 | exports.ARAnchorManager = ARAnchorManager;
1594 |
1595 | Object.defineProperty(exports, '__esModule', { value: true });
1596 |
1597 | })));
1598 |
--------------------------------------------------------------------------------
/models/Hip Hop Dancing.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/Hip Hop Dancing.fbx
--------------------------------------------------------------------------------
/models/Takashi-Thriller.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/Takashi-Thriller.fbx
--------------------------------------------------------------------------------
/models/daito/Arm_col.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/daito/Arm_col.jpg
--------------------------------------------------------------------------------
/models/daito/Cap_col.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/daito/Cap_col.jpg
--------------------------------------------------------------------------------
/models/daito/HeadBase_col.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/daito/HeadBase_col.jpg
--------------------------------------------------------------------------------
/models/daito/Pants_col.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/daito/Pants_col.jpg
--------------------------------------------------------------------------------
/models/daito/Shose_col.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/daito/Shose_col.jpg
--------------------------------------------------------------------------------
/models/daito/Tshirt_col.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/daito/Tshirt_col.jpg
--------------------------------------------------------------------------------
/models/porg/Hip Hop Dancing.fbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/porg/Hip Hop Dancing.fbx
--------------------------------------------------------------------------------
/models/porg/body_d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/porg/body_d.png
--------------------------------------------------------------------------------
/models/porg/body_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/porg/body_n.png
--------------------------------------------------------------------------------
/models/porg/body_s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/porg/body_s.png
--------------------------------------------------------------------------------
/models/porg/eye_d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/porg/eye_d.png
--------------------------------------------------------------------------------
/models/porg/eye_d_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/porg/eye_d_.png
--------------------------------------------------------------------------------
/models/porg/eye_env.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/porg/eye_env.png
--------------------------------------------------------------------------------
/models/porg/feathers_d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/porg/feathers_d.png
--------------------------------------------------------------------------------
/models/porg/feathers_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrdoob/webar-experiments/5b82a3ab6cf4d73aa51d73370be3ebd240df6493/models/porg/feathers_n.png
--------------------------------------------------------------------------------
/webgl_dae_daito.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | three.ar.js - Load Model
5 |
6 |
8 |
39 |
40 |
41 |
44 |
45 |
46 |
47 |
48 |
49 |
309 |
310 |
311 |
--------------------------------------------------------------------------------
/webgl_fbx_mixamo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | three.ar.js - Load Model
5 |
6 |
8 |
39 |
40 |
41 |
44 |
45 |
46 |
47 |
48 |
49 |
305 |
306 |
307 |
--------------------------------------------------------------------------------
/webgl_fbx_porg.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | three.ar.js - Load Model
5 |
6 |
8 |
42 |
43 |
44 |
48 |
49 |
50 |
51 |
52 |
53 |
318 |
319 |
320 |
--------------------------------------------------------------------------------
/webgl_fbx_takashi.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | three.ar.js - Load Model
5 |
6 |
8 |
39 |
40 |
41 |
44 |
45 |
46 |
47 |
48 |
49 |
307 |
308 |
309 |
--------------------------------------------------------------------------------