1( function () { 2 3 class GLTFLoader extends THREE.Loader { 4 5 constructor( manager ) { 6 7 super( manager ); 8 this.dracoLoader = null; 9 this.ktx2Loader = null; 10 this.meshoptDecoder = null; 11 this.pluginCallbacks = []; 12 this.register( function ( parser ) { 13 14 return new GLTFMaterialsClearcoatExtension( parser ); 15 16 } ); 17 this.register( function ( parser ) { 18 19 return new GLTFTextureBasisUExtension( parser ); 20 21 } ); 22 this.register( function ( parser ) { 23 24 return new GLTFTextureWebPExtension( parser ); 25 26 } ); 27 this.register( function ( parser ) { 28 29 return new GLTFMaterialsSheenExtension( parser ); 30 31 } ); 32 this.register( function ( parser ) { 33 34 return new GLTFMaterialsTransmissionExtension( parser ); 35 36 } ); 37 this.register( function ( parser ) { 38 39 return new GLTFMaterialsVolumeExtension( parser ); 40 41 } ); 42 this.register( function ( parser ) { 43 44 return new GLTFMaterialsIorExtension( parser ); 45 46 } ); 47 this.register( function ( parser ) { 48 49 return new GLTFMaterialsSpecularExtension( parser ); 50 51 } ); 52 this.register( function ( parser ) { 53 54 return new GLTFLightsExtension( parser ); 55 56 } ); 57 this.register( function ( parser ) { 58 59 return new GLTFMeshoptCompression( parser ); 60 61 } ); 62 63 } 64 65 load( url, onLoad, onProgress, onError ) { 66 67 const scope = this; 68 let resourcePath; 69 70 if ( this.resourcePath !== '' ) { 71 72 resourcePath = this.resourcePath; 73 74 } else if ( this.path !== '' ) { 75 76 resourcePath = this.path; 77 78 } else { 79 80 resourcePath = THREE.LoaderUtils.extractUrlBase( url ); 81 82 } // Tells the LoadingManager to track an extra item, which resolves after 83 // the model is fully loaded. This means the count of items loaded will 84 // be incorrect, but ensures manager.onLoad() does not fire early. 85 86 87 this.manager.itemStart( url ); 88 89 const _onError = function ( e ) { 90 91 if ( onError ) { 92 93 onError( e ); 94 95 } else { 96 97 console.error( e ); 98 99 } 100 101 scope.manager.itemError( url ); 102 scope.manager.itemEnd( url ); 103 104 }; 105 106 const loader = new THREE.FileLoader( this.manager ); 107 loader.setPath( this.path ); 108 loader.setResponseType( 'arraybuffer' ); 109 loader.setRequestHeader( this.requestHeader ); 110 loader.setWithCredentials( this.withCredentials ); 111 loader.load( url, function ( data ) { 112 113 try { 114 115 scope.parse( data, resourcePath, function ( gltf ) { 116 117 onLoad( gltf ); 118 scope.manager.itemEnd( url ); 119 120 }, _onError ); 121 122 } catch ( e ) { 123 124 _onError( e ); 125 126 } 127 128 }, onProgress, _onError ); 129 130 } 131 132 setDRACOLoader( dracoLoader ) { 133 134 this.dracoLoader = dracoLoader; 135 return this; 136 137 } 138 139 setDDSLoader() { 140 141 throw new Error( 'THREE.GLTFLoader: "MSFT_texture_dds" no longer supported. Please update to "KHR_texture_basisu".' ); 142 143 } 144 145 setKTX2Loader( ktx2Loader ) { 146 147 this.ktx2Loader = ktx2Loader; 148 return this; 149 150 } 151 152 setMeshoptDecoder( meshoptDecoder ) { 153 154 this.meshoptDecoder = meshoptDecoder; 155 return this; 156 157 } 158 159 register( callback ) { 160 161 if ( this.pluginCallbacks.indexOf( callback ) === - 1 ) { 162 163 this.pluginCallbacks.push( callback ); 164 165 } 166 167 return this; 168 169 } 170 171 unregister( callback ) { 172 173 if ( this.pluginCallbacks.indexOf( callback ) !== - 1 ) { 174 175 this.pluginCallbacks.splice( this.pluginCallbacks.indexOf( callback ), 1 ); 176 177 } 178 179 return this; 180 181 } 182 183 parse( data, path, onLoad, onError ) { 184 185 let content; 186 const extensions = {}; 187 const plugins = {}; 188 189 if ( typeof data === 'string' ) { 190 191 content = data; 192 193 } else { 194 195 const magic = THREE.LoaderUtils.decodeText( new Uint8Array( data, 0, 4 ) ); 196 197 if ( magic === BINARY_EXTENSION_HEADER_MAGIC ) { 198 199 try { 200 201 extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data ); 202 203 } catch ( error ) { 204 205 if ( onError ) onError( error ); 206 return; 207 208 } 209 210 content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content; 211 212 } else { 213 214 content = THREE.LoaderUtils.decodeText( new Uint8Array( data ) ); 215 216 } 217 218 } 219 220 const json = JSON.parse( content ); 221 222 if ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) { 223 224 if ( onError ) onError( new Error( 'THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported.' ) ); 225 return; 226 227 } 228 229 const parser = new GLTFParser( json, { 230 path: path || this.resourcePath || '', 231 crossOrigin: this.crossOrigin, 232 requestHeader: this.requestHeader, 233 manager: this.manager, 234 ktx2Loader: this.ktx2Loader, 235 meshoptDecoder: this.meshoptDecoder 236 } ); 237 parser.fileLoader.setRequestHeader( this.requestHeader ); 238 239 for ( let i = 0; i < this.pluginCallbacks.length; i ++ ) { 240 241 const plugin = this.pluginCallbacks[ i ]( parser ); 242 plugins[ plugin.name ] = plugin; // Workaround to avoid determining as unknown extension 243 // in addUnknownExtensionsToUserData(). 244 // Remove this workaround if we move all the existing 245 // extension handlers to plugin system 246 247 extensions[ plugin.name ] = true; 248 249 } 250 251 if ( json.extensionsUsed ) { 252 253 for ( let i = 0; i < json.extensionsUsed.length; ++ i ) { 254 255 const extensionName = json.extensionsUsed[ i ]; 256 const extensionsRequired = json.extensionsRequired || []; 257 258 switch ( extensionName ) { 259 260 case EXTENSIONS.KHR_MATERIALS_UNLIT: 261 extensions[ extensionName ] = new GLTFMaterialsUnlitExtension(); 262 break; 263 264 case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 265 extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension(); 266 break; 267 268 case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION: 269 extensions[ extensionName ] = new GLTFDracoMeshCompressionExtension( json, this.dracoLoader ); 270 break; 271 272 case EXTENSIONS.KHR_TEXTURE_TRANSFORM: 273 extensions[ extensionName ] = new GLTFTextureTransformExtension(); 274 break; 275
vendor: 4,819 bytes, lines 276-447
276 case EXTENSIONS.KHR_MESH_QUANTIZATION: 277 extensions[ extensionName ] = new GLTFMeshQuantizationExtension(); 278 break; 279 280 default: 281 if ( extensionsRequired.indexOf( extensionName ) >= 0 && plugins[ extensionName ] === undefined ) { 282 283 console.warn( 'THREE.GLTFLoader: Unknown extension "' + extensionName + '".' ); 284 285 } 286 287 } 288 289 } 290 291 } 292 293 parser.setExtensions( extensions ); 294 parser.setPlugins( plugins ); 295 parser.parse( onLoad, onError ); 296 297 } 298 299 } 300 /* GLTFREGISTRY */ 301 302 303 function GLTFRegistry() { 304 305 let objects = {}; 306 return { 307 get: function ( key ) { 308 309 return objects[ key ]; 310 311 }, 312 add: function ( key, object ) { 313 314 objects[ key ] = object; 315 316 }, 317 remove: function ( key ) { 318 319 delete objects[ key ]; 320 321 }, 322 removeAll: function () { 323 324 objects = {}; 325 326 } 327 }; 328 329 } 330 /*********************************/ 331 332 /********** EXTENSIONS ***********/ 333 334 /*********************************/ 335 336 337 const EXTENSIONS = { 338 KHR_BINARY_GLTF: 'KHR_binary_glTF', 339 KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression', 340 KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual', 341 KHR_MATERIALS_CLEARCOAT: 'KHR_materials_clearcoat', 342 KHR_MATERIALS_IOR: 'KHR_materials_ior', 343 KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness', 344 KHR_MATERIALS_SHEEN: 'KHR_materials_sheen', 345 KHR_MATERIALS_SPECULAR: 'KHR_materials_specular', 346 KHR_MATERIALS_TRANSMISSION: 'KHR_materials_transmission', 347 KHR_MATERIALS_UNLIT: 'KHR_materials_unlit', 348 KHR_MATERIALS_VOLUME: 'KHR_materials_volume', 349 KHR_TEXTURE_BASISU: 'KHR_texture_basisu', 350 KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform', 351 KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization', 352 EXT_TEXTURE_WEBP: 'EXT_texture_webp', 353 EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression' 354 }; 355 /** 356 * Punctual Lights Extension 357 * 358 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual 359 */ 360 361 class GLTFLightsExtension { 362 363 constructor( parser ) { 364 365 this.parser = parser; 366 this.name = EXTENSIONS.KHR_LIGHTS_PUNCTUAL; // THREE.Object3D instance caches 367 368 this.cache = { 369 refs: {}, 370 uses: {} 371 }; 372 373 } 374 375 _markDefs() { 376 377 const parser = this.parser; 378 const nodeDefs = this.parser.json.nodes || []; 379 380 for ( let nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex ++ ) { 381 382 const nodeDef = nodeDefs[ nodeIndex ]; 383 384 if ( nodeDef.extensions && nodeDef.extensions[ this.name ] && nodeDef.extensions[ this.name ].light !== undefined ) { 385 386 parser._addNodeRef( this.cache, nodeDef.extensions[ this.name ].light ); 387 388 } 389 390 } 391 392 } 393 394 _loadLight( lightIndex ) { 395 396 const parser = this.parser; 397 const cacheKey = 'light:' + lightIndex; 398 let dependency = parser.cache.get( cacheKey ); 399 if ( dependency ) return dependency; 400 const json = parser.json; 401 const extensions = json.extensions && json.extensions[ this.name ] || {}; 402 const lightDefs = extensions.lights || []; 403 const lightDef = lightDefs[ lightIndex ]; 404 let lightNode; 405 const color = new THREE.Color( 0xffffff ); 406 if ( lightDef.color !== undefined ) color.fromArray( lightDef.color ); 407 const range = lightDef.range !== undefined ? lightDef.range : 0; 408 409 switch ( lightDef.type ) { 410 411 case 'directional': 412 lightNode = new THREE.DirectionalLight( color ); 413 lightNode.target.position.set( 0, 0, - 1 ); 414 lightNode.add( lightNode.target ); 415 break; 416 417 case 'point': 418 lightNode = new THREE.PointLight( color ); 419 lightNode.distance = range; 420 break; 421 422 case 'spot': 423 lightNode = new THREE.SpotLight( color ); 424 lightNode.distance = range; // Handle spotlight properties. 425 426 lightDef.spot = lightDef.spot || {}; 427 lightDef.spot.innerConeAngle = lightDef.spot.innerConeAngle !== undefined ? lightDef.spot.innerConeAngle : 0; 428 lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0; 429 lightNode.angle = lightDef.spot.outerConeAngle; 430 lightNode.penumbra = 1.0 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle; 431 lightNode.target.position.set( 0, 0, - 1 ); 432 lightNode.add( lightNode.target ); 433 break; 434 435 default: 436 throw new Error( 'THREE.GLTFLoader: Unexpected light type: ' + lightDef.type ); 437 438 } // Some lights (e.g. spot) default to a position other than the origin. Reset the position 439 // here, because node-level parsing will only override position if explicitly specified. 440 441 442 lightNode.position.set( 0, 0, 0 ); 443 lightNode.decay = 2; 444 if ( lightDef.intensity !== undefined ) lightNode.intensity = lightDef.intensity; 445 lightNode.name = parser.createUniqueName( lightDef.name || 'light_' + lightIndex ); 446 dependency = Promise.resolve( lightNode ); 447 parser.cache.add( cacheKey, dependency );
448 return dependency; 449 450 } 451 452 createNodeAttachment( nodeIndex ) { 453 454 const self = this; 455 const parser = this.parser; 456 const json = parser.json; 457 const nodeDef = json.nodes[ nodeIndex ]; 458 const lightDef = nodeDef.extensions && nodeDef.extensions[ this.name ] || {}; 459 const lightIndex = lightDef.light; 460 if ( lightIndex === undefined ) return null; 461 return this._loadLight( lightIndex ).then( function ( light ) { 462 463 return parser._getNodeRef( self.cache, lightIndex, light ); 464 465 } ); 466 467 } 468 469 } 470 /** 471 * Unlit Materials Extension 472 * 473 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit 474 */ 475 476 477 class GLTFMaterialsUnlitExtension { 478 479 constructor() { 480 481 this.name = EXTENSIONS.KHR_MATERIALS_UNLIT; 482 483 } 484 485 getMaterialType() { 486 487 return THREE.MeshBasicMaterial; 488 489 } 490 491 extendParams( materialParams, materialDef, parser ) { 492 493 const pending = []; 494 materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 ); 495 materialParams.opacity = 1.0; 496 const metallicRoughness = materialDef.pbrMetallicRoughness; 497 498 if ( metallicRoughness ) { 499 500 if ( Array.isArray( metallicRoughness.baseColorFactor ) ) { 501 502 const array = metallicRoughness.baseColorFactor; 503 materialParams.color.fromArray( array ); 504 materialParams.opacity = array[ 3 ]; 505 506 } 507 508 if ( metallicRoughness.baseColorTexture !== undefined ) { 509 510 pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) ); 511 512 } 513 514 } 515 516 return Promise.all( pending ); 517 518 } 519 520 } 521 /** 522 * Clearcoat Materials Extension 523 * 524 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_clearcoat 525 */ 526 527 528 class GLTFMaterialsClearcoatExtension { 529 530 constructor( parser ) { 531 532 this.parser = parser; 533 this.name = EXTENSIONS.KHR_MATERIALS_CLEARCOAT; 534 535 } 536 537 getMaterialType( materialIndex ) { 538 539 const parser = this.parser; 540 const materialDef = parser.json.materials[ materialIndex ]; 541 if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null; 542 return THREE.MeshPhysicalMaterial; 543 544 } 545 546 extendMaterialParams( materialIndex, materialParams ) { 547 548 const parser = this.parser; 549 const materialDef = parser.json.materials[ materialIndex ]; 550 551 if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) { 552 553 return Promise.resolve(); 554 555 } 556 557 const pending = []; 558 const extension = materialDef.extensions[ this.name ]; 559 560 if ( extension.clearcoatFactor !== undefined ) { 561 562 materialParams.clearcoat = extension.clearcoatFactor; 563 564 } 565 566 if ( extension.clearcoatTexture !== undefined ) { 567 568 pending.push( parser.assignTexture( materialParams, 'clearcoatMap', extension.clearcoatTexture ) ); 569 570 } 571 572 if ( extension.clearcoatRoughnessFactor !== undefined ) { 573 574 materialParams.clearcoatRoughness = extension.clearcoatRoughnessFactor; 575 576 } 577 578 if ( extension.clearcoatRoughnessTexture !== undefined ) { 579 580 pending.push( parser.assignTexture( materialParams, 'clearcoatRoughnessMap', extension.clearcoatRoughnessTexture ) ); 581 582 } 583 584 if ( extension.clearcoatNormalTexture !== undefined ) { 585 586 pending.push( parser.assignTexture( materialParams, 'clearcoatNormalMap', extension.clearcoatNormalTexture ) ); 587 588 if ( extension.clearcoatNormalTexture.scale !== undefined ) { 589 590 const scale = extension.clearcoatNormalTexture.scale; 591 materialParams.clearcoatNormalScale = new THREE.Vector2( scale, scale ); 592 593 } 594 595 } 596 597 return Promise.all( pending ); 598 599 } 600 601 } 602 /** 603 * Sheen Materials Extension 604 * 605 * Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_sheen 606 */ 607 608 609 class GLTFMaterialsSheenExtension { 610 611 constructor( parser ) { 612 613 this.parser = parser; 614 this.name = EXTENSIONS.KHR_MATERIALS_SHEEN; 615 616 } 617 618 getMaterialType( materialIndex ) { 619 620 const parser = this.parser; 621 const materialDef = parser.json.materials[ materialIndex ]; 622 if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null; 623 return THREE.MeshPhysicalMaterial; 624 625 } 626 627 extendMaterialParams( materialIndex, materialParams ) { 628 629 const parser = this.parser; 630 const materialDef = parser.json.materials[ materialIndex ]; 631 632 if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) { 633 634 return Promise.resolve(); 635 636 } 637 638 const pending = []; 639 materialParams.sheenColor = new THREE.Color( 0, 0, 0 ); 640 materialParams.sheenRoughness = 0; 641 materialParams.sheen = 1; 642 const extension = materialDef.extensions[ this.name ]; 643 644 if ( extension.sheenColorFactor !== undefined ) { 645 646 materialParams.sheenColor.fromArray( extension.sheenColorFactor ); 647 648 } 649 650 if ( extension.sheenRoughnessFactor !== undefined ) { 651 652 materialParams.sheenRoughness = extension.sheenRoughnessFactor; 653 654 } 655 656 if ( extension.sheenColorTexture !== undefined ) { 657 658 pending.push( parser.assignTexture( materialParams, 'sheenColorMap', extension.sheenColorTexture ) ); 659 660 } 661 662 if ( extension.sheenRoughnessTexture !== undefined ) { 663 664 pending.push( parser.assignTexture( materialParams, 'sheenRoughnessMap', extension.sheenRoughnessTexture ) ); 665 666 } 667 668 return Promise.all( pending ); 669 670 } 671 672 } 673 /** 674 * Transmission Materials Extension 675 * 676 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_transmission 677 * Draft: https://github.com/KhronosGroup/glTF/pull/1698 678 */ 679 680 681 class GLTFMaterialsTransmissionExtension { 682 683 constructor( parser ) { 684 685 this.parser = parser; 686 this.name = EXTENSIONS.KHR_MATERIALS_TRANSMISSION; 687 688 } 689 690 getMaterialType( materialIndex ) { 691 692 const parser = this.parser; 693 const materialDef = parser.json.materials[ materialIndex ]; 694 if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null; 695 return THREE.MeshPhysicalMaterial; 696 697 } 698 699 extendMaterialParams( materialIndex, materialParams ) { 700 701 const parser = this.parser; 702 const materialDef = parser.json.materials[ materialIndex ]; 703 704 if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) { 705 706 return Promise.resolve(); 707 708 } 709 710 const pending = []; 711 const extension = materialDef.extensions[ this.name ]; 712 713 if ( extension.transmissionFactor !== undefined ) { 714 715 materialParams.transmission = extension.transmissionFactor; 716 717 } 718 719 if ( extension.transmissionTexture !== undefined ) { 720 721 pending.push( parser.assignTexture( materialParams, 'transmissionMap', extension.transmissionTexture ) ); 722 723 } 724 725 return Promise.all( pending ); 726 727 } 728 729 } 730 /** 731 * Materials Volume Extension 732 * 733 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_volume 734 */ 735 736 737 class GLTFMaterialsVolumeExtension { 738 739 constructor( parser ) { 740 741 this.parser = parser; 742 this.name = EXTENSIONS.KHR_MATERIALS_VOLUME; 743 744 } 745 746 getMaterialType( materialIndex ) { 747 748 const parser = this.parser; 749 const materialDef = parser.json.materials[ materialIndex ]; 750 if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null; 751 return THREE.MeshPhysicalMaterial; 752 753 } 754 755 extendMaterialParams( materialIndex, materialParams ) { 756 757 const parser = this.parser; 758 const materialDef = parser.json.materials[ materialIndex ]; 759 760 if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) { 761 762 return Promise.resolve(); 763 764 } 765 766 const pending = []; 767 const extension = materialDef.extensions[ this.name ]; 768 materialParams.thickness = extension.thicknessFactor !== undefined ? extension.thicknessFactor : 0; 769 770 if ( extension.thicknessTexture !== undefined ) { 771 772 pending.push( parser.assignTexture( materialParams, 'thicknessMap', extension.thicknessTexture ) ); 773 774 } 775 776 materialParams.attenuationDistance = extension.attenuationDistance || 0; 777 const colorArray = extension.attenuationColor || [ 1, 1, 1 ]; 778 materialParams.attenuationColor = new THREE.Color( colorArray[ 0 ], colorArray[ 1 ], colorArray[ 2 ] ); 779 return Promise.all( pending ); 780 781 } 782 783 } 784 /** 785 * Materials ior Extension 786 * 787 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_ior 788 */ 789 790
791 class GLTFMaterialsIorExtension { 792 793 constructor( parser ) { 794 795 this.parser = parser; 796 this.name = EXTENSIONS.KHR_MATERIALS_IOR; 797 798 } 799 800 getMaterialType( materialIndex ) { 801 802 const parser = this.parser; 803 const materialDef = parser.json.materials[ materialIndex ]; 804 if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null; 805 return THREE.MeshPhysicalMaterial; 806 807 } 808 809 extendMaterialParams( materialIndex, materialParams ) { 810 811 const parser = this.parser; 812 const materialDef = parser.json.materials[ materialIndex ]; 813 814 if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) { 815 816 return Promise.resolve(); 817 818 } 819 820 const extension = materialDef.extensions[ this.name ]; 821 materialParams.ior = extension.ior !== undefined ? extension.ior : 1.5; 822 return Promise.resolve(); 823 824 } 825 826 } 827 /** 828 * Materials specular Extension 829 * 830 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_specular 831 */ 832 833 834 class GLTFMaterialsSpecularExtension { 835 836 constructor( parser ) { 837 838 this.parser = parser; 839 this.name = EXTENSIONS.KHR_MATERIALS_SPECULAR; 840 841 } 842 843 getMaterialType( materialIndex ) { 844 845 const parser = this.parser; 846 const materialDef = parser.json.materials[ materialIndex ]; 847 if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null; 848 return THREE.MeshPhysicalMaterial; 849 850 } 851 852 extendMaterialParams( materialIndex, materialParams ) { 853 854 const parser = this.parser; 855 const materialDef = parser.json.materials[ materialIndex ]; 856 857 if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) { 858 859 return Promise.resolve(); 860 861 } 862 863 const pending = []; 864 const extension = materialDef.extensions[ this.name ]; 865 materialParams.specularIntensity = extension.specularFactor !== undefined ? extension.specularFactor : 1.0; 866 867 if ( extension.specularTexture !== undefined ) { 868 869 pending.push( parser.assignTexture( materialParams, 'specularIntensityMap', extension.specularTexture ) ); 870 871 } 872 873 const colorArray = extension.specularColorFactor || [ 1, 1, 1 ]; 874 materialParams.specularColor = new THREE.Color( colorArray[ 0 ], colorArray[ 1 ], colorArray[ 2 ] ); 875 876 if ( extension.specularColorTexture !== undefined ) { 877 878 pending.push( parser.assignTexture( materialParams, 'specularColorMap', extension.specularColorTexture ).then( function ( texture ) { 879 880 texture.encoding = THREE.sRGBEncoding; 881 882 } ) ); 883 884 } 885 886 return Promise.all( pending ); 887 888 } 889 890 } 891 /** 892 * BasisU THREE.Texture Extension 893 * 894 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_basisu 895 */ 896 897 898 class GLTFTextureBasisUExtension { 899 900 constructor( parser ) { 901 902 this.parser = parser; 903 this.name = EXTENSIONS.KHR_TEXTURE_BASISU; 904 905 } 906 907 loadTexture( textureIndex ) { 908 909 const parser = this.parser; 910 const json = parser.json; 911 const textureDef = json.textures[ textureIndex ]; 912 913 if ( ! textureDef.extensions || ! textureDef.extensions[ this.name ] ) { 914 915 return null; 916 917 } 918 919 const extension = textureDef.extensions[ this.name ]; 920 const source = json.images[ extension.source ]; 921 const loader = parser.options.ktx2Loader; 922 923 if ( ! loader ) { 924 925 if ( json.extensionsRequired && json.extensionsRequired.indexOf( this.name ) >= 0 ) { 926 927 throw new Error( 'THREE.GLTFLoader: setKTX2Loader must be called before loading KTX2 textures' ); 928 929 } else { 930 931 // Assumes that the extension is optional and that a fallback texture is present 932 return null; 933 934 } 935 936 } 937 938 return parser.loadTextureImage( textureIndex, source, loader ); 939 940 } 941 942 } 943 /** 944 * WebP THREE.Texture Extension 945 * 946 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_texture_webp 947 */ 948 949 950 class GLTFTextureWebPExtension { 951 952 constructor( parser ) { 953 954 this.parser = parser; 955 this.name = EXTENSIONS.EXT_TEXTURE_WEBP; 956 this.isSupported = null; 957 958 } 959 960 loadTexture( textureIndex ) { 961 962 const name = this.name; 963 const parser = this.parser; 964 const json = parser.json; 965 const textureDef = json.textures[ textureIndex ]; 966 967 if ( ! textureDef.extensions || ! textureDef.extensions[ name ] ) { 968 969 return null; 970 971 } 972 973 const extension = textureDef.extensions[ name ]; 974 const source = json.images[ extension.source ]; 975 let loader = parser.textureLoader; 976 977 if ( source.uri ) { 978 979 const handler = parser.options.manager.getHandler( source.uri ); 980 if ( handler !== null ) loader = handler; 981 982 } 983 984 return this.detectSupport().then( function ( isSupported ) { 985 986 if ( isSupported ) return parser.loadTextureImage( textureIndex, source, loader ); 987 988 if ( json.extensionsRequired && json.extensionsRequired.indexOf( name ) >= 0 ) { 989 990 throw new Error( 'THREE.GLTFLoader: WebP required by asset but unsupported.' ); 991 992 } // Fall back to PNG or JPEG. 993 994 995 return parser.loadTexture( textureIndex ); 996 997 } ); 998 999 } 1000 1001 detectSupport() { 1002 1003 if ( ! this.isSupported ) { 1004 1005 this.isSupported = new Promise( function ( resolve ) { 1006 1007 const image = new Image(); // Lossy test image. Support for lossy images doesn't guarantee support for all 1008 // WebP images, unfortunately. 1009 1010 image.src = 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA'; 1011 1012 image.onload = image.onerror = function () { 1013 1014 resolve( image.height === 1 ); 1015 1016 }; 1017 1018 } ); 1019 1020 } 1021 1022 return this.isSupported; 1023 1024 } 1025 1026 } 1027 /** 1028 * meshopt BufferView Compression Extension 1029 * 1030 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_meshopt_compression 1031 */ 1032 1033 1034 class GLTFMeshoptCompression { 1035 1036 constructor( parser ) { 1037 1038 this.name = EXTENSIONS.EXT_MESHOPT_COMPRESSION; 1039 this.parser = parser; 1040 1041 } 1042 1043 loadBufferView( index ) { 1044 1045 const json = this.parser.json; 1046 const bufferView = json.bufferViews[ index ]; 1047 1048 if ( bufferView.extensions && bufferView.extensions[ this.name ] ) { 1049 1050 const extensionDef = bufferView.extensions[ this.name ]; 1051 const buffer = this.parser.getDependency( 'buffer', extensionDef.buffer ); 1052 const decoder = this.parser.options.meshoptDecoder; 1053 1054 if ( ! decoder || ! decoder.supported ) { 1055 1056 if ( json.extensionsRequired && json.extensionsRequired.indexOf( this.name ) >= 0 ) { 1057 1058 throw new Error( 'THREE.GLTFLoader: setMeshoptDecoder must be called before loading compressed files' ); 1059 1060 } else { 1061 1062 // Assumes that the extension is optional and that fallback buffer data is present 1063 return null; 1064 1065 } 1066 1067 } 1068 1069 return Promise.all( [ buffer, decoder.ready ] ).then( function ( res ) { 1070 1071 const byteOffset = extensionDef.byteOffset || 0; 1072 const byteLength = extensionDef.byteLength || 0; 1073 const count = extensionDef.count; 1074 const stride = extensionDef.byteStride; 1075 const result = new ArrayBuffer( count * stride ); 1076 const source = new Uint8Array( res[ 0 ], byteOffset, byteLength ); 1077 decoder.decodeGltfBuffer( new Uint8Array( result ), count, stride, source, extensionDef.mode, extensionDef.filter ); 1078 return result; 1079 1080 } ); 1081 1082 } else { 1083 1084 return null; 1085 1086 } 1087 1088 } 1089 1090 } 1091 /* BINARY EXTENSION */ 1092 1093 1094 const BINARY_EXTENSION_HEADER_MAGIC = 'glTF'; 1095 const BINARY_EXTENSION_HEADER_LENGTH = 12; 1096 const BINARY_EXTENSION_CHUNK_TYPES = { 1097 JSON: 0x4E4F534A, 1098 BIN: 0x004E4942 1099 }; 1100 1101 class GLTFBinaryExtension { 1102 1103 constructor( data ) { 1104 1105 this.name = EXTENSIONS.KHR_BINARY_GLTF; 1106 this.content = null; 1107 this.body = null; 1108 const headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH ); 1109 this.header = { 1110 magic: THREE.LoaderUtils.decodeText( new Uint8Array( data.slice( 0, 4 ) ) ), 1111 version: headerView.getUint32( 4, true ), 1112 length: headerView.getUint32( 8, true ) 1113 }; 1114 1115 if ( this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC ) { 1116 1117 throw new Error( 'THREE.GLTFLoader: Unsupported glTF-Binary header.' ); 1118 1119 } else if ( this.header.version < 2.0 ) { 1120 1121 throw new Error( 'THREE.GLTFLoader: Legacy binary file detected.' ); 1122 1123 } 1124 1125 const chunkContentsLength = this.header.length - BINARY_EXTENSION_HEADER_LENGTH; 1126 const chunkView = new DataView( data, BINARY_EXTENSION_HEADER_LENGTH ); 1127 let chunkIndex = 0; 1128 1129 while ( chunkIndex < chunkContentsLength ) { 1130
1131 const chunkLength = chunkView.getUint32( chunkIndex, true ); 1132 chunkIndex += 4; 1133 const chunkType = chunkView.getUint32( chunkIndex, true ); 1134 chunkIndex += 4; 1135 1136 if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON ) { 1137 1138 const contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength ); 1139 this.content = THREE.LoaderUtils.decodeText( contentArray ); 1140 1141 } else if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN ) { 1142 1143 const byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex; 1144 this.body = data.slice( byteOffset, byteOffset + chunkLength ); 1145 1146 } // Clients must ignore chunks with unknown types. 1147 1148 1149 chunkIndex += chunkLength; 1150 1151 } 1152 1153 if ( this.content === null ) { 1154 1155 throw new Error( 'THREE.GLTFLoader: JSON content not found.' ); 1156 1157 } 1158 1159 } 1160 1161 } 1162 /** 1163 * DRACO THREE.Mesh Compression Extension 1164 * 1165 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression 1166 */ 1167 1168 1169 class GLTFDracoMeshCompressionExtension { 1170 1171 constructor( json, dracoLoader ) { 1172 1173 if ( ! dracoLoader ) { 1174 1175 throw new Error( 'THREE.GLTFLoader: No DRACOLoader instance provided.' ); 1176 1177 } 1178 1179 this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION; 1180 this.json = json; 1181 this.dracoLoader = dracoLoader; 1182 this.dracoLoader.preload(); 1183 1184 } 1185 1186 decodePrimitive( primitive, parser ) { 1187 1188 const json = this.json; 1189 const dracoLoader = this.dracoLoader; 1190 const bufferViewIndex = primitive.extensions[ this.name ].bufferView; 1191 const gltfAttributeMap = primitive.extensions[ this.name ].attributes; 1192 const threeAttributeMap = {}; 1193 const attributeNormalizedMap = {}; 1194 const attributeTypeMap = {}; 1195 1196 for ( const attributeName in gltfAttributeMap ) { 1197 1198 const threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase(); 1199 threeAttributeMap[ threeAttributeName ] = gltfAttributeMap[ attributeName ]; 1200 1201 } 1202 1203 for ( const attributeName in primitive.attributes ) { 1204 1205 const threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase(); 1206 1207 if ( gltfAttributeMap[ attributeName ] !== undefined ) { 1208 1209 const accessorDef = json.accessors[ primitive.attributes[ attributeName ] ]; 1210 const componentType = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ]; 1211 attributeTypeMap[ threeAttributeName ] = componentType; 1212 attributeNormalizedMap[ threeAttributeName ] = accessorDef.normalized === true; 1213 1214 } 1215 1216 } 1217 1218 return parser.getDependency( 'bufferView', bufferViewIndex ).then( function ( bufferView ) { 1219 1220 return new Promise( function ( resolve ) { 1221 1222 dracoLoader.decodeDracoFile( bufferView, function ( geometry ) { 1223 1224 for ( const attributeName in geometry.attributes ) { 1225 1226 const attribute = geometry.attributes[ attributeName ]; 1227 const normalized = attributeNormalizedMap[ attributeName ]; 1228 if ( normalized !== undefined ) attribute.normalized = normalized; 1229 1230 } 1231 1232 resolve( geometry ); 1233 1234 }, threeAttributeMap, attributeTypeMap ); 1235 1236 } ); 1237 1238 } ); 1239 1240 } 1241 1242 } 1243 /** 1244 * THREE.Texture Transform Extension 1245 * 1246 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_transform 1247 */ 1248 1249 1250 class GLTFTextureTransformExtension { 1251 1252 constructor() { 1253 1254 this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM; 1255 1256 } 1257 1258 extendTexture( texture, transform ) { 1259 1260 if ( transform.texCoord !== undefined ) { 1261 1262 console.warn( 'THREE.GLTFLoader: Custom UV sets in "' + this.name + '" extension not yet supported.' ); 1263 1264 } 1265 1266 if ( transform.offset === undefined && transform.rotation === undefined && transform.scale === undefined ) { 1267 1268 // See https://github.com/mrdoob/three.js/issues/21819. 1269 return texture; 1270 1271 } 1272 1273 texture = texture.clone(); 1274 1275 if ( transform.offset !== undefined ) { 1276 1277 texture.offset.fromArray( transform.offset ); 1278 1279 } 1280 1281 if ( transform.rotation !== undefined ) { 1282 1283 texture.rotation = transform.rotation; 1284 1285 } 1286 1287 if ( transform.scale !== undefined ) { 1288 1289 texture.repeat.fromArray( transform.scale ); 1290 1291 } 1292 1293 texture.needsUpdate = true; 1294 return texture; 1295 1296 } 1297 1298 } 1299 /** 1300 * Specular-Glossiness Extension 1301 * 1302 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness 1303 */ 1304 1305 /** 1306 * A sub class of StandardMaterial with some of the functionality 1307 * changed via the `onBeforeCompile` callback 1308 * @pailhead 1309 */ 1310 1311 1312 class GLTFMeshStandardSGMaterial extends THREE.MeshStandardMaterial { 1313 1314 constructor( params ) { 1315 1316 super(); 1317 this.isGLTFSpecularGlossinessMaterial = true; //various chunks that need replacing 1318 1319 const specularMapParsFragmentChunk = [ '#ifdef USE_SPECULARMAP', ' uniform sampler2D specularMap;', '#endif' ].join( '\n' ); 1320 const glossinessMapParsFragmentChunk = [ '#ifdef USE_GLOSSINESSMAP', ' uniform sampler2D glossinessMap;', '#endif' ].join( '\n' ); 1321 const specularMapFragmentChunk = [ 'vec3 specularFactor = specular;', '#ifdef USE_SPECULARMAP', ' vec4 texelSpecular = texture2D( specularMap, vUv );', ' texelSpecular = sRGBToLinear( texelSpecular );', ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture', ' specularFactor *= texelSpecular.rgb;', '#endif' ].join( '\n' ); 1322 const glossinessMapFragmentChunk = [ 'float glossinessFactor = glossiness;', '#ifdef USE_GLOSSINESSMAP', ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );', ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture', ' glossinessFactor *= texelGlossiness.a;', '#endif' ].join( '\n' ); 1323 const lightPhysicalFragmentChunk = [ 'PhysicalMaterial material;', 'material.diffuseColor = diffuseColor.rgb * ( 1. - max( specularFactor.r, max( specularFactor.g, specularFactor.b ) ) );', 'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );', 'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );
1323', 'material.roughness = max( 1.0 - glossinessFactor, 0.0525 ); // 0.0525 corresponds to the base mip of a 256 cubemap.', 'material.roughness += geometryRoughness;', 'material.roughness = min( material.roughness, 1.0 );', 'material.specularColor = specularFactor;' ].join( '\n' ); 1324 const uniforms = { 1325 specular: { 1326 value: new THREE.Color().setHex( 0xffffff ) 1327 }, 1328 glossiness: { 1329 value: 1 1330 }, 1331 specularMap: { 1332 value: null 1333 }, 1334 glossinessMap: { 1335 value: null 1336 } 1337 }; 1338 this._extraUniforms = uniforms; 1339 1340 this.onBeforeCompile = function ( shader ) { 1341 1342 for ( const uniformName in uniforms ) { 1343 1344 shader.uniforms[ uniformName ] = uniforms[ uniformName ]; 1345 1346 } 1347 1348 shader.fragmentShader = shader.fragmentShader.replace( 'uniform float roughness;', 'uniform vec3 specular;' ).replace( 'uniform float metalness;', 'uniform float glossiness;' ).replace( '#include <roughnessmap_pars_fragment>', specularMapParsFragmentChunk ).replace( '#include <metalnessmap_pars_fragment>', glossinessMapParsFragmentChunk ).replace( '#include <roughnessmap_fragment>', specularMapFragmentChunk ).replace( '#include <metalnessmap_fragment>', glossinessMapFragmentChunk ).replace( '#include <lights_physical_fragment>', lightPhysicalFragmentChunk ); 1349 1350 }; 1351 1352 Object.defineProperties( this, { 1353 specular: { 1354 get: function () { 1355 1356 return uniforms.specular.value; 1357 1358 }, 1359 set: function ( v ) { 1360 1361 uniforms.specular.value = v; 1362 1363 } 1364 }, 1365 specularMap: { 1366 get: function () { 1367 1368 return uniforms.specularMap.value; 1369 1370 }, 1371 set: function ( v ) { 1372 1373 uniforms.specularMap.value = v; 1374 1375 if ( v ) { 1376 1377 this.defines.USE_SPECULARMAP = ''; // USE_UV is set by the renderer for specular maps 1378 1379 } else { 1380 1381 delete this.defines.USE_SPECULARMAP; 1382 1383 } 1384 1385 } 1386 }, 1387 glossiness: { 1388 get: function () { 1389 1390 return uniforms.glossiness.value; 1391 1392 }, 1393 set: function ( v ) { 1394 1395 uniforms.glossiness.value = v; 1396 1397 } 1398 }, 1399 glossinessMap: { 1400 get: function () { 1401 1402 return uniforms.glossinessMap.value; 1403 1404 }, 1405 set: function ( v ) { 1406 1407 uniforms.glossinessMap.value = v; 1408 1409 if ( v ) { 1410 1411 this.defines.USE_GLOSSINESSMAP = ''; 1412 this.defines.USE_UV = ''; 1413 1414 } else { 1415 1416 delete this.defines.USE_GLOSSINESSMAP; 1417 delete this.defines.USE_UV; 1418 1419 } 1420 1421 } 1422 } 1423 } ); 1424 delete this.metalness; 1425 delete this.roughness; 1426 delete this.metalnessMap; 1427 delete this.roughnessMap; 1428 this.setValues( params ); 1429 1430 } 1431 1432 copy( source ) { 1433 1434 super.copy( source ); 1435 this.specularMap = source.specularMap; 1436 this.specular.copy( source.specular ); 1437 this.glossinessMap = source.glossinessMap; 1438 this.glossiness = source.glossiness; 1439 delete this.metalness; 1440 delete this.roughness; 1441 delete this.metalnessMap; 1442 delete this.roughnessMap; 1443 return this; 1444 1445 } 1446 1447 } 1448 1449 class GLTFMaterialsPbrSpecularGlossinessExtension { 1450 1451 constructor() { 1452 1453 this.name = EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS; 1454 this.specularGlossinessParams = [ 'color', 'map', 'lightMap', 'lightMapIntensity', 'aoMap', 'aoMapIntensity', 'emissive', 'emissiveIntensity', 'emissiveMap', 'bumpMap', 'bumpScale', 'normalMap', 'normalMapType', 'displacementMap', 'displacementScale', 'displacementBias', 'specularMap', 'specular', 'glossinessMap', 'glossiness', 'alphaMap', 'envMap', 'envMapIntensity', 'refractionRatio' ]; 1455 1456 } 1457 1458 getMaterialType() { 1459 1460 return GLTFMeshStandardSGMaterial; 1461 1462 } 1463 1464 extendParams( materialParams, materialDef, parser ) { 1465 1466 const pbrSpecularGlossiness = materialDef.extensions[ this.name ]; 1467 materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 ); 1468 materialParams.opacity = 1.0; 1469 const pending = []; 1470 1471 if ( Array.isArray( pbrSpecularGlossiness.diffuseFactor ) ) { 1472 1473 const array = pbrSpecularGlossiness.diffuseFactor; 1474 materialParams.color.fromArray( array ); 1475 materialParams.opacity = array[ 3 ]; 1476 1477 } 1478 1479 if ( pbrSpecularGlossiness.diffuseTexture !== undefined ) { 1480 1481 pending.push( parser.assignTexture( materialParams, 'map', pbrSpecularGlossiness.diffuseTexture ) ); 1482 1483 } 1484 1485 materialParams.emissive = new THREE.Color( 0.0, 0.0, 0.0 ); 1486 materialParams.glossiness = pbrSpecularGlossiness.glossinessFactor !== undefined ? pbrSpecularGlossiness.glossinessFactor : 1.0; 1487 materialParams.specular = new THREE.Color( 1.0, 1.0, 1.0 ); 1488 1489 if ( Array.isArray( pbrSpecularGlossiness.specularFactor ) ) { 1490 1491 materialParams.specular.fromArray( pbrSpecularGlossiness.specularFactor ); 1492 1493 } 1494 1495 if ( pbrSpecularGlossiness.specularGlossinessTexture !== undefined ) { 1496 1497 const specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture; 1498 pending.push( parser.assignTexture( materialParams, 'glossinessMap', specGlossMapDef ) ); 1499 pending.push( parser.assignTexture( materialParams, 'specularMap', specGlossMapDef ) ); 1500 1501 } 1502 1503 return Promise.all( pending ); 1504 1505 } 1506 1507 createMaterial( materialParams ) { 1508 1509 const material = new GLTFMeshStandardSGMaterial( materialParams ); 1510 material.fog = true; 1511 material.color = materialParams.color; 1512 material.map = materialParams.map === undefined ? null : materialParams.map; 1513 material.lightMap = null; 1514 material.lightMapIntensity = 1.0; 1515 material.aoMap = materialParams.aoMap === undefined ? null : materialParams.aoMap; 1516 material.aoMapIntensity = 1.0; 1517 material.emissive = materialParams.emissive; 1518 material.emissiveIntensity = 1.0; 1519 material.emissiveMap = materialParams.emissiveMap === undefined ? null : materialParams.emissiveMap; 1520 material.bumpMap = materialParams.bumpMap === undefined ? null : materialParams.bumpMap; 1521 material.bumpScale = 1; 1522 material.normalMap = materialParams.normalMap === undefined ? null : materialParams.normalMap; 1523 material.normalMapType = THREE.TangentSpaceNormalMap; 1524 if ( materialParams.normalScale ) material.normalScale = materialParams.normalScale; 1525 material.displacementMap = null; 1526 material.displacementScale = 1; 1527 material.displacementBias = 0; 1528 material.specularMap = materialParams.specularMap === undefined ? null : materialParams.specularMap; 1529 material.specular = materialParams.specular; 1530 material.glossinessMap = materialParams.glossinessMap === undefined ? null : materialParams.glossinessMap; 1531 material.glossiness = materialParams.glossiness; 1532 material.alphaMap = null; 1533 material.envMap = materialParams.envMap === undefined ? null : materialParams.envMap; 1534 material.envMapIntensity = 1.0; 1535 material.refractionRatio = 0.98; 1536 return material; 1537 1538 } 1539 1540 } 1541 /** 1542 * THREE.Mesh Quantization Extension 1543 * 1544 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization 1545 */ 1546 1547 1548 class GLTFMeshQuantizationExtension { 1549 1550 constructor() { 1551
vendor: 6,172 bytes, lines 1552-1812
1552 this.name = EXTENSIONS.KHR_MESH_QUANTIZATION; 1553 1554 } 1555 1556 } 1557 /*********************************/ 1558 1559 /********** INTERPOLATION ********/ 1560 1561 /*********************************/ 1562 // Spline Interpolation 1563 // Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation 1564 1565 1566 class GLTFCubicSplineInterpolant extends THREE.Interpolant { 1567 1568 constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { 1569 1570 super( parameterPositions, sampleValues, sampleSize, resultBuffer ); 1571 1572 } 1573 1574 copySampleValue_( index ) { 1575 1576 // Copies a sample value to the result buffer. See description of glTF 1577 // CUBICSPLINE values layout in interpolate_() function below. 1578 const result = this.resultBuffer, 1579 values = this.sampleValues, 1580 valueSize = this.valueSize, 1581 offset = index * valueSize * 3 + valueSize; 1582 1583 for ( let i = 0; i !== valueSize; i ++ ) { 1584 1585 result[ i ] = values[ offset + i ]; 1586 1587 } 1588 1589 return result; 1590 1591 } 1592 1593 } 1594 1595 GLTFCubicSplineInterpolant.prototype.beforeStart_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_; 1596 GLTFCubicSplineInterpolant.prototype.afterEnd_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_; 1597 1598 GLTFCubicSplineInterpolant.prototype.interpolate_ = function ( i1, t0, t, t1 ) { 1599 1600 const result = this.resultBuffer; 1601 const values = this.sampleValues; 1602 const stride = this.valueSize; 1603 const stride2 = stride * 2; 1604 const stride3 = stride * 3; 1605 const td = t1 - t0; 1606 const p = ( t - t0 ) / td; 1607 const pp = p * p; 1608 const ppp = pp * p; 1609 const offset1 = i1 * stride3; 1610 const offset0 = offset1 - stride3; 1611 const s2 = - 2 * ppp + 3 * pp; 1612 const s3 = ppp - pp; 1613 const s0 = 1 - s2; 1614 const s1 = s3 - pp + p; // Layout of keyframe output values for CUBICSPLINE animations: 1615 // [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ] 1616 1617 for ( let i = 0; i !== stride; i ++ ) { 1618 1619 const p0 = values[ offset0 + i + stride ]; // splineVertex_k 1620 1621 const m0 = values[ offset0 + i + stride2 ] * td; // outTangent_k * (t_k+1 - t_k) 1622 1623 const p1 = values[ offset1 + i + stride ]; // splineVertex_k+1 1624 1625 const m1 = values[ offset1 + i ] * td; // inTangent_k+1 * (t_k+1 - t_k) 1626 1627 result[ i ] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1; 1628 1629 } 1630 1631 return result; 1632 1633 }; 1634 1635 const _q = new THREE.Quaternion(); 1636 1637 class GLTFCubicSplineQuaternionInterpolant extends GLTFCubicSplineInterpolant { 1638 1639 interpolate_( i1, t0, t, t1 ) { 1640 1641 const result = super.interpolate_( i1, t0, t, t1 ); 1642 1643 _q.fromArray( result ).normalize().toArray( result ); 1644 1645 return result; 1646 1647 } 1648 1649 } 1650 /*********************************/ 1651 1652 /********** INTERNALS ************/ 1653 1654 /*********************************/ 1655 1656 /* CONSTANTS */ 1657 1658 1659 const WEBGL_CONSTANTS = { 1660 FLOAT: 5126, 1661 //FLOAT_MAT2: 35674, 1662 FLOAT_MAT3: 35675, 1663 FLOAT_MAT4: 35676, 1664 FLOAT_VEC2: 35664, 1665 FLOAT_VEC3: 35665, 1666 FLOAT_VEC4: 35666, 1667 LINEAR: 9729, 1668 REPEAT: 10497, 1669 SAMPLER_2D: 35678, 1670 POINTS: 0, 1671 LINES: 1, 1672 LINE_LOOP: 2, 1673 LINE_STRIP: 3, 1674 TRIANGLES: 4, 1675 TRIANGLE_STRIP: 5, 1676 TRIANGLE_FAN: 6, 1677 UNSIGNED_BYTE: 5121, 1678 UNSIGNED_SHORT: 5123 1679 }; 1680 const WEBGL_COMPONENT_TYPES = { 1681 5120: Int8Array, 1682 5121: Uint8Array, 1683 5122: Int16Array, 1684 5123: Uint16Array, 1685 5125: Uint32Array, 1686 5126: Float32Array 1687 }; 1688 const WEBGL_FILTERS = { 1689 9728: THREE.NearestFilter, 1690 9729: THREE.LinearFilter, 1691 9984: THREE.NearestMipmapNearestFilter, 1692 9985: THREE.LinearMipmapNearestFilter, 1693 9986: THREE.NearestMipmapLinearFilter, 1694 9987: THREE.LinearMipmapLinearFilter 1695 }; 1696 const WEBGL_WRAPPINGS = { 1697 33071: THREE.ClampToEdgeWrapping, 1698 33648: THREE.MirroredRepeatWrapping, 1699 10497: THREE.RepeatWrapping 1700 }; 1701 const WEBGL_TYPE_SIZES = { 1702 'SCALAR': 1, 1703 'VEC2': 2, 1704 'VEC3': 3, 1705 'VEC4': 4, 1706 'MAT2': 4, 1707 'MAT3': 9, 1708 'MAT4': 16 1709 }; 1710 const ATTRIBUTES = { 1711 POSITION: 'position', 1712 NORMAL: 'normal', 1713 TANGENT: 'tangent', 1714 TEXCOORD_0: 'uv', 1715 TEXCOORD_1: 'uv2', 1716 COLOR_0: 'color', 1717 WEIGHTS_0: 'skinWeight', 1718 JOINTS_0: 'skinIndex' 1719 }; 1720 const PATH_PROPERTIES = { 1721 scale: 'scale', 1722 translation: 'position', 1723 rotation: 'quaternion', 1724 weights: 'morphTargetInfluences' 1725 }; 1726 const INTERPOLATION = { 1727 CUBICSPLINE: undefined, 1728 // We use a custom interpolant (GLTFCubicSplineInterpolation) for CUBICSPLINE tracks. Each 1729 // keyframe track will be initialized with a default interpolation type, then modified. 1730 LINEAR: THREE.InterpolateLinear, 1731 STEP: THREE.InterpolateDiscrete 1732 }; 1733 const ALPHA_MODES = { 1734 OPAQUE: 'OPAQUE', 1735 MASK: 'MASK', 1736 BLEND: 'BLEND' 1737 }; 1738 /** 1739 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material 1740 */ 1741 1742 function createDefaultMaterial( cache ) { 1743 1744 if ( cache[ 'DefaultMaterial' ] === undefined ) { 1745 1746 cache[ 'DefaultMaterial' ] = new THREE.MeshStandardMaterial( { 1747 color: 0xFFFFFF, 1748 emissive: 0x000000, 1749 metalness: 1, 1750 roughness: 1, 1751 transparent: false, 1752 depthTest: true, 1753 side: THREE.FrontSide 1754 } ); 1755 1756 } 1757 1758 return cache[ 'DefaultMaterial' ]; 1759 1760 } 1761 1762 function addUnknownExtensionsToUserData( knownExtensions, object, objectDef ) { 1763 1764 // Add unknown glTF extensions to an object's userData. 1765 for ( const name in objectDef.extensions ) { 1766 1767 if ( knownExtensions[ name ] === undefined ) { 1768 1769 object.userData.gltfExtensions = object.userData.gltfExtensions || {}; 1770 object.userData.gltfExtensions[ name ] = objectDef.extensions[ name ]; 1771 1772 } 1773 1774 } 1775 1776 } 1777 /** 1778 * @param {Object3D|Material|BufferGeometry} object 1779 * @param {GLTF.definition} gltfDef 1780 */ 1781 1782 1783 function assignExtrasToUserData( object, gltfDef ) { 1784 1785 if ( gltfDef.extras !== undefined ) { 1786 1787 if ( typeof gltfDef.extras === 'object' ) { 1788 1789 Object.assign( object.userData, gltfDef.extras ); 1790 1791 } else { 1792 1793 console.warn( 'THREE.GLTFLoader: Ignoring primitive type .extras, ' + gltfDef.extras ); 1794 1795 } 1796 1797 } 1798 1799 } 1800 /** 1801 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets 1802 * 1803 * @param {BufferGeometry} geometry 1804 * @param {Array<GLTF.Target>} targets 1805 * @param {GLTFParser} parser 1806 * @return {Promise<BufferGeometry>} 1807 */ 1808 1809 1810 function addMorphTargets( geometry, targets, parser ) { 1811 1812 let hasMorphPosition = false;
1813 let hasMorphNormal = false; 1814 1815 for ( let i = 0, il = targets.length; i < il; i ++ ) { 1816 1817 const target = targets[ i ]; 1818 if ( target.POSITION !== undefined ) hasMorphPosition = true; 1819 if ( target.NORMAL !== undefined ) hasMorphNormal = true; 1820 if ( hasMorphPosition && hasMorphNormal ) break; 1821 1822 } 1823 1824 if ( ! hasMorphPosition && ! hasMorphNormal ) return Promise.resolve( geometry ); 1825 const pendingPositionAccessors = []; 1826 const pendingNormalAccessors = []; 1827 1828 for ( let i = 0, il = targets.length; i < il; i ++ ) { 1829 1830 const target = targets[ i ]; 1831 1832 if ( hasMorphPosition ) { 1833 1834 const pendingAccessor = target.POSITION !== undefined ? parser.getDependency( 'accessor', target.POSITION ) : geometry.attributes.position; 1835 pendingPositionAccessors.push( pendingAccessor ); 1836 1837 } 1838 1839 if ( hasMorphNormal ) { 1840 1841 const pendingAccessor = target.NORMAL !== undefined ? parser.getDependency( 'accessor', target.NORMAL ) : geometry.attributes.normal; 1842 pendingNormalAccessors.push( pendingAccessor ); 1843 1844 } 1845 1846 } 1847 1848 return Promise.all( [ Promise.all( pendingPositionAccessors ), Promise.all( pendingNormalAccessors ) ] ).then( function ( accessors ) { 1849 1850 const morphPositions = accessors[ 0 ]; 1851 const morphNormals = accessors[ 1 ]; 1852 if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions; 1853 if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals; 1854 geometry.morphTargetsRelative = true; 1855 return geometry; 1856 1857 } ); 1858 1859 } 1860 /** 1861 * @param {Mesh} mesh 1862 * @param {GLTF.Mesh} meshDef 1863 */ 1864 1865 1866 function updateMorphTargets( mesh, meshDef ) { 1867 1868 mesh.updateMorphTargets(); 1869 1870 if ( meshDef.weights !== undefined ) { 1871 1872 for ( let i = 0, il = meshDef.weights.length; i < il; i ++ ) { 1873 1874 mesh.morphTargetInfluences[ i ] = meshDef.weights[ i ]; 1875 1876 } 1877 1878 } // .extras has user-defined data, so check that .extras.targetNames is an array. 1879 1880 1881 if ( meshDef.extras && Array.isArray( meshDef.extras.targetNames ) ) { 1882 1883 const targetNames = meshDef.extras.targetNames; 1884 1885 if ( mesh.morphTargetInfluences.length === targetNames.length ) { 1886 1887 mesh.morphTargetDictionary = {}; 1888 1889 for ( let i = 0, il = targetNames.length; i < il; i ++ ) { 1890 1891 mesh.morphTargetDictionary[ targetNames[ i ] ] = i; 1892 1893 } 1894 1895 } else { 1896 1897 console.warn( 'THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.' ); 1898 1899 } 1900 1901 } 1902 1903 } 1904 1905 function createPrimitiveKey( primitiveDef ) { 1906 1907 const dracoExtension = primitiveDef.extensions && primitiveDef.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ]; 1908 let geometryKey; 1909 1910 if ( dracoExtension ) { 1911 1912 geometryKey = 'draco:' + dracoExtension.bufferView + ':' + dracoExtension.indices + ':' + createAttributesKey( dracoExtension.attributes ); 1913 1914 } else { 1915 1916 geometryKey = primitiveDef.indices + ':' + createAttributesKey( primitiveDef.attributes ) + ':' + primitiveDef.mode; 1917 1918 } 1919 1920 return geometryKey; 1921 1922 } 1923 1924 function createAttributesKey( attributes ) { 1925 1926 let attributesKey = ''; 1927 const keys = Object.keys( attributes ).sort(); 1928 1929 for ( let i = 0, il = keys.length; i < il; i ++ ) { 1930 1931 attributesKey += keys[ i ] + ':' + attributes[ keys[ i ] ] + ';'; 1932 1933 } 1934 1935 return attributesKey; 1936 1937 } 1938 1939 function getNormalizedComponentScale( constructor ) { 1940 1941 // Reference: 1942 // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization#encoding-quantized-data 1943 switch ( constructor ) { 1944 1945 case Int8Array: 1946 return 1 / 127; 1947 1948 case Uint8Array: 1949 return 1 / 255; 1950 1951 case Int16Array: 1952 return 1 / 32767; 1953 1954 case Uint16Array: 1955 return 1 / 65535; 1956 1957 default: 1958 throw new Error( 'THREE.GLTFLoader: Unsupported normalized accessor component type.' ); 1959 1960 } 1961 1962 } 1963 /* GLTF PARSER */ 1964 1965 1966 class GLTFParser { 1967 1968 constructor( json = {}, options = {} ) { 1969 1970 this.json = json; 1971 this.extensions = {}; 1972 this.plugins = {}; 1973 this.options = options; // loader object cache 1974 1975 this.cache = new GLTFRegistry(); // associations between Three.js objects and glTF elements 1976 1977 this.associations = new Map(); // THREE.BufferGeometry caching 1978 1979 this.primitiveCache = {}; // THREE.Object3D instance caches 1980 1981 this.meshCache = { 1982 refs: {}, 1983 uses: {} 1984 }; 1985 this.cameraCache = { 1986 refs: {}, 1987 uses: {} 1988 }; 1989 this.lightCache = { 1990 refs: {}, 1991 uses: {} 1992 }; 1993 this.textureCache = {}; // Track node names, to ensure no duplicates 1994 1995 this.nodeNamesUsed = {}; // Use an THREE.ImageBitmapLoader if imageBitmaps are supported. Moves much of the 1996 // expensive work of uploading a texture to the GPU off the main thread. 1997 1998 if ( typeof createImageBitmap !== 'undefined' && /Firefox/.test( navigator.userAgent ) === false ) { 1999 2000 this.textureLoader = new THREE.ImageBitmapLoader( this.options.manager ); 2001 2002 } else { 2003 2004 this.textureLoader = new THREE.TextureLoader( this.options.manager ); 2005 2006 } 2007 2008 this.textureLoader.setCrossOrigin( this.options.crossOrigin ); 2009 this.textureLoader.setRequestHeader( this.options.requestHeader ); 2010 this.fileLoader = new THREE.FileLoader( this.options.manager ); 2011 this.fileLoader.setResponseType( 'arraybuffer' ); 2012 2013 if ( this.options.crossOrigin === 'use-credentials' ) { 2014 2015 this.fileLoader.setWithCredentials( true ); 2016 2017 } 2018 2019 } 2020 2021 setExtensions( extensions ) { 2022 2023 this.extensions = extensions; 2024 2025 } 2026 2027 setPlugins( plugins ) { 2028 2029 this.plugins = plugins; 2030 2031 } 2032 2033 parse( onLoad, onError ) { 2034 2035 const parser = this; 2036 const json = this.json; 2037 const extensions = this.extensions; // Clear the loader cache 2038 2039 this.cache.removeAll(); // Mark the special nodes/meshes in json for efficient parse 2040 2041 this._invokeAll( function ( ext ) { 2042 2043 return ext._markDefs && ext._markDefs(); 2044 2045 } ); 2046 2047 Promise.all( this._invokeAll( function ( ext ) { 2048 2049 return ext.beforeRoot && ext.beforeRoot(); 2050 2051 } ) ).then( function () { 2052 2053 return Promise.all( [ parser.getDependencies( 'scene' ), parser.getDependencies( 'animation' ), parser.getDependencies( 'camera' ) ] ); 2054 2055 } ).then( function ( dependencies ) { 2056 2057 const result = {
vendor: 5,634 bytes, lines 2058-2309
2058 scene: dependencies[ 0 ][ json.scene || 0 ], 2059 scenes: dependencies[ 0 ], 2060 animations: dependencies[ 1 ], 2061 cameras: dependencies[ 2 ], 2062 asset: json.asset, 2063 parser: parser, 2064 userData: {} 2065 }; 2066 addUnknownExtensionsToUserData( extensions, result, json ); 2067 assignExtrasToUserData( result, json ); 2068 Promise.all( parser._invokeAll( function ( ext ) { 2069 2070 return ext.afterRoot && ext.afterRoot( result ); 2071 2072 } ) ).then( function () { 2073 2074 onLoad( result ); 2075 2076 } ); 2077 2078 } ).catch( onError ); 2079 2080 } 2081 /** 2082 * Marks the special nodes/meshes in json for efficient parse. 2083 */ 2084 2085 2086 _markDefs() { 2087 2088 const nodeDefs = this.json.nodes || []; 2089 const skinDefs = this.json.skins || []; 2090 const meshDefs = this.json.meshes || []; // Nothing in the node definition indicates whether it is a THREE.Bone or an 2091 // THREE.Object3D. Use the skins' joint references to mark bones. 2092 2093 for ( let skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex ++ ) { 2094 2095 const joints = skinDefs[ skinIndex ].joints; 2096 2097 for ( let i = 0, il = joints.length; i < il; i ++ ) { 2098 2099 nodeDefs[ joints[ i ] ].isBone = true; 2100 2101 } 2102 2103 } // Iterate over all nodes, marking references to shared resources, 2104 // as well as skeleton joints. 2105 2106 2107 for ( let nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex ++ ) { 2108 2109 const nodeDef = nodeDefs[ nodeIndex ]; 2110 2111 if ( nodeDef.mesh !== undefined ) { 2112 2113 this._addNodeRef( this.meshCache, nodeDef.mesh ); // Nothing in the mesh definition indicates whether it is 2114 // a THREE.SkinnedMesh or THREE.Mesh. Use the node's mesh reference 2115 // to mark THREE.SkinnedMesh if node has skin. 2116 2117 2118 if ( nodeDef.skin !== undefined ) { 2119 2120 meshDefs[ nodeDef.mesh ].isSkinnedMesh = true; 2121 2122 } 2123 2124 } 2125 2126 if ( nodeDef.camera !== undefined ) { 2127 2128 this._addNodeRef( this.cameraCache, nodeDef.camera ); 2129 2130 } 2131 2132 } 2133 2134 } 2135 /** 2136 * Counts references to shared node / THREE.Object3D resources. These resources 2137 * can be reused, or "instantiated", at multiple nodes in the scene 2138 * hierarchy. THREE.Mesh, Camera, and Light instances are instantiated and must 2139 * be marked. Non-scenegraph resources (like Materials, Geometries, and 2140 * Textures) can be reused directly and are not marked here. 2141 * 2142 * Example: CesiumMilkTruck sample model reuses "Wheel" meshes. 2143 */ 2144 2145 2146 _addNodeRef( cache, index ) { 2147 2148 if ( index === undefined ) return; 2149 2150 if ( cache.refs[ index ] === undefined ) { 2151 2152 cache.refs[ index ] = cache.uses[ index ] = 0; 2153 2154 } 2155 2156 cache.refs[ index ] ++; 2157 2158 } 2159 /** Returns a reference to a shared resource, cloning it if necessary. */ 2160 2161 2162 _getNodeRef( cache, index, object ) { 2163 2164 if ( cache.refs[ index ] <= 1 ) return object; 2165 const ref = object.clone(); // Propagates mappings to the cloned object, prevents mappings on the 2166 // original object from being lost. 2167 2168 const updateMappings = ( original, clone ) => { 2169 2170 const mappings = this.associations.get( original ); 2171 2172 if ( mappings != null ) { 2173 2174 this.associations.set( clone, mappings ); 2175 2176 } 2177 2178 for ( const [ i, child ] of original.children.entries() ) { 2179 2180 updateMappings( child, clone.children[ i ] ); 2181 2182 } 2183 2184 }; 2185 2186 updateMappings( object, ref ); 2187 ref.name += '_instance_' + cache.uses[ index ] ++; 2188 return ref; 2189 2190 } 2191 2192 _invokeOne( func ) { 2193 2194 const extensions = Object.values( this.plugins ); 2195 extensions.push( this ); 2196 2197 for ( let i = 0; i < extensions.length; i ++ ) { 2198 2199 const result = func( extensions[ i ] ); 2200 if ( result ) return result; 2201 2202 } 2203 2204 return null; 2205 2206 } 2207 2208 _invokeAll( func ) { 2209 2210 const extensions = Object.values( this.plugins ); 2211 extensions.unshift( this ); 2212 const pending = []; 2213 2214 for ( let i = 0; i < extensions.length; i ++ ) { 2215 2216 const result = func( extensions[ i ] ); 2217 if ( result ) pending.push( result ); 2218 2219 } 2220 2221 return pending; 2222 2223 } 2224 /** 2225 * Requests the specified dependency asynchronously, with caching. 2226 * @param {string} type 2227 * @param {number} index 2228 * @return {Promise<Object3D|Material|THREE.Texture|AnimationClip|ArrayBuffer|Object>} 2229 */ 2230 2231 2232 getDependency( type, index ) { 2233 2234 const cacheKey = type + ':' + index; 2235 let dependency = this.cache.get( cacheKey ); 2236 2237 if ( ! dependency ) { 2238 2239 switch ( type ) { 2240 2241 case 'scene': 2242 dependency = this.loadScene( index ); 2243 break; 2244 2245 case 'node': 2246 dependency = this.loadNode( index ); 2247 break; 2248 2249 case 'mesh': 2250 dependency = this._invokeOne( function ( ext ) { 2251 2252 return ext.loadMesh && ext.loadMesh( index ); 2253 2254 } ); 2255 break; 2256 2257 case 'accessor': 2258 dependency = this.loadAccessor( index ); 2259 break; 2260 2261 case 'bufferView': 2262 dependency = this._invokeOne( function ( ext ) { 2263 2264 return ext.loadBufferView && ext.loadBufferView( index ); 2265 2266 } ); 2267 break; 2268 2269 case 'buffer': 2270 dependency = this.loadBuffer( index ); 2271 break; 2272 2273 case 'material': 2274 dependency = this._invokeOne( function ( ext ) { 2275 2276 return ext.loadMaterial && ext.loadMaterial( index ); 2277 2278 } ); 2279 break; 2280 2281 case 'texture': 2282 dependency = this._invokeOne( function ( ext ) { 2283 2284 return ext.loadTexture && ext.loadTexture( index ); 2285 2286 } ); 2287 break; 2288 2289 case 'skin': 2290 dependency = this.loadSkin( index ); 2291 break; 2292 2293 case 'animation': 2294 dependency = this.loadAnimation( index ); 2295 break; 2296 2297 case 'camera': 2298 dependency = this.loadCamera( index ); 2299 break; 2300 2301 default: 2302 throw new Error( 'Unknown type: ' + type ); 2303 2304 } 2305 2306 this.cache.add( cacheKey, dependency ); 2307 2308 } 2309
vendor: 9,474 bytes, lines 2310-2616
2310 return dependency; 2311 2312 } 2313 /** 2314 * Requests all dependencies of the specified type asynchronously, with caching. 2315 * @param {string} type 2316 * @return {Promise<Array<Object>>} 2317 */ 2318 2319 2320 getDependencies( type ) { 2321 2322 let dependencies = this.cache.get( type ); 2323 2324 if ( ! dependencies ) { 2325 2326 const parser = this; 2327 const defs = this.json[ type + ( type === 'mesh' ? 'es' : 's' ) ] || []; 2328 dependencies = Promise.all( defs.map( function ( def, index ) { 2329 2330 return parser.getDependency( type, index ); 2331 2332 } ) ); 2333 this.cache.add( type, dependencies ); 2334 2335 } 2336 2337 return dependencies; 2338 2339 } 2340 /** 2341 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views 2342 * @param {number} bufferIndex 2343 * @return {Promise<ArrayBuffer>} 2344 */ 2345 2346 2347 loadBuffer( bufferIndex ) { 2348 2349 const bufferDef = this.json.buffers[ bufferIndex ]; 2350 const loader = this.fileLoader; 2351 2352 if ( bufferDef.type && bufferDef.type !== 'arraybuffer' ) { 2353 2354 throw new Error( 'THREE.GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.' ); 2355 2356 } // If present, GLB container is required to be the first buffer. 2357 2358 2359 if ( bufferDef.uri === undefined && bufferIndex === 0 ) { 2360 2361 return Promise.resolve( this.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body ); 2362 2363 } 2364 2365 const options = this.options; 2366 return new Promise( function ( resolve, reject ) { 2367 2368 loader.load( THREE.LoaderUtils.resolveURL( bufferDef.uri, options.path ), resolve, undefined, function () { 2369 2370 reject( new Error( 'THREE.GLTFLoader: Failed to load buffer "' + bufferDef.uri + '".' ) ); 2371 2372 } ); 2373 2374 } ); 2375 2376 } 2377 /** 2378 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views 2379 * @param {number} bufferViewIndex 2380 * @return {Promise<ArrayBuffer>} 2381 */ 2382 2383 2384 loadBufferView( bufferViewIndex ) { 2385 2386 const bufferViewDef = this.json.bufferViews[ bufferViewIndex ]; 2387 return this.getDependency( 'buffer', bufferViewDef.buffer ).then( function ( buffer ) { 2388 2389 const byteLength = bufferViewDef.byteLength || 0; 2390 const byteOffset = bufferViewDef.byteOffset || 0; 2391 return buffer.slice( byteOffset, byteOffset + byteLength ); 2392 2393 } ); 2394 2395 } 2396 /** 2397 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors 2398 * @param {number} accessorIndex 2399 * @return {Promise<BufferAttribute|InterleavedBufferAttribute>} 2400 */ 2401 2402 2403 loadAccessor( accessorIndex ) { 2404 2405 const parser = this; 2406 const json = this.json; 2407 const accessorDef = this.json.accessors[ accessorIndex ]; 2408 2409 if ( accessorDef.bufferView === undefined && accessorDef.sparse === undefined ) { 2410 2411 // Ignore empty accessors, which may be used to declare runtime 2412 // information about attributes coming from another source (e.g. Draco 2413 // compression extension). 2414 return Promise.resolve( null ); 2415 2416 } 2417 2418 const pendingBufferViews = []; 2419 2420 if ( accessorDef.bufferView !== undefined ) { 2421 2422 pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.bufferView ) ); 2423 2424 } else { 2425 2426 pendingBufferViews.push( null ); 2427 2428 } 2429 2430 if ( accessorDef.sparse !== undefined ) { 2431 2432 pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.indices.bufferView ) ); 2433 pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.values.bufferView ) ); 2434 2435 } 2436 2437 return Promise.all( pendingBufferViews ).then( function ( bufferViews ) { 2438 2439 const bufferView = bufferViews[ 0 ]; 2440 const itemSize = WEBGL_TYPE_SIZES[ accessorDef.type ]; 2441 const TypedArray = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ]; // For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12. 2442 2443 const elementBytes = TypedArray.BYTES_PER_ELEMENT; 2444 const itemBytes = elementBytes * itemSize; 2445 const byteOffset = accessorDef.byteOffset || 0; 2446 const byteStride = accessorDef.bufferView !== undefined ? json.bufferViews[ accessorDef.bufferView ].byteStride : undefined; 2447 const normalized = accessorDef.normalized === true; 2448 let array, bufferAttribute; // The buffer is not interleaved if the stride is the item size in bytes. 2449 2450 if ( byteStride && byteStride !== itemBytes ) { 2451 2452 // Each "slice" of the buffer, as defined by 'count' elements of 'byteStride' bytes, gets its own THREE.InterleavedBuffer 2453 // This makes sure that IBA.count reflects accessor.count properly 2454 const ibSlice = Math.floor( byteOffset / byteStride ); 2455 const ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType + ':' + ibSlice + ':' + accessorDef.count; 2456 let ib = parser.cache.get( ibCacheKey ); 2457 2458 if ( ! ib ) { 2459 2460 array = new TypedArray( bufferView, ibSlice * byteStride, accessorDef.count * byteStride / elementBytes ); // Integer parameters to IB/IBA are in array elements, not bytes. 2461 2462 ib = new THREE.InterleavedBuffer( array, byteStride / elementBytes ); 2463 parser.cache.add( ibCacheKey, ib ); 2464 2465 } 2466 2467 bufferAttribute = new THREE.InterleavedBufferAttribute( ib, itemSize, byteOffset % byteStride / elementBytes, normalized ); 2468 2469 } else { 2470 2471 if ( bufferView === null ) { 2472 2473 array = new TypedArray( accessorDef.count * itemSize ); 2474 2475 } else { 2476 2477 array = new TypedArray( bufferView, byteOffset, accessorDef.count * itemSize ); 2478 2479 } 2480 2481 bufferAttribute = new THREE.BufferAttribute( array, itemSize, normalized ); 2482 2483 } // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessors 2484 2485 2486 if ( accessorDef.sparse !== undefined ) { 2487 2488 const itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR; 2489 const TypedArrayIndices = WEBGL_COMPONENT_TYPES[ accessorDef.sparse.indices.componentType ]; 2490 const byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0; 2491 const byteOffsetValues = accessorDef.sparse.values.byteOffset || 0; 2492 const sparseIndices = new TypedArrayIndices( bufferViews[ 1 ], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices ); 2493 const sparseValues = new TypedArray( bufferViews[ 2 ], byteOffsetValues, accessorDef.sparse.count * itemSize ); 2494 2495 if ( bufferView !== null ) { 2496 2497 // Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes. 2498 bufferAttribute = new THREE.BufferAttribute( bufferAttribute.array.slice(), bufferAttribute.itemSize, bufferAttribute.normalized ); 2499 2500 } 2501 2502 for ( let i = 0, il = sparseIndices.length; i < il; i ++ ) { 2503 2504 const index = sparseIndices[ i ]; 2505 bufferAttribute.setX( index, sparseValues[ i * itemSize ] ); 2506 if ( itemSize >= 2 ) bufferAttribute.setY( index, sparseValues[ i * itemSize + 1 ] ); 2507 if ( itemSize >= 3 ) bufferAttribute.setZ( index, sparseValues[ i * itemSize + 2 ] ); 2508 if ( itemSize >= 4 ) bufferAttribute.setW( index, sparseValues[ i * itemSize + 3 ] ); 2509 if ( itemSize >= 5 ) throw new Error( 'THREE.GLTFLoader: Unsupported itemSize in sparse THREE.BufferAttribute.' ); 2510 2511 } 2512 2513 } 2514 2515 return bufferAttribute; 2516 2517 } ); 2518 2519 } 2520 /** 2521 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures 2522 * @param {number} textureIndex 2523 * @return {Promise<THREE.Texture>} 2524 */ 2525 2526 2527 loadTexture( textureIndex ) { 2528 2529 const json = this.json; 2530 const options = this.options; 2531 const textureDef = json.textures[ textureIndex ]; 2532 const source = json.images[ textureDef.source ]; 2533 let loader = this.textureLoader; 2534 2535 if ( source.uri ) { 2536 2537 const handler = options.manager.getHandler( source.uri ); 2538 if ( handler !== null ) loader = handler; 2539 2540 } 2541 2542 return this.loadTextureImage( textureIndex, source, loader ); 2543 2544 } 2545 2546 loadTextureImage( textureIndex, source, loader ) { 2547 2548 const parser = this; 2549 const json = this.json; 2550 const options = this.options; 2551 const textureDef = json.textures[ textureIndex ]; 2552 const cacheKey = ( source.uri || source.bufferView ) + ':' + textureDef.sampler; 2553 2554 if ( this.textureCache[ cacheKey ] ) { 2555 2556 // See https://github.com/mrdoob/three.js/issues/21559. 2557 return this.textureCache[ cacheKey ]; 2558 2559 } 2560 2561 const URL = self.URL || self.webkitURL; 2562 let sourceURI = source.uri || ''; 2563 let isObjectURL = false; 2564 2565 if ( source.bufferView !== undefined ) { 2566 2567 // Load binary image data from bufferView, if provided. 2568 sourceURI = parser.getDependency( 'bufferView', source.bufferView ).then( function ( bufferView ) { 2569 2570 isObjectURL = true; 2571 const blob = new Blob( [ bufferView ], { 2572 type: source.mimeType 2573 } ); 2574 sourceURI = URL.createObjectURL( blob ); 2575 return sourceURI; 2576 2577 } ); 2578 2579 } else if ( source.uri === undefined ) { 2580 2581 throw new Error( 'THREE.GLTFLoader: Image ' + textureIndex + ' is missing URI and bufferView' ); 2582 2583 } 2584 2585 const promise = Promise.resolve( sourceURI ).then( function ( sourceURI ) { 2586 2587 return new Promise( function ( resolve, reject ) { 2588 2589 let onLoad = resolve; 2590 2591 if ( loader.isImageBitmapLoader === true ) { 2592 2593 onLoad = function ( imageBitmap ) { 2594 2595 const texture = new THREE.Texture( imageBitmap ); 2596 texture.needsUpdate = true; 2597 resolve( texture ); 2598 2599 }; 2600 2601 } 2602 2603 loader.load( THREE.LoaderUtils.resolveURL( sourceURI, options.path ), onLoad, undefined, reject ); 2604 2605 } ); 2606 2607 } ).then( function ( texture ) { 2608 2609 // Clean up resources and configure THREE.Texture. 2610 if ( isObjectURL === true ) { 2611 2612 URL.revokeObjectURL( sourceURI ); 2613 2614 } 2615 2616 texture.flipY = false;
2617 if ( textureDef.name ) texture.name = textureDef.name; 2618 const samplers = json.samplers || {}; 2619 const sampler = samplers[ textureDef.sampler ] || {}; 2620 texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || THREE.LinearFilter; 2621 texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || THREE.LinearMipmapLinearFilter; 2622 texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || THREE.RepeatWrapping; 2623 texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || THREE.RepeatWrapping; 2624 parser.associations.set( texture, { 2625 textures: textureIndex 2626 } ); 2627 return texture; 2628 2629 } ).catch( function () { 2630 2631 console.error( 'THREE.GLTFLoader: Couldn\'t load texture', sourceURI ); 2632 return null; 2633 2634 } ); 2635 this.textureCache[ cacheKey ] = promise; 2636 return promise; 2637 2638 } 2639 /** 2640 * Asynchronously assigns a texture to the given material parameters. 2641 * @param {Object} materialParams 2642 * @param {string} mapName 2643 * @param {Object} mapDef 2644 * @return {Promise<Texture>} 2645 */ 2646 2647 2648 assignTexture( materialParams, mapName, mapDef ) { 2649 2650 const parser = this; 2651 return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) { 2652 2653 // Materials sample aoMap from UV set 1 and other maps from UV set 0 - this can't be configured 2654 // However, we will copy UV set 0 to UV set 1 on demand for aoMap 2655 if ( mapDef.texCoord !== undefined && mapDef.texCoord != 0 && ! ( mapName === 'aoMap' && mapDef.texCoord == 1 ) ) { 2656 2657 console.warn( 'THREE.GLTFLoader: Custom UV set ' + mapDef.texCoord + ' for texture ' + mapName + ' not yet supported.' ); 2658 2659 } 2660 2661 if ( parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] ) { 2662 2663 const transform = mapDef.extensions !== undefined ? mapDef.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] : undefined; 2664 2665 if ( transform ) { 2666 2667 const gltfReference = parser.associations.get( texture ); 2668 texture = parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ].extendTexture( texture, transform ); 2669 parser.associations.set( texture, gltfReference ); 2670 2671 } 2672 2673 } 2674 2675 materialParams[ mapName ] = texture; 2676 return texture; 2677 2678 } ); 2679 2680 } 2681 /** 2682 * Assigns final material to a THREE.Mesh, THREE.Line, or THREE.Points instance. The instance 2683 * already has a material (generated from the glTF material options alone) 2684 * but reuse of the same glTF material may require multiple threejs materials 2685 * to accommodate different primitive types, defines, etc. New materials will 2686 * be created if necessary, and reused from a cache. 2687 * @param {Object3D} mesh THREE.Mesh, THREE.Line, or THREE.Points instance. 2688 */ 2689 2690 2691 assignFinalMaterial( mesh ) { 2692 2693 const geometry = mesh.geometry; 2694 let material = mesh.material; 2695 const useDerivativeTangents = geometry.attributes.tangent === undefined; 2696 const useVertexColors = geometry.attributes.color !== undefined; 2697 const useFlatShading = geometry.attributes.normal === undefined; 2698 2699 if ( mesh.isPoints ) { 2700 2701 const cacheKey = 'PointsMaterial:' + material.uuid; 2702 let pointsMaterial = this.cache.get( cacheKey ); 2703 2704 if ( ! pointsMaterial ) { 2705 2706 pointsMaterial = new THREE.PointsMaterial(); 2707 THREE.Material.prototype.copy.call( pointsMaterial, material ); 2708 pointsMaterial.color.copy( material.color ); 2709 pointsMaterial.map = material.map; 2710 pointsMaterial.sizeAttenuation = false; // glTF spec says points should be 1px 2711 2712 this.cache.add( cacheKey, pointsMaterial ); 2713 2714 } 2715 2716 material = pointsMaterial; 2717 2718 } else if ( mesh.isLine ) { 2719 2720 const cacheKey = 'LineBasicMaterial:' + material.uuid; 2721 let lineMaterial = this.cache.get( cacheKey ); 2722 2723 if ( ! lineMaterial ) { 2724 2725 lineMaterial = new THREE.LineBasicMaterial(); 2726 THREE.Material.prototype.copy.call( lineMaterial, material ); 2727 lineMaterial.color.copy( material.color ); 2728 this.cache.add( cacheKey, lineMaterial ); 2729 2730 } 2731 2732 material = lineMaterial; 2733 2734 } // Clone the material if it will be modified 2735 2736 2737 if ( useDerivativeTangents || useVertexColors || useFlatShading ) { 2738 2739 let cacheKey = 'ClonedMaterial:' + material.uuid + ':'; 2740 if ( material.isGLTFSpecularGlossinessMaterial ) cacheKey += 'specular-glossiness:'; 2741 if ( useDerivativeTangents ) cacheKey += 'derivative-tangents:'; 2742 if ( useVertexColors ) cacheKey += 'vertex-colors:'; 2743 if ( useFlatShading ) cacheKey += 'flat-shading:'; 2744 let cachedMaterial = this.cache.get( cacheKey ); 2745 2746 if ( ! cachedMaterial ) { 2747 2748 cachedMaterial = material.clone(); 2749 if ( useVertexColors ) cachedMaterial.vertexColors = true; 2750 if ( useFlatShading ) cachedMaterial.flatShading = true; 2751 2752 if ( useDerivativeTangents ) { 2753 2754 // https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995 2755 if ( cachedMaterial.normalScale ) cachedMaterial.normalScale.y *= - 1; 2756 if ( cachedMaterial.clearcoatNormalScale ) cachedMaterial.clearcoatNormalScale.y *= - 1; 2757 2758 } 2759 2760 this.cache.add( cacheKey, cachedMaterial ); 2761 this.associations.set( cachedMaterial, this.associations.get( material ) ); 2762 2763 } 2764 2765 material = cachedMaterial; 2766 2767 } // workarounds for mesh and geometry 2768 2769 2770 if ( material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined ) { 2771 2772 geometry.setAttribute( 'uv2', geometry.attributes.uv ); 2773 2774 } 2775 2776 mesh.material = material; 2777 2778 } 2779 2780 getMaterialType() { 2781 2782 return THREE.MeshStandardMaterial; 2783 2784 } 2785 /** 2786 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials 2787 * @param {number} materialIndex 2788 * @return {Promise<Material>} 2789 */ 2790 2791 2792 loadMaterial( materialIndex ) { 2793 2794 const parser = this; 2795 const json = this.json; 2796 const extensions = this.extensions; 2797 const materialDef = json.materials[ materialIndex ]; 2798 let materialType; 2799 const materialParams = {}; 2800 const materialExtensions = materialDef.extensions || {}; 2801 const pending = []; 2802 2803 if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] ) { 2804 2805 const sgExtension = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ]; 2806 materialType = sgExtension.getMaterialType(); 2807 pending.push( sgExtension.extendParams( materialParams, materialDef, parser ) ); 2808 2809 } else if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ] ) { 2810
2811 const kmuExtension = extensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ]; 2812 materialType = kmuExtension.getMaterialType(); 2813 pending.push( kmuExtension.extendParams( materialParams, materialDef, parser ) ); 2814 2815 } else { 2816 2817 // Specification: 2818 // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material 2819 const metallicRoughness = materialDef.pbrMetallicRoughness || {}; 2820 materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 ); 2821 materialParams.opacity = 1.0; 2822 2823 if ( Array.isArray( metallicRoughness.baseColorFactor ) ) { 2824 2825 const array = metallicRoughness.baseColorFactor; 2826 materialParams.color.fromArray( array ); 2827 materialParams.opacity = array[ 3 ]; 2828 2829 } 2830 2831 if ( metallicRoughness.baseColorTexture !== undefined ) { 2832 2833 pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) ); 2834 2835 } 2836 2837 materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0; 2838 materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0; 2839 2840 if ( metallicRoughness.metallicRoughnessTexture !== undefined ) { 2841 2842 pending.push( parser.assignTexture( materialParams, 'metalnessMap', metallicRoughness.metallicRoughnessTexture ) ); 2843 pending.push( parser.assignTexture( materialParams, 'roughnessMap', metallicRoughness.metallicRoughnessTexture ) ); 2844 2845 } 2846 2847 materialType = this._invokeOne( function ( ext ) { 2848 2849 return ext.getMaterialType && ext.getMaterialType( materialIndex ); 2850 2851 } ); 2852 pending.push( Promise.all( this._invokeAll( function ( ext ) { 2853 2854 return ext.extendMaterialParams && ext.extendMaterialParams( materialIndex, materialParams ); 2855 2856 } ) ) ); 2857 2858 } 2859 2860 if ( materialDef.doubleSided === true ) { 2861 2862 materialParams.side = THREE.DoubleSide; 2863 2864 } 2865 2866 const alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE; 2867 2868 if ( alphaMode === ALPHA_MODES.BLEND ) { 2869 2870 materialParams.transparent = true; // See: https://github.com/mrdoob/three.js/issues/17706 2871 2872 materialParams.depthWrite = false; 2873 2874 } else { 2875 2876 materialParams.format = THREE.RGBFormat; 2877 materialParams.transparent = false; 2878 2879 if ( alphaMode === ALPHA_MODES.MASK ) { 2880 2881 materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5; 2882 2883 } 2884 2885 } 2886 2887 if ( materialDef.normalTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) { 2888 2889 pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture ) ); 2890 materialParams.normalScale = new THREE.Vector2( 1, 1 ); 2891 2892 if ( materialDef.normalTexture.scale !== undefined ) { 2893 2894 const scale = materialDef.normalTexture.scale; 2895 materialParams.normalScale.set( scale, scale ); 2896 2897 } 2898 2899 } 2900 2901 if ( materialDef.occlusionTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) { 2902 2903 pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture ) ); 2904 2905 if ( materialDef.occlusionTexture.strength !== undefined ) { 2906 2907 materialParams.aoMapIntensity = materialDef.occlusionTexture.strength; 2908 2909 } 2910 2911 } 2912 2913 if ( materialDef.emissiveFactor !== undefined && materialType !== THREE.MeshBasicMaterial ) { 2914 2915 materialParams.emissive = new THREE.Color().fromArray( materialDef.emissiveFactor ); 2916 2917 } 2918 2919 if ( materialDef.emissiveTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) { 2920 2921 pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture ) ); 2922 2923 } 2924 2925 return Promise.all( pending ).then( function () { 2926 2927 let material; 2928 2929 if ( materialType === GLTFMeshStandardSGMaterial ) { 2930 2931 material = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].createMaterial( materialParams ); 2932 2933 } else { 2934 2935 material = new materialType( materialParams ); 2936 2937 } 2938 2939 if ( materialDef.name ) material.name = materialDef.name; // baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding. 2940 2941 if ( material.map ) material.map.encoding = THREE.sRGBEncoding; 2942 if ( material.emissiveMap ) material.emissiveMap.encoding = THREE.sRGBEncoding; 2943 assignExtrasToUserData( material, materialDef ); 2944 parser.associations.set( material, { 2945 materials: materialIndex 2946 } ); 2947 if ( materialDef.extensions ) addUnknownExtensionsToUserData( extensions, material, materialDef ); 2948 return material; 2949 2950 } ); 2951 2952 } 2953 /** When THREE.Object3D instances are targeted by animation, they need unique names. */ 2954 2955 2956 createUniqueName( originalName ) { 2957 2958 const sanitizedName = THREE.PropertyBinding.sanitizeNodeName( originalName || '' ); 2959 let name = sanitizedName; 2960 2961 for ( let i = 1; this.nodeNamesUsed[ name ]; ++ i ) { 2962 2963 name = sanitizedName + '_' + i; 2964 2965 } 2966 2967 this.nodeNamesUsed[ name ] = true; 2968 return name; 2969 2970 } 2971 /** 2972 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry 2973 * 2974 * Creates BufferGeometries from primitives. 2975 * 2976 * @param {Array<GLTF.Primitive>} primitives 2977 * @return {Promise<Array<BufferGeometry>>} 2978 */ 2979 2980 2981 loadGeometries( primitives ) { 2982 2983 const parser = this; 2984 const extensions = this.extensions; 2985 const cache = this.primitiveCache; 2986 2987 function createDracoPrimitive( primitive ) { 2988 2989 return extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ].decodePrimitive( primitive, parser ).then( function ( geometry ) { 2990 2991 return addPrimitiveAttributes( geometry, primitive, parser ); 2992 2993 } ); 2994 2995 } 2996 2997 const pending = []; 2998 2999 for ( let i = 0, il = primitives.length; i < il; i ++ ) { 3000 3001 const primitive = primitives[ i ]; 3002 const cacheKey = createPrimitiveKey( primitive ); // See if we've already created this geometry 3003
vendor: 5,165 bytes, lines 3004-3194
3004 const cached = cache[ cacheKey ]; 3005 3006 if ( cached ) { 3007 3008 // Use the cached geometry if it exists 3009 pending.push( cached.promise ); 3010 3011 } else { 3012 3013 let geometryPromise; 3014 3015 if ( primitive.extensions && primitive.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] ) { 3016 3017 // Use DRACO geometry if available 3018 geometryPromise = createDracoPrimitive( primitive ); 3019 3020 } else { 3021 3022 // Otherwise create a new geometry 3023 geometryPromise = addPrimitiveAttributes( new THREE.BufferGeometry(), primitive, parser ); 3024 3025 } // Cache this geometry 3026 3027 3028 cache[ cacheKey ] = { 3029 primitive: primitive, 3030 promise: geometryPromise 3031 }; 3032 pending.push( geometryPromise ); 3033 3034 } 3035 3036 } 3037 3038 return Promise.all( pending ); 3039 3040 } 3041 /** 3042 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes 3043 * @param {number} meshIndex 3044 * @return {Promise<Group|Mesh|SkinnedMesh>} 3045 */ 3046 3047 3048 loadMesh( meshIndex ) { 3049 3050 const parser = this; 3051 const json = this.json; 3052 const extensions = this.extensions; 3053 const meshDef = json.meshes[ meshIndex ]; 3054 const primitives = meshDef.primitives; 3055 const pending = []; 3056 3057 for ( let i = 0, il = primitives.length; i < il; i ++ ) { 3058 3059 const material = primitives[ i ].material === undefined ? createDefaultMaterial( this.cache ) : this.getDependency( 'material', primitives[ i ].material ); 3060 pending.push( material ); 3061 3062 } 3063 3064 pending.push( parser.loadGeometries( primitives ) ); 3065 return Promise.all( pending ).then( function ( results ) { 3066 3067 const materials = results.slice( 0, results.length - 1 ); 3068 const geometries = results[ results.length - 1 ]; 3069 const meshes = []; 3070 3071 for ( let i = 0, il = geometries.length; i < il; i ++ ) { 3072 3073 const geometry = geometries[ i ]; 3074 const primitive = primitives[ i ]; // 1. create THREE.Mesh 3075 3076 let mesh; 3077 const material = materials[ i ]; 3078 3079 if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES || primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP || primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN || primitive.mode === undefined ) { 3080 3081 // .isSkinnedMesh isn't in glTF spec. See ._markDefs() 3082 mesh = meshDef.isSkinnedMesh === true ? new THREE.SkinnedMesh( geometry, material ) : new THREE.Mesh( geometry, material ); 3083 3084 if ( mesh.isSkinnedMesh === true && ! mesh.geometry.attributes.skinWeight.normalized ) { 3085 3086 // we normalize floating point skin weight array to fix malformed assets (see #15319) 3087 // it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs 3088 mesh.normalizeSkinWeights(); 3089 3090 } 3091 3092 if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) { 3093 3094 mesh.geometry = toTrianglesDrawMode( mesh.geometry, THREE.TriangleStripDrawMode ); 3095 3096 } else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) { 3097 3098 mesh.geometry = toTrianglesDrawMode( mesh.geometry, THREE.TriangleFanDrawMode ); 3099 3100 } 3101 3102 } else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) { 3103 3104 mesh = new THREE.LineSegments( geometry, material ); 3105 3106 } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) { 3107 3108 mesh = new THREE.Line( geometry, material ); 3109 3110 } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) { 3111 3112 mesh = new THREE.LineLoop( geometry, material ); 3113 3114 } else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) { 3115 3116 mesh = new THREE.Points( geometry, material ); 3117 3118 } else { 3119 3120 throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode ); 3121 3122 } 3123 3124 if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) { 3125 3126 updateMorphTargets( mesh, meshDef ); 3127 3128 } 3129 3130 mesh.name = parser.createUniqueName( meshDef.name || 'mesh_' + meshIndex ); 3131 assignExtrasToUserData( mesh, meshDef ); 3132 if ( primitive.extensions ) addUnknownExtensionsToUserData( extensions, mesh, primitive ); 3133 parser.assignFinalMaterial( mesh ); 3134 meshes.push( mesh ); 3135 3136 } 3137 3138 for ( let i = 0, il = meshes.length; i < il; i ++ ) { 3139 3140 parser.associations.set( meshes[ i ], { 3141 meshes: meshIndex, 3142 primitives: i 3143 } ); 3144 3145 } 3146 3147 if ( meshes.length === 1 ) { 3148 3149 return meshes[ 0 ]; 3150 3151 } 3152 3153 const group = new THREE.Group(); 3154 parser.associations.set( group, { 3155 meshes: meshIndex 3156 } ); 3157 3158 for ( let i = 0, il = meshes.length; i < il; i ++ ) { 3159 3160 group.add( meshes[ i ] ); 3161 3162 } 3163 3164 return group; 3165 3166 } ); 3167 3168 } 3169 /** 3170 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras 3171 * @param {number} cameraIndex 3172 * @return {Promise<THREE.Camera>} 3173 */ 3174 3175 3176 loadCamera( cameraIndex ) { 3177 3178 let camera; 3179 const cameraDef = this.json.cameras[ cameraIndex ]; 3180 const params = cameraDef[ cameraDef.type ]; 3181 3182 if ( ! params ) { 3183 3184 console.warn( 'THREE.GLTFLoader: Missing camera parameters.' ); 3185 return; 3186 3187 } 3188 3189 if ( cameraDef.type === 'perspective' ) { 3190 3191 camera = new THREE.PerspectiveCamera( THREE.MathUtils.radToDeg( params.yfov ), params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6 ); 3192 3193 } else if ( cameraDef.type === 'orthographic' ) { 3194
3195 camera = new THREE.OrthographicCamera( - params.xmag, params.xmag, params.ymag, - params.ymag, params.znear, params.zfar ); 3196 3197 } 3198 3199 if ( cameraDef.name ) camera.name = this.createUniqueName( cameraDef.name ); 3200 assignExtrasToUserData( camera, cameraDef ); 3201 return Promise.resolve( camera ); 3202 3203 } 3204 /** 3205 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins 3206 * @param {number} skinIndex 3207 * @return {Promise<Object>} 3208 */ 3209 3210 3211 loadSkin( skinIndex ) { 3212 3213 const skinDef = this.json.skins[ skinIndex ]; 3214 const skinEntry = { 3215 joints: skinDef.joints 3216 }; 3217 3218 if ( skinDef.inverseBindMatrices === undefined ) { 3219 3220 return Promise.resolve( skinEntry ); 3221 3222 } 3223 3224 return this.getDependency( 'accessor', skinDef.inverseBindMatrices ).then( function ( accessor ) { 3225 3226 skinEntry.inverseBindMatrices = accessor; 3227 return skinEntry; 3228 3229 } ); 3230 3231 } 3232 /** 3233 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations 3234 * @param {number} animationIndex 3235 * @return {Promise<AnimationClip>} 3236 */ 3237 3238 3239 loadAnimation( animationIndex ) { 3240 3241 const json = this.json; 3242 const animationDef = json.animations[ animationIndex ]; 3243 const pendingNodes = []; 3244 const pendingInputAccessors = []; 3245 const pendingOutputAccessors = []; 3246 const pendingSamplers = []; 3247 const pendingTargets = []; 3248 3249 for ( let i = 0, il = animationDef.channels.length; i < il; i ++ ) { 3250 3251 const channel = animationDef.channels[ i ]; 3252 const sampler = animationDef.samplers[ channel.sampler ]; 3253 const target = channel.target; 3254 const name = target.node !== undefined ? target.node : target.id; // NOTE: target.id is deprecated. 3255 3256 const input = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.input ] : sampler.input; 3257 const output = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.output ] : sampler.output; 3258 pendingNodes.push( this.getDependency( 'node', name ) ); 3259 pendingInputAccessors.push( this.getDependency( 'accessor', input ) ); 3260 pendingOutputAccessors.push( this.getDependency( 'accessor', output ) ); 3261 pendingSamplers.push( sampler ); 3262 pendingTargets.push( target ); 3263 3264 } 3265 3266 return Promise.all( [ Promise.all( pendingNodes ), Promise.all( pendingInputAccessors ), Promise.all( pendingOutputAccessors ), Promise.all( pendingSamplers ), Promise.all( pendingTargets ) ] ).then( function ( dependencies ) { 3267 3268 const nodes = dependencies[ 0 ]; 3269 const inputAccessors = dependencies[ 1 ]; 3270 const outputAccessors = dependencies[ 2 ]; 3271 const samplers = dependencies[ 3 ]; 3272 const targets = dependencies[ 4 ]; 3273 const tracks = []; 3274 3275 for ( let i = 0, il = nodes.length; i < il; i ++ ) { 3276 3277 const node = nodes[ i ]; 3278 const inputAccessor = inputAccessors[ i ]; 3279 const outputAccessor = outputAccessors[ i ]; 3280 const sampler = samplers[ i ]; 3281 const target = targets[ i ]; 3282 if ( node === undefined ) continue; 3283 node.updateMatrix(); 3284 node.matrixAutoUpdate = true; 3285 let TypedKeyframeTrack; 3286 3287 switch ( PATH_PROPERTIES[ target.path ] ) { 3288 3289 case PATH_PROPERTIES.weights: 3290 TypedKeyframeTrack = THREE.NumberKeyframeTrack; 3291 break; 3292 3293 case PATH_PROPERTIES.rotation: 3294 TypedKeyframeTrack = THREE.QuaternionKeyframeTrack; 3295 break; 3296 3297 case PATH_PROPERTIES.position: 3298 case PATH_PROPERTIES.scale: 3299 default: 3300 TypedKeyframeTrack = THREE.VectorKeyframeTrack; 3301 break; 3302 3303 } 3304 3305 const targetName = node.name ? node.name : node.uuid; 3306 const interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : THREE.InterpolateLinear; 3307 const targetNames = []; 3308 3309 if ( PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.weights ) { 3310 3311 // Node may be a THREE.Group (glTF mesh with several primitives) or a THREE.Mesh. 3312 node.traverse( function ( object ) { 3313 3314 if ( object.isMesh === true && object.morphTargetInfluences ) { 3315 3316 targetNames.push( object.name ? object.name : object.uuid ); 3317 3318 } 3319 3320 } ); 3321 3322 } else { 3323 3324 targetNames.push( targetName ); 3325 3326 } 3327 3328 let outputArray = outputAccessor.array; 3329 3330 if ( outputAccessor.normalized ) { 3331 3332 const scale = getNormalizedComponentScale( outputArray.constructor ); 3333 const scaled = new Float32Array( outputArray.length ); 3334 3335 for ( let j = 0, jl = outputArray.length; j < jl; j ++ ) { 3336 3337 scaled[ j ] = outputArray[ j ] * scale; 3338 3339 } 3340 3341 outputArray = scaled; 3342 3343 } 3344 3345 for ( let j = 0, jl = targetNames.length; j < jl; j ++ ) { 3346 3347 const track = new TypedKeyframeTrack( targetNames[ j ] + '.' + PATH_PROPERTIES[ target.path ], inputAccessor.array, outputArray, interpolation ); // Override interpolation with custom factory method. 3348 3349 if ( sampler.interpolation === 'CUBICSPLINE' ) { 3350 3351 track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline( result ) { 3352 3353 // A CUBICSPLINE keyframe in glTF has three output values for each input value, 3354 // representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize() 3355 // must be divided by three to get the interpolant's sampleSize argument. 3356 const interpolantType = this instanceof THREE.QuaternionKeyframeTrack ? GLTFCubicSplineQuaternionInterpolant : GLTFCubicSplineInterpolant; 3357 return new interpolantType( this.times, this.values, this.getValueSize() / 3, result ); 3358 3359 };
3359 // Mark as CUBICSPLINE. `track.getInterpolation()` doesn't support custom interpolants. 3360 3361 3362 track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true; 3363 3364 } 3365 3366 tracks.push( track ); 3367 3368 } 3369 3370 } 3371 3372 const name = animationDef.name ? animationDef.name : 'animation_' + animationIndex; 3373 return new THREE.AnimationClip( name, undefined, tracks ); 3374 3375 } ); 3376 3377 } 3378 3379 createNodeMesh( nodeIndex ) { 3380 3381 const json = this.json; 3382 const parser = this; 3383 const nodeDef = json.nodes[ nodeIndex ]; 3384 if ( nodeDef.mesh === undefined ) return null; 3385 return parser.getDependency( 'mesh', nodeDef.mesh ).then( function ( mesh ) { 3386 3387 const node = parser._getNodeRef( parser.meshCache, nodeDef.mesh, mesh ); // if weights are provided on the node, override weights on the mesh. 3388 3389 3390 if ( nodeDef.weights !== undefined ) { 3391 3392 node.traverse( function ( o ) { 3393 3394 if ( ! o.isMesh ) return; 3395 3396 for ( let i = 0, il = nodeDef.weights.length; i < il; i ++ ) { 3397 3398 o.morphTargetInfluences[ i ] = nodeDef.weights[ i ]; 3399 3400 } 3401 3402 } ); 3403 3404 } 3405 3406 return node; 3407 3408 } ); 3409 3410 } 3411 /** 3412 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy 3413 * @param {number} nodeIndex 3414 * @return {Promise<Object3D>} 3415 */ 3416 3417 3418 loadNode( nodeIndex ) { 3419 3420 const json = this.json; 3421 const extensions = this.extensions; 3422 const parser = this; 3423 const nodeDef = json.nodes[ nodeIndex ]; // reserve node's name before its dependencies, so the root has the intended name. 3424 3425 const nodeName = nodeDef.name ? parser.createUniqueName( nodeDef.name ) : ''; 3426 return function () { 3427 3428 const pending = []; 3429 3430 const meshPromise = parser._invokeOne( function ( ext ) { 3431 3432 return ext.createNodeMesh && ext.createNodeMesh( nodeIndex ); 3433 3434 } ); 3435 3436 if ( meshPromise ) { 3437 3438 pending.push( meshPromise ); 3439 3440 } 3441 3442 if ( nodeDef.camera !== undefined ) { 3443 3444 pending.push( parser.getDependency( 'camera', nodeDef.camera ).then( function ( camera ) { 3445 3446 return parser._getNodeRef( parser.cameraCache, nodeDef.camera, camera ); 3447 3448 } ) ); 3449 3450 } 3451 3452 parser._invokeAll( function ( ext ) { 3453 3454 return ext.createNodeAttachment && ext.createNodeAttachment( nodeIndex ); 3455 3456 } ).forEach( function ( promise ) { 3457 3458 pending.push( promise ); 3459 3460 } ); 3461 3462 return Promise.all( pending ); 3463 3464 }().then( function ( objects ) { 3465 3466 let node; // .isBone isn't in glTF spec. See ._markDefs 3467 3468 if ( nodeDef.isBone === true ) { 3469 3470 node = new THREE.Bone(); 3471 3472 } else if ( objects.length > 1 ) { 3473 3474 node = new THREE.Group(); 3475 3476 } else if ( objects.length === 1 ) { 3477 3478 node = objects[ 0 ]; 3479 3480 } else { 3481 3482 node = new THREE.Object3D(); 3483 3484 } 3485 3486 if ( node !== objects[ 0 ] ) { 3487 3488 for ( let i = 0, il = objects.length; i < il; i ++ ) { 3489 3490 node.add( objects[ i ] ); 3491 3492 } 3493 3494 } 3495 3496 if ( nodeDef.name ) { 3497 3498 node.userData.name = nodeDef.name; 3499 node.name = nodeName; 3500 3501 } 3502 3503 assignExtrasToUserData( node, nodeDef ); 3504 if ( nodeDef.extensions ) addUnknownExtensionsToUserData( extensions, node, nodeDef ); 3505 3506 if ( nodeDef.matrix !== undefined ) { 3507 3508 const matrix = new THREE.Matrix4(); 3509 matrix.fromArray( nodeDef.matrix ); 3510 node.applyMatrix4( matrix ); 3511 3512 } else { 3513 3514 if ( nodeDef.translation !== undefined ) { 3515 3516 node.position.fromArray( nodeDef.translation ); 3517 3518 } 3519 3520 if ( nodeDef.rotation !== undefined ) { 3521 3522 node.quaternion.fromArray( nodeDef.rotation ); 3523 3524 } 3525 3526 if ( nodeDef.scale !== undefined ) { 3527 3528 node.scale.fromArray( nodeDef.scale ); 3529 3530 } 3531 3532 } 3533 3534 if ( ! parser.associations.has( node ) ) { 3535 3536 parser.associations.set( node, {} ); 3537 3538 } 3539 3540 parser.associations.get( node ).nodes = nodeIndex; 3541 return node; 3542 3543 } ); 3544 3545 } 3546 /** 3547 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes 3548 * @param {number} sceneIndex 3549 * @return {Promise<Group>} 3550 */ 3551 3552 3553 loadScene( sceneIndex ) { 3554 3555 const json = this.json; 3556 const extensions = this.extensions; 3557 const sceneDef = this.json.scenes[ sceneIndex ]; 3558 const parser = this; // THREE.Loader returns THREE.Group, not Scene. 3559 // See: https://github.com/mrdoob/three.js/issues/18342#issuecomment-578981172 3560 3561 const scene = new THREE.Group(); 3562 if ( sceneDef.name ) scene.name = parser.createUniqueName( sceneDef.name ); 3563 assignExtrasToUserData( scene, sceneDef ); 3564 if ( sceneDef.extensions ) addUnknownExtensionsToUserData( extensions, scene, sceneDef ); 3565 const nodeIds = sceneDef.nodes || []; 3566 const pending = []; 3567 3568 for ( let i = 0, il = nodeIds.length; i < il; i ++ ) { 3569 3570 pending.push( buildNodeHierarchy( nodeIds[ i ], scene, json, parser ) ); 3571 3572 } 3573 3574 return Promise.all( pending ).then( function () { 3575 3576 // Removes dangling associations, associations that reference a node that 3577 // didn't make it into the scene. 3578 const reduceAssociations = node => { 3579 3580 const reducedAssociations = new Map(); 3581 3582 for ( const [ key, value ] of parser.associations ) { 3583 3584 if ( key instanceof THREE.Material || key instanceof THREE.Texture ) { 3585
3586 reducedAssociations.set( key, value ); 3587 3588 } 3589 3590 } 3591 3592 node.traverse( node => { 3593 3594 const mappings = parser.associations.get( node ); 3595 3596 if ( mappings != null ) { 3597 3598 reducedAssociations.set( node, mappings ); 3599 3600 } 3601 3602 } ); 3603 return reducedAssociations; 3604 3605 }; 3606 3607 parser.associations = reduceAssociations( scene ); 3608 return scene; 3609 3610 } ); 3611 3612 } 3613 3614 } 3615 3616 function buildNodeHierarchy( nodeId, parentObject, json, parser ) { 3617 3618 const nodeDef = json.nodes[ nodeId ]; 3619 return parser.getDependency( 'node', nodeId ).then( function ( node ) { 3620 3621 if ( nodeDef.skin === undefined ) return node; // build skeleton here as well 3622 3623 let skinEntry; 3624 return parser.getDependency( 'skin', nodeDef.skin ).then( function ( skin ) { 3625 3626 skinEntry = skin; 3627 const pendingJoints = []; 3628 3629 for ( let i = 0, il = skinEntry.joints.length; i < il; i ++ ) { 3630 3631 pendingJoints.push( parser.getDependency( 'node', skinEntry.joints[ i ] ) ); 3632 3633 } 3634 3635 return Promise.all( pendingJoints ); 3636 3637 } ).then( function ( jointNodes ) { 3638 3639 node.traverse( function ( mesh ) { 3640 3641 if ( ! mesh.isMesh ) return; 3642 const bones = []; 3643 const boneInverses = []; 3644 3645 for ( let j = 0, jl = jointNodes.length; j < jl; j ++ ) { 3646 3647 const jointNode = jointNodes[ j ]; 3648 3649 if ( jointNode ) { 3650 3651 bones.push( jointNode ); 3652 const mat = new THREE.Matrix4(); 3653 3654 if ( skinEntry.inverseBindMatrices !== undefined ) { 3655 3656 mat.fromArray( skinEntry.inverseBindMatrices.array, j * 16 ); 3657 3658 } 3659 3660 boneInverses.push( mat ); 3661 3662 } else { 3663 3664 console.warn( 'THREE.GLTFLoader: Joint "%s" could not be found.', skinEntry.joints[ j ] ); 3665 3666 } 3667 3668 } 3669 3670 mesh.bind( new THREE.Skeleton( bones, boneInverses ), mesh.matrixWorld ); 3671 3672 } ); 3673 return node; 3674 3675 } ); 3676 3677 } ).then( function ( node ) { 3678 3679 // build node hierachy 3680 parentObject.add( node ); 3681 const pending = []; 3682 3683 if ( nodeDef.children ) { 3684 3685 const children = nodeDef.children; 3686 3687 for ( let i = 0, il = children.length; i < il; i ++ ) { 3688 3689 const child = children[ i ]; 3690 pending.push( buildNodeHierarchy( child, node, json, parser ) ); 3691 3692 } 3693 3694 } 3695 3696 return Promise.all( pending ); 3697 3698 } ); 3699 3700 } 3701 /** 3702 * @param {BufferGeometry} geometry 3703 * @param {GLTF.Primitive} primitiveDef 3704 * @param {GLTFParser} parser 3705 */ 3706 3707 3708 function computeBounds( geometry, primitiveDef, parser ) { 3709 3710 const attributes = primitiveDef.attributes; 3711 const box = new THREE.Box3(); 3712 3713 if ( attributes.POSITION !== undefined ) { 3714 3715 const accessor = parser.json.accessors[ attributes.POSITION ]; 3716 const min = accessor.min; 3717 const max = accessor.max; // glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement. 3718 3719 if ( min !== undefined && max !== undefined ) { 3720 3721 box.set( new THREE.Vector3( min[ 0 ], min[ 1 ], min[ 2 ] ), new THREE.Vector3( max[ 0 ], max[ 1 ], max[ 2 ] ) ); 3722 3723 if ( accessor.normalized ) { 3724 3725 const boxScale = getNormalizedComponentScale( WEBGL_COMPONENT_TYPES[ accessor.componentType ] ); 3726 box.min.multiplyScalar( boxScale ); 3727 box.max.multiplyScalar( boxScale ); 3728 3729 } 3730 3731 } else { 3732 3733 console.warn( 'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.' ); 3734 return; 3735 3736 } 3737 3738 } else { 3739 3740 return; 3741 3742 } 3743 3744 const targets = primitiveDef.targets; 3745 3746 if ( targets !== undefined ) { 3747 3748 const maxDisplacement = new THREE.Vector3(); 3749 const vector = new THREE.Vector3(); 3750 3751 for ( let i = 0, il = targets.length; i < il; i ++ ) { 3752 3753 const target = targets[ i ]; 3754 3755 if ( target.POSITION !== undefined ) { 3756 3757 const accessor = parser.json.accessors[ target.POSITION ]; 3758 const min = accessor.min; 3759 const max = accessor.max; // glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement. 3760 3761 if ( min !== undefined && max !== undefined ) { 3762 3763 // we need to get max of absolute components because target weight is [-1,1] 3764 vector.setX( Math.max( Math.abs( min[ 0 ] ), Math.abs( max[ 0 ] ) ) ); 3765 vector.setY( Math.max( Math.abs( min[ 1 ] ), Math.abs( max[ 1 ] ) ) ); 3766 vector.setZ( Math.max( Math.abs( min[ 2 ] ), Math.abs( max[ 2 ] ) ) ); 3767 3768 if ( accessor.normalized ) { 3769 3770 const boxScale = getNormalizedComponentScale( WEBGL_COMPONENT_TYPES[ accessor.componentType ] ); 3771 vector.multiplyScalar( boxScale ); 3772 3773 } // Note: this assumes that the sum of all weights is at most 1. This isn't quite correct - it's more conservative 3774 // to assume that each target can have a max weight of 1. However, for some use cases - notably, when morph targets 3775 // are used to implement key-frame animations and as such only two are active at a time - this results in very large 3776 // boxes. So for now we make a box that's sometimes a touch too small but is hopefully mostly of reasonable size. 3777 3778 3779 maxDisplacement.max( vector ); 3780 3781 } else { 3782 3783 console.warn( 'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.' ); 3784 3785 } 3786 3787 } 3788 3789 } // As per comment above this box isn't conservative, but has a reasonable size for a very large number of morph targets. 3790 3791 3792 box.expandByVector( maxDisplacement ); 3793 3794 } 3795 3796 geometry.boundingBox = box; 3797 const sphere = new THREE.Sphere(); 3798 box.getCenter( sphere.center ); 3799 sphere.radius = box.min.distanceTo( box.max ) / 2; 3800 geometry.boundingSphere = sphere; 3801 3802 } 3803 /** 3804 * @param {BufferGeometry} geometry 3805 * @param {GLTF.Primitive} primitiveDef 3806 * @param {GLTFParser} parser 3807 * @return {Promise<BufferGeometry>} 3808 */ 3809 3810 3811 function addPrimitiveAttributes( geometry, primitiveDef, parser ) { 3812 3813 const attributes = primitiveDef.attributes; 3814 const pending = []; 3815
vendor: 2,921 bytes, lines 3816-3944
3816 function assignAttributeAccessor( accessorIndex, attributeName ) { 3817 3818 return parser.getDependency( 'accessor', accessorIndex ).then( function ( accessor ) { 3819 3820 geometry.setAttribute( attributeName, accessor ); 3821 3822 } ); 3823 3824 } 3825 3826 for ( const gltfAttributeName in attributes ) { 3827 3828 const threeAttributeName = ATTRIBUTES[ gltfAttributeName ] || gltfAttributeName.toLowerCase(); // Skip attributes already provided by e.g. Draco extension. 3829 3830 if ( threeAttributeName in geometry.attributes ) continue; 3831 pending.push( assignAttributeAccessor( attributes[ gltfAttributeName ], threeAttributeName ) ); 3832 3833 } 3834 3835 if ( primitiveDef.indices !== undefined && ! geometry.index ) { 3836 3837 const accessor = parser.getDependency( 'accessor', primitiveDef.indices ).then( function ( accessor ) { 3838 3839 geometry.setIndex( accessor ); 3840 3841 } ); 3842 pending.push( accessor ); 3843 3844 } 3845 3846 assignExtrasToUserData( geometry, primitiveDef ); 3847 computeBounds( geometry, primitiveDef, parser ); 3848 return Promise.all( pending ).then( function () { 3849 3850 return primitiveDef.targets !== undefined ? addMorphTargets( geometry, primitiveDef.targets, parser ) : geometry; 3851 3852 } ); 3853 3854 } 3855 /** 3856 * @param {BufferGeometry} geometry 3857 * @param {Number} drawMode 3858 * @return {BufferGeometry} 3859 */ 3860 3861 3862 function toTrianglesDrawMode( geometry, drawMode ) { 3863 3864 let index = geometry.getIndex(); // generate index if not present 3865 3866 if ( index === null ) { 3867 3868 const indices = []; 3869 const position = geometry.getAttribute( 'position' ); 3870 3871 if ( position !== undefined ) { 3872 3873 for ( let i = 0; i < position.count; i ++ ) { 3874 3875 indices.push( i ); 3876 3877 } 3878 3879 geometry.setIndex( indices ); 3880 index = geometry.getIndex(); 3881 3882 } else { 3883 3884 console.error( 'THREE.GLTFLoader.toTrianglesDrawMode(): Undefined position attribute. Processing not possible.' ); 3885 return geometry; 3886 3887 } 3888 3889 } // 3890 3891 3892 const numberOfTriangles = index.count - 2; 3893 const newIndices = []; 3894 3895 if ( drawMode === THREE.TriangleFanDrawMode ) { 3896 3897 // gl.TRIANGLE_FAN 3898 for ( let i = 1; i <= numberOfTriangles; i ++ ) { 3899 3900 newIndices.push( index.getX( 0 ) ); 3901 newIndices.push( index.getX( i ) ); 3902 newIndices.push( index.getX( i + 1 ) ); 3903 3904 } 3905 3906 } else { 3907 3908 // gl.TRIANGLE_STRIP 3909 for ( let i = 0; i < numberOfTriangles; i ++ ) { 3910 3911 if ( i % 2 === 0 ) { 3912 3913 newIndices.push( index.getX( i ) ); 3914 newIndices.push( index.getX( i + 1 ) ); 3915 newIndices.push( index.getX( i + 2 ) ); 3916 3917 } else { 3918 3919 newIndices.push( index.getX( i + 2 ) ); 3920 newIndices.push( index.getX( i + 1 ) ); 3921 newIndices.push( index.getX( i ) ); 3922 3923 } 3924 3925 } 3926 3927 } 3928 3929 if ( newIndices.length / 3 !== numberOfTriangles ) { 3930 3931 console.error( 'THREE.GLTFLoader.toTrianglesDrawMode(): Unable to generate correct amount of triangles.' ); 3932 3933 } // build final geometry 3934 3935 3936 const newGeometry = geometry.clone(); 3937 newGeometry.setIndex( newIndices ); 3938 return newGeometry; 3939 3940 } 3941 3942 THREE.GLTFLoader = GLTFLoader; 3943 3944} )();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.