├── 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 |
35 | webgl_dae_daito
36 | webgl_fbx_mixamo
37 | webgl_fbx_porg
38 | webgl_fbx_takashi 39 |
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 |
42 | webar experiments 43 |
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 |
42 | webar experiments 43 |
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 |
45 | 46 | 47 |
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 |
42 | webar experiments 43 |
44 | 45 | 46 | 47 | 48 | 49 | 307 | 308 | 309 | --------------------------------------------------------------------------------