1/** 2 * @author Rich Tibbett / https://github.com/richtr 3 * @author mrdoob / http://mrdoob.com/ 4 * @author Tony Parisi / http://www.tonyparisi.com/ 5 * @author Takahiro / https://github.com/takahirox 6 * @author Don McCurdy / https://www.donmccurdy.com 7 */ 8 9THREE.GLTFLoader = ( function () { 10 11 function GLTFLoader( manager ) { 12 13 this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 14 this.dracoLoader = null; 15 16 } 17 18 GLTFLoader.prototype = { 19 20 constructor: GLTFLoader, 21 22 crossOrigin: 'anonymous', 23 24 load: function ( url, onLoad, onProgress, onError ) { 25 26 var scope = this; 27 28 var resourcePath; 29 30 if ( this.resourcePath !== undefined ) { 31 32 resourcePath = this.resourcePath; 33 34 } else if ( this.path !== undefined ) { 35 36 resourcePath = this.path; 37 38 } else { 39 40 resourcePath = THREE.LoaderUtils.extractUrlBase( url ); 41 42 } 43 44 // Tells the LoadingManager to track an extra item, which resolves after 45 // the model is fully loaded. This means the count of items loaded will 46 // be incorrect, but ensures manager.onLoad() does not fire early. 47 scope.manager.itemStart( url ); 48 49 var _onError = function ( e ) { 50 51 if ( onError ) { 52 53 onError( e ); 54 55 } else { 56 57 console.error( e ); 58 59 } 60 61 scope.manager.itemError( url ); 62 scope.manager.itemEnd( url ); 63 64 }; 65 66 var loader = new THREE.FileLoader( scope.manager ); 67 68 loader.setPath( this.path ); 69 loader.setResponseType( 'arraybuffer' ); 70 71 loader.load( url, function ( data ) { 72 73 try { 74 75 scope.parse( data, resourcePath, function ( gltf ) { 76 77 onLoad( gltf ); 78 79 scope.manager.itemEnd( url ); 80 81 }, _onError ); 82 83 } catch ( e ) { 84 85 _onError( e ); 86 87 } 88 89 }, onProgress, _onError ); 90 91 }, 92 93 setCrossOrigin: function ( value ) { 94 95 this.crossOrigin = value; 96 return this; 97 98 }, 99 100 setPath: function ( value ) { 101 102 this.path = value; 103 return this; 104 105 }, 106 107 setResourcePath: function ( value ) { 108 109 this.resourcePath = value; 110 return this; 111 112 }, 113 114 setDRACOLoader: function ( dracoLoader ) { 115 116 this.dracoLoader = dracoLoader; 117 return this; 118 119 }, 120 121 parse: function ( data, path, onLoad, onError ) { 122 123 var content; 124 var extensions = {}; 125 126 if ( typeof data === 'string' ) { 127 128 content = data; 129 130 } else { 131 132 var magic = THREE.LoaderUtils.decodeText( new Uint8Array( data, 0, 4 ) ); 133 134 if ( magic === BINARY_EXTENSION_HEADER_MAGIC ) { 135 136 try { 137 138 extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data ); 139 140 } catch ( error ) { 141 142 if ( onError ) onError( error ); 143 return; 144 145 } 146 147 content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content; 148 149 } else { 150 151 content = THREE.LoaderUtils.decodeText( new Uint8Array( data ) ); 152 153 } 154 155 } 156 157 var json = JSON.parse( content ); 158 159 if ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) { 160 161 if ( onError ) onError( new Error( 'THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported. Use LegacyGLTFLoader instead.' ) ); 162 return; 163 164 } 165 166 if ( json.extensionsUsed ) { 167 168 for ( var i = 0; i < json.extensionsUsed.length; ++ i ) { 169 170 var extensionName = json.extensionsUsed[ i ]; 171 var extensionsRequired = json.extensionsRequired || []; 172 173 switch ( extensionName ) { 174 175 case EXTENSIONS.KHR_LIGHTS_PUNCTUAL: 176 extensions[ extensionName ] = new GLTFLightsExtension( json ); 177 break; 178 179 case EXTENSIONS.KHR_MATERIALS_UNLIT: 180 extensions[ extensionName ] = new GLTFMaterialsUnlitExtension( json ); 181 break; 182 183 case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 184 extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension( json ); 185 break; 186 187 case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION: 188 extensions[ extensionName ] = new GLTFDracoMeshCompressionExtension( json, this.dracoLoader ); 189 break; 190 191 case EXTENSIONS.MSFT_TEXTURE_DDS: 192 extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension(); 193 break; 194 195 case EXTENSIONS.KHR_TEXTURE_TRANSFORM: 196 extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] = new GLTFTextureTransformExtension( json ); 197 break; 198 199 default: 200 201 if ( extensionsRequired.indexOf( extensionName ) >= 0 ) { 202 203 console.warn( 'THREE.GLTFLoader: Unknown extension "' + extensionName + '".' ); 204 205 } 206 207 } 208 209 } 210 211 } 212 213 var parser = new GLTFParser( json, extensions, { 214 215 path: path || this.resourcePath || '', 216 crossOrigin: this.crossOrigin, 217 manager: this.manager 218 219 } ); 220 221 parser.parse( onLoad, onError ); 222 223 } 224 225 }; 226 227 /* GLTFREGISTRY */ 228 229 function GLTFRegistry() { 230 231 var objects = {}; 232 233 return { 234 235 get: function ( key ) { 236 237 return objects[ key ]; 238 239 }, 240 241 add: function ( key, object ) { 242 243 objects[ key ] = object; 244 245 }, 246 247 remove: function ( key ) { 248 249 delete objects[ key ]; 250 251 }, 252 253 removeAll: function () { 254 255 objects = {}; 256 257 } 258 259 }; 260 261 } 262
263 /*********************************/ 264 /********** EXTENSIONS ***********/ 265 /*********************************/ 266 267 var EXTENSIONS = { 268 KHR_BINARY_GLTF: 'KHR_binary_glTF', 269 KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression', 270 KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual', 271 KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness', 272 KHR_MATERIALS_UNLIT: 'KHR_materials_unlit', 273 KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform', 274 MSFT_TEXTURE_DDS: 'MSFT_texture_dds' 275 }; 276 277 /** 278 * DDS Texture Extension 279 * 280 * Specification: 281 * https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds 282 * 283 */ 284 function GLTFTextureDDSExtension() { 285 286 if ( ! THREE.DDSLoader ) { 287 288 throw new Error( 'THREE.GLTFLoader: Attempting to load .dds texture without importing THREE.DDSLoader' ); 289 290 } 291 292 this.name = EXTENSIONS.MSFT_TEXTURE_DDS; 293 this.ddsLoader = new THREE.DDSLoader(); 294 295 } 296 297 /** 298 * Lights Extension 299 * 300 * Specification: PENDING 301 */ 302 function GLTFLightsExtension( json ) { 303 304 this.name = EXTENSIONS.KHR_LIGHTS_PUNCTUAL; 305 306 var extension = ( json.extensions && json.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ] ) || {}; 307 this.lightDefs = extension.lights || []; 308 309 } 310 311 GLTFLightsExtension.prototype.loadLight = function ( lightIndex ) { 312 313 var lightDef = this.lightDefs[ lightIndex ]; 314 var lightNode; 315 316 var color = new THREE.Color( 0xffffff ); 317 if ( lightDef.color !== undefined ) color.fromArray( lightDef.color ); 318 319 var range = lightDef.range !== undefined ? lightDef.range : 0; 320 321 switch ( lightDef.type ) { 322 323 case 'directional': 324 lightNode = new THREE.DirectionalLight( color ); 325 lightNode.target.position.set( 0, 0, - 1 ); 326 lightNode.add( lightNode.target ); 327 break; 328 329 case 'point': 330 lightNode = new THREE.PointLight( color ); 331 lightNode.distance = range; 332 break; 333 334 case 'spot': 335 lightNode = new THREE.SpotLight( color ); 336 lightNode.distance = range; 337 // Handle spotlight properties. 338 lightDef.spot = lightDef.spot || {}; 339 lightDef.spot.innerConeAngle = lightDef.spot.innerConeAngle !== undefined ? lightDef.spot.innerConeAngle : 0; 340 lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0; 341 lightNode.angle = lightDef.spot.outerConeAngle; 342 lightNode.penumbra = 1.0 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle; 343 lightNode.target.position.set( 0, 0, - 1 ); 344 lightNode.add( lightNode.target ); 345 break; 346 347 default: 348 throw new Error( 'THREE.GLTFLoader: Unexpected light type, "' + lightDef.type + '".' ); 349 350 } 351 352 // Some lights (e.g. spot) default to a position other than the origin. Reset the position 353 // here, because node-level parsing will only override position if explicitly specified. 354 lightNode.position.set( 0, 0, 0 ); 355 356 lightNode.decay = 2; 357 358 if ( lightDef.intensity !== undefined ) lightNode.intensity = lightDef.intensity; 359 360 lightNode.name = lightDef.name || ( 'light_' + lightIndex ); 361 362 return Promise.resolve( lightNode ); 363 364 }; 365 366 /** 367 * Unlit Materials Extension (pending) 368 * 369 * PR: https://github.com/KhronosGroup/glTF/pull/1163 370 */ 371 function GLTFMaterialsUnlitExtension( json ) { 372 373 this.name = EXTENSIONS.KHR_MATERIALS_UNLIT; 374 375 } 376 377 GLTFMaterialsUnlitExtension.prototype.getMaterialType = function ( material ) { 378 379 return THREE.MeshBasicMaterial; 380 381 }; 382 383 GLTFMaterialsUnlitExtension.prototype.extendParams = function ( materialParams, material, parser ) { 384 385 var pending = []; 386 387 materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 ); 388 materialParams.opacity = 1.0; 389 390 var metallicRoughness = material.pbrMetallicRoughness; 391 392 if ( metallicRoughness ) { 393 394 if ( Array.isArray( metallicRoughness.baseColorFactor ) ) { 395 396 var array = metallicRoughness.baseColorFactor; 397 398 materialParams.color.fromArray( array ); 399 materialParams.opacity = array[ 3 ]; 400 401 } 402 403 if ( metallicRoughness.baseColorTexture !== undefined ) { 404 405 pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) ); 406 407 } 408 409 } 410 411 return Promise.all( pending ); 412 413 }; 414 415 /* BINARY EXTENSION */ 416 417 var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF'; 418 var BINARY_EXTENSION_HEADER_MAGIC = 'glTF'; 419 var BINARY_EXTENSION_HEADER_LENGTH = 12; 420 var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 }; 421 422 function GLTFBinaryExtension( data ) { 423 424 this.name = EXTENSIONS.KHR_BINARY_GLTF; 425 this.content = null; 426 this.body = null; 427 428 var headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH ); 429 430 this.header = { 431 magic: THREE.LoaderUtils.decodeText( new Uint8Array( data.slice( 0, 4 ) ) ), 432 version: headerView.getUint32( 4, true ), 433 length: headerView.getUint32( 8, true ) 434 }; 435 436 if ( this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC ) { 437 438 throw new Error( 'THREE.GLTFLoader: Unsupported glTF-Binary header.' ); 439 440 } else if ( this.header.version < 2.0 ) { 441 442 throw new Error( 'THREE.GLTFLoader: Legacy binary file detected. Use LegacyGLTFLoader instead.' ); 443 444 } 445 446 var chunkView = new DataView( data, BINARY_EXTENSION_HEADER_LENGTH ); 447 var chunkIndex = 0; 448 449 while ( chunkIndex < chunkView.byteLength ) { 450
451 var chunkLength = chunkView.getUint32( chunkIndex, true ); 452 chunkIndex += 4; 453 454 var chunkType = chunkView.getUint32( chunkIndex, true ); 455 chunkIndex += 4; 456 457 if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON ) { 458 459 var contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength ); 460 this.content = THREE.LoaderUtils.decodeText( contentArray ); 461 462 } else if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN ) { 463 464 var byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex; 465 this.body = data.slice( byteOffset, byteOffset + chunkLength ); 466 467 } 468 469 // Clients must ignore chunks with unknown types. 470 471 chunkIndex += chunkLength; 472 473 } 474 475 if ( this.content === null ) { 476 477 throw new Error( 'THREE.GLTFLoader: JSON content not found.' ); 478 479 } 480 481 } 482 483 /** 484 * DRACO Mesh Compression Extension 485 * 486 * Specification: https://github.com/KhronosGroup/glTF/pull/874 487 */ 488 function GLTFDracoMeshCompressionExtension( json, dracoLoader ) { 489 490 if ( ! dracoLoader ) { 491 492 throw new Error( 'THREE.GLTFLoader: No DRACOLoader instance provided.' ); 493 494 } 495 496 this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION; 497 this.json = json; 498 this.dracoLoader = dracoLoader; 499 THREE.DRACOLoader.getDecoderModule(); 500 501 } 502 503 GLTFDracoMeshCompressionExtension.prototype.decodePrimitive = function ( primitive, parser ) { 504 505 var json = this.json; 506 var dracoLoader = this.dracoLoader; 507 var bufferViewIndex = primitive.extensions[ this.name ].bufferView; 508 var gltfAttributeMap = primitive.extensions[ this.name ].attributes; 509 var threeAttributeMap = {}; 510 var attributeNormalizedMap = {}; 511 var attributeTypeMap = {}; 512 513 for ( var attributeName in gltfAttributeMap ) { 514 515 var threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase(); 516 517 threeAttributeMap[ threeAttributeName ] = gltfAttributeMap[ attributeName ]; 518 519 } 520 521 for ( attributeName in primitive.attributes ) { 522 523 var threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase(); 524 525 if ( gltfAttributeMap[ attributeName ] !== undefined ) { 526 527 var accessorDef = json.accessors[ primitive.attributes[ attributeName ] ]; 528 var componentType = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ]; 529 530 attributeTypeMap[ threeAttributeName ] = componentType; 531 attributeNormalizedMap[ threeAttributeName ] = accessorDef.normalized === true; 532 533 } 534 535 } 536 537 return parser.getDependency( 'bufferView', bufferViewIndex ).then( function ( bufferView ) { 538 539 return new Promise( function ( resolve ) { 540 541 dracoLoader.decodeDracoFile( bufferView, function ( geometry ) { 542 543 for ( var attributeName in geometry.attributes ) { 544 545 var attribute = geometry.attributes[ attributeName ]; 546 var normalized = attributeNormalizedMap[ attributeName ]; 547 548 if ( normalized !== undefined ) attribute.normalized = normalized; 549 550 } 551 552 resolve( geometry ); 553 554 }, threeAttributeMap, attributeTypeMap ); 555 556 } ); 557 558 } ); 559 560 }; 561 562 /** 563 * Texture Transform Extension 564 * 565 * Specification: 566 */ 567 function GLTFTextureTransformExtension( json ) { 568 569 this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM; 570 571 } 572 573 GLTFTextureTransformExtension.prototype.extendTexture = function ( texture, transform ) { 574 575 texture = texture.clone(); 576 577 if ( transform.offset !== undefined ) { 578 579 texture.offset.fromArray( transform.offset ); 580 581 } 582 583 if ( transform.rotation !== undefined ) { 584 585 texture.rotation = transform.rotation; 586 587 } 588 589 if ( transform.scale !== undefined ) { 590 591 texture.repeat.fromArray( transform.scale ); 592 593 } 594 595 if ( transform.texCoord !== undefined ) { 596 597 console.warn( 'THREE.GLTFLoader: Custom UV sets in "' + this.name + '" extension not yet supported.' ); 598 599 } 600 601 texture.needsUpdate = true; 602 603 return texture; 604 605 }; 606 607 /** 608 * Specular-Glossiness Extension 609 * 610 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness 611 */ 612 function GLTFMaterialsPbrSpecularGlossinessExtension() { 613 614 return { 615 616 name: EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS, 617 618 specularGlossinessParams: [ 619 'color', 620 'map', 621 'lightMap', 622 'lightMapIntensity', 623 'aoMap', 624 'aoMapIntensity', 625 'emissive', 626 'emissiveIntensity', 627 'emissiveMap', 628 'bumpMap', 629 'bumpScale', 630 'normalMap', 631 'displacementMap', 632 'displacementScale', 633 'displacementBias', 634 'specularMap', 635 'specular', 636 'glossinessMap', 637 'glossiness', 638 'alphaMap', 639 'envMap', 640 'envMapIntensity', 641 'refractionRatio', 642 ], 643 644 getMaterialType: function () { 645 646 return THREE.ShaderMaterial; 647 648 }, 649 650 extendParams: function ( params, material, parser ) { 651 652 var pbrSpecularGlossiness = material.extensions[ this.name ]; 653 654 var shader = THREE.ShaderLib[ 'standard' ]; 655 656 var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); 657 658 var specularMapParsFragmentChunk = [ 659 '#ifdef USE_SPECULARMAP', 660 ' uniform sampler2D specularMap;', 661 '#endif' 662 ].join( '\n' ); 663 664 var glossinessMapParsFragmentChunk = [ 665 '#ifdef USE_GLOSSINESSMAP', 666 ' uniform sampler2D glossinessMap;', 667 '#endif' 668 ].join( '\n' ); 669 670 var specularMapFragmentChunk = [ 671 'vec3 specularFactor = specular;', 672 '#ifdef USE_SPECULARMAP', 673 ' vec4 texelSpecular = texture2D( specularMap, vUv );', 674 ' texelSpecular = sRGBToLinear( texelSpecular );', 675 ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture', 676 ' specularFactor *= texelSpecular.rgb;', 677 '#endif' 678 ].join( '\n' ); 679 680 var glossinessMapFragmentChunk = [ 681 'float glossinessFactor = glossiness;', 682 '#ifdef USE_GLOSSINESSMAP', 683 ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );', 684 ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture', 685 ' glossinessFactor *= texelGlossiness.a;', 686 '#endif' 687 ].join( '\n' ); 688 689 var lightPhysicalFragmentChunk = [ 690 'PhysicalMaterial material;', 691 'material.diffuseColor = diffuseColor.rgb;', 692 'material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );', 693 'material.specularColor = specularFactor.rgb;', 694 ].join( '\n' ); 695 696 var fragmentShader = shader.fragmentShader 697 .replace( 'uniform float roughness;', 'uniform vec3 specular;' ) 698 .replace( 'uniform float metalness;', 'uniform float glossiness;' ) 699 .replace( '#include <roughnessmap_pars_fragment>', specularMapParsFragmentChunk ) 700 .replace( '#include <metalnessmap_pars_fragment>', glossinessMapParsFragmentChunk ) 701 .replace( '#include <roughnessmap_fragment>', specularMapFragmentChunk ) 702 .replace( '#include <metalnessmap_fragment>', glossinessMapFragmentChunk ) 703 .replace( '#include <lights_physical_fragment>', lightPhysicalFragmentChunk ); 704 705 delete uniforms.roughness; 706 delete uniforms.metalness; 707 delete uniforms.roughnessMap; 708 delete uniforms.metalnessMap; 709 710 uniforms.specular = { value: new THREE.Color().setHex( 0x111111 ) }; 711 uniforms.glossiness = { value: 0.5 }; 712 uniforms.specularMap = { value: null }; 713 uniforms.glossinessMap = { value: null }; 714 715 params.vertexShader = shader.vertexShader; 716 params.fragmentShader = fragmentShader; 717 params.uniforms = uniforms; 718 params.defines = { 'STANDARD': '' }; 719 720 params.color = new THREE.Color( 1.0, 1.0, 1.0 ); 721 params.opacity = 1.0; 722 723 var pending = []; 724 725 if ( Array.isArray( pbrSpecularGlossiness.diffuseFactor ) ) { 726 727 var array = pbrSpecularGlossiness.diffuseFactor; 728 729 params.color.fromArray( array ); 730 params.opacity = array[ 3 ]; 731 732 } 733 734 if ( pbrSpecularGlossiness.diffuseTexture !== undefined ) { 735 736 pending.push( parser.assignTexture( params, 'map', pbrSpecularGlossiness.diffuseTexture ) ); 737 738 } 739 740 params.emissive = new THREE.Color( 0.0, 0.0, 0.0 ); 741 params.glossiness = pbrSpecularGlossiness.glossinessFactor !== undefined ? pbrSpecularGlossiness.glossinessFactor : 1.0; 742 params.specular = new THREE.Color( 1.0, 1.0, 1.0 ); 743 744 if ( Array.isArray( pbrSpecularGlossiness.specularFactor ) ) { 745 746 params.specular.fromArray( pbrSpecularGlossiness.specularFactor ); 747 748 } 749 750 if ( pbrSpecularGlossiness.specularGlossinessTexture !== undefined ) { 751 752 var specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture; 753 pending.push( parser.assignTexture( params, 'glossinessMap', specGlossMapDef ) ); 754 pending.push( parser.assignTexture( params, 'specularMap', specGlossMapDef ) ); 755 756 } 757 758 return Promise.all( pending ); 759 760 }, 761 762 createMaterial: function ( params ) { 763 764 // setup material properties based on MeshStandardMaterial for Specular-Glossiness 765 766 var material = new THREE.ShaderMaterial( { 767 defines: params.defines, 768 vertexShader: params.vertexShader, 769 fragmentShader: params.fragmentShader, 770 uniforms: params.uniforms, 771 fog: true, 772 lights: true, 773 opacity: params.opacity, 774 transparent: params.transparent 775 } ); 776 777 material.isGLTFSpecularGlossinessMaterial = true; 778 779 material.color = params.color; 780 781 material.map = params.map === undefined ? null : params.map; 782 783 material.lightMap = null; 784 material.lightMapIntensity = 1.0; 785 786 material.aoMap = params.aoMap === undefined ? null : params.aoMap; 787 material.aoMapIntensity = 1.0; 788 789 material.emissive = params.emissive; 790 material.emissiveIntensity = 1.0; 791 material.emissiveMap = params.emissiveMap === undefined ? null : params.emissiveMap; 792 793 material.bumpMap = params.bumpMap === undefined ? null : params.bumpMap; 794 material.bumpScale = 1; 795 796 material.normalMap = params.normalMap === undefined ? null : params.normalMap; 797 if ( params.normalScale ) material.normalScale = params.normalScale; 798 799 material.displacementMap = null; 800 material.displacementScale = 1; 801 material.displacementBias = 0; 802 803 material.specularMap = params.specularMap === undefined ? null : params.specularMap; 804 material.specular = params.specular; 805 806 material.glossinessMap = params.glossinessMap === undefined ? null : params.glossinessMap; 807 material.glossiness = params.glossiness; 808 809 material.alphaMap = null; 810 811 material.envMap = params.envMap === undefined ? null : params.envMap; 812 material.envMapIntensity = 1.0; 813 814 material.refractionRatio = 0.98; 815 816 material.extensions.derivatives = true; 817 818 return material; 819 820 }, 821 822 /** 823 * Clones a GLTFSpecularGlossinessMaterial instance. The ShaderMaterial.copy() method can 824 * copy only properties it knows about or inherits, and misses many properties that would 825 * normally be defined by MeshStandardMaterial. 826 * 827 * This method allows GLTFSpecularGlossinessMaterials to be cloned in the process of 828 * loading a glTF model, but cloning later (e.g. by the user) would require these changes 829 * AND also updating `.onBeforeRender` on the parent mesh. 830 * 831 * @param {THREE.ShaderMaterial} source 832 * @return {THREE.ShaderMaterial} 833 */ 834 cloneMaterial: function ( source ) { 835 836 var target = source.clone(); 837 838 target.isGLTFSpecularGlossinessMaterial = true; 839 840 var params = this.specularGlossinessParams; 841 842 for ( var i = 0, il = params.length; i < il; i ++ ) { 843 844 target[ params[ i ] ] = source[ params[ i ] ]; 845 846 } 847 848 return target; 849 850 }, 851 852 // Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer. 853 refreshUniforms: function ( renderer, scene, camera, geometry, material, group ) { 854 855 if ( material.isGLTFSpecularGlossinessMaterial !== true ) { 856 857 return; 858 859 } 860 861 var uniforms = material.uniforms; 862 var defines = material.defines; 863 864 uniforms.opacity.value = material.opacity; 865 866 uniforms.diffuse.value.copy( material.color ); 867 uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); 868 869 uniforms.map.value = material.map; 870 uniforms.specularMap.value = material.specularMap; 871 uniforms.alphaMap.value = material.alphaMap; 872 873 uniforms.lightMap.value = material.lightMap; 874 uniforms.lightMapIntensity.value = material.lightMapIntensity; 875 876 uniforms.aoMap.value = material.aoMap; 877 uniforms.aoMapIntensity.value = material.aoMapIntensity; 878 879 // uv repeat and offset setting priorities 880 // 1. color map 881 // 2. specular map 882 // 3. normal map 883 // 4. bump map 884 // 5. alpha map 885 // 6. emissive map 886 887 var uvScaleMap; 888 889 if ( material.map ) { 890 891 uvScaleMap = material.map; 892 893 } else if ( material.specularMap ) { 894 895 uvScaleMap = material.specularMap; 896 897 } else if ( material.displacementMap ) { 898 899 uvScaleMap = material.displacementMap; 900 901 } else if ( material.normalMap ) { 902 903 uvScaleMap = material.normalMap; 904 905 } else if ( material.bumpMap ) { 906 907 uvScaleMap = material.bumpMap; 908 909 } else if ( material.glossinessMap ) { 910 911 uvScaleMap = material.glossinessMap; 912 913 } else if ( material.alphaMap ) { 914 915 uvScaleMap = material.alphaMap; 916 917 } else if ( material.emissiveMap ) { 918 919 uvScaleMap = material.emissiveMap; 920 921 } 922 923 if ( uvScaleMap !== undefined ) { 924 925 // backwards compatibility 926 if ( uvScaleMap.isWebGLRenderTarget ) { 927 928 uvScaleMap = uvScaleMap.texture; 929 930 } 931 932 if ( uvScaleMap.matrixAutoUpdate === true ) { 933 934 uvScaleMap.updateMatrix(); 935 936 } 937 938 uniforms.uvTransform.value.copy( uvScaleMap.matrix ); 939 940 } 941 942 if ( material.envMap ) { 943 944 uniforms.envMap.value = material.envMap; 945 uniforms.envMapIntensity.value = material.envMapIntensity; 946 947 // don't flip CubeTexture envMaps, flip everything else: 948 // WebGLRenderTargetCube will be flipped for backwards compatibility 949 // WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture 950 // this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future 951 uniforms.flipEnvMap.value = material.envMap.isCubeTexture ? - 1 : 1; 952 953 uniforms.reflectivity.value = material.reflectivity; 954 uniforms.refractionRatio.value = material.refractionRatio; 955 956 uniforms.maxMipLevel.value = renderer.properties.get( material.envMap ).__maxMipLevel; 957 958 } 959 960 uniforms.specular.value.copy( material.specular ); 961 uniforms.glossiness.value = material.glossiness; 962 963 uniforms.glossinessMap.value = material.glossinessMap; 964 965 uniforms.emissiveMap.value = material.emissiveMap; 966 uniforms.bumpMap.value = material.bumpMap; 967 uniforms.normalMap.value = material.normalMap; 968 969 uniforms.displacementMap.value = material.displacementMap; 970 uniforms.displacementScale.value = material.displacementScale; 971 uniforms.displacementBias.value = material.displacementBias; 972 973 if ( uniforms.glossinessMap.value !== null && defines.USE_GLOSSINESSMAP === undefined ) { 974 975 defines.USE_GLOSSINESSMAP = ''; 976 // set USE_ROUGHNESSMAP to enable vUv 977 defines.USE_ROUGHNESSMAP = ''; 978 979 } 980 981 if ( uniforms.glossinessMap.value === null && defines.USE_GLOSSINESSMAP !== undefined ) { 982 983 delete defines.USE_GLOSSINESSMAP; 984 delete defines.USE_ROUGHNESSMAP; 985 986 } 987 988 } 989 990 }; 991 992 } 993
994 /*********************************/ 995 /********** INTERPOLATION ********/ 996 /*********************************/ 997 998 // Spline Interpolation 999 // Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation 1000 function GLTFCubicSplineInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { 1001 1002 THREE.Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); 1003 1004 } 1005 1006 GLTFCubicSplineInterpolant.prototype = Object.create( THREE.Interpolant.prototype ); 1007 GLTFCubicSplineInterpolant.prototype.constructor = GLTFCubicSplineInterpolant; 1008 1009 GLTFCubicSplineInterpolant.prototype.copySampleValue_ = function ( index ) { 1010 1011 // Copies a sample value to the result buffer. See description of glTF 1012 // CUBICSPLINE values layout in interpolate_() function below. 1013 1014 var result = this.resultBuffer, 1015 values = this.sampleValues, 1016 valueSize = this.valueSize, 1017 offset = index * valueSize * 3 + valueSize; 1018 1019 for ( var i = 0; i !== valueSize; i ++ ) { 1020 1021 result[ i ] = values[ offset + i ]; 1022 1023 } 1024 1025 return result; 1026 1027 }; 1028 1029 GLTFCubicSplineInterpolant.prototype.beforeStart_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_; 1030 1031 GLTFCubicSplineInterpolant.prototype.afterEnd_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_; 1032 1033 GLTFCubicSplineInterpolant.prototype.interpolate_ = function ( i1, t0, t, t1 ) { 1034 1035 var result = this.resultBuffer; 1036 var values = this.sampleValues; 1037 var stride = this.valueSize; 1038 1039 var stride2 = stride * 2; 1040 var stride3 = stride * 3; 1041 1042 var td = t1 - t0; 1043 1044 var p = ( t - t0 ) / td; 1045 var pp = p * p; 1046 var ppp = pp * p; 1047 1048 var offset1 = i1 * stride3; 1049 var offset0 = offset1 - stride3; 1050 1051 var s2 = - 2 * ppp + 3 * pp; 1052 var s3 = ppp - pp; 1053 var s0 = 1 - s2; 1054 var s1 = s3 - pp + p; 1055 1056 // Layout of keyframe output values for CUBICSPLINE animations: 1057 // [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ] 1058 for ( var i = 0; i !== stride; i ++ ) { 1059 1060 var p0 = values[ offset0 + i + stride ]; // splineVertex_k 1061 var m0 = values[ offset0 + i + stride2 ] * td; // outTangent_k * (t_k+1 - t_k) 1062 var p1 = values[ offset1 + i + stride ]; // splineVertex_k+1 1063 var m1 = values[ offset1 + i ] * td; // inTangent_k+1 * (t_k+1 - t_k) 1064 1065 result[ i ] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1; 1066 1067 } 1068 1069 return result; 1070 1071 }; 1072 1073 /*********************************/ 1074 /********** INTERNALS ************/ 1075 /*********************************/ 1076 1077 /* CONSTANTS */ 1078 1079 var WEBGL_CONSTANTS = { 1080 FLOAT: 5126, 1081 //FLOAT_MAT2: 35674, 1082 FLOAT_MAT3: 35675, 1083 FLOAT_MAT4: 35676, 1084 FLOAT_VEC2: 35664, 1085 FLOAT_VEC3: 35665, 1086 FLOAT_VEC4: 35666, 1087 LINEAR: 9729, 1088 REPEAT: 10497, 1089 SAMPLER_2D: 35678, 1090 POINTS: 0, 1091 LINES: 1, 1092 LINE_LOOP: 2, 1093 LINE_STRIP: 3, 1094 TRIANGLES: 4, 1095 TRIANGLE_STRIP: 5, 1096 TRIANGLE_FAN: 6, 1097 UNSIGNED_BYTE: 5121, 1098 UNSIGNED_SHORT: 5123 1099 }; 1100 1101 var WEBGL_TYPE = { 1102 5126: Number, 1103 //35674: THREE.Matrix2, 1104 35675: THREE.Matrix3, 1105 35676: THREE.Matrix4, 1106 35664: THREE.Vector2, 1107 35665: THREE.Vector3, 1108 35666: THREE.Vector4, 1109 35678: THREE.Texture 1110 }; 1111 1112 var WEBGL_COMPONENT_TYPES = { 1113 5120: Int8Array, 1114 5121: Uint8Array, 1115 5122: Int16Array, 1116 5123: Uint16Array, 1117 5125: Uint32Array, 1118 5126: Float32Array 1119 }; 1120 1121 var WEBGL_FILTERS = { 1122 9728: THREE.NearestFilter, 1123 9729: THREE.LinearFilter, 1124 9984: THREE.NearestMipMapNearestFilter, 1125 9985: THREE.LinearMipMapNearestFilter, 1126 9986: THREE.NearestMipMapLinearFilter, 1127 9987: THREE.LinearMipMapLinearFilter 1128 }; 1129 1130 var WEBGL_WRAPPINGS = { 1131 33071: THREE.ClampToEdgeWrapping, 1132 33648: THREE.MirroredRepeatWrapping, 1133 10497: THREE.RepeatWrapping 1134 }; 1135 1136 var WEBGL_SIDES = { 1137 1028: THREE.BackSide, // Culling front 1138 1029: THREE.FrontSide // Culling back 1139 //1032: THREE.NoSide // Culling front and back, what to do? 1140 }; 1141 1142 var WEBGL_DEPTH_FUNCS = { 1143 512: THREE.NeverDepth, 1144 513: THREE.LessDepth, 1145 514: THREE.EqualDepth, 1146 515: THREE.LessEqualDepth, 1147 516: THREE.GreaterEqualDepth, 1148 517: THREE.NotEqualDepth, 1149 518: THREE.GreaterEqualDepth, 1150 519: THREE.AlwaysDepth 1151 }; 1152 1153 var WEBGL_BLEND_EQUATIONS = { 1154 32774: THREE.AddEquation, 1155 32778: THREE.SubtractEquation, 1156 32779: THREE.ReverseSubtractEquation 1157 }; 1158 1159 var WEBGL_BLEND_FUNCS = {
1160 0: THREE.ZeroFactor, 1161 1: THREE.OneFactor, 1162 768: THREE.SrcColorFactor, 1163 769: THREE.OneMinusSrcColorFactor, 1164 770: THREE.SrcAlphaFactor, 1165 771: THREE.OneMinusSrcAlphaFactor, 1166 772: THREE.DstAlphaFactor, 1167 773: THREE.OneMinusDstAlphaFactor, 1168 774: THREE.DstColorFactor, 1169 775: THREE.OneMinusDstColorFactor, 1170 776: THREE.SrcAlphaSaturateFactor 1171 // The followings are not supported by Three.js yet 1172 //32769: CONSTANT_COLOR, 1173 //32770: ONE_MINUS_CONSTANT_COLOR, 1174 //32771: CONSTANT_ALPHA, 1175 //32772: ONE_MINUS_CONSTANT_COLOR 1176 }; 1177 1178 var WEBGL_TYPE_SIZES = { 1179 'SCALAR': 1, 1180 'VEC2': 2, 1181 'VEC3': 3, 1182 'VEC4': 4, 1183 'MAT2': 4, 1184 'MAT3': 9, 1185 'MAT4': 16 1186 }; 1187 1188 var ATTRIBUTES = { 1189 POSITION: 'position', 1190 NORMAL: 'normal', 1191 TANGENT: 'tangent', 1192 TEXCOORD_0: 'uv', 1193 TEXCOORD_1: 'uv2', 1194 COLOR_0: 'color', 1195 WEIGHTS_0: 'skinWeight', 1196 JOINTS_0: 'skinIndex', 1197 }; 1198 1199 var PATH_PROPERTIES = { 1200 scale: 'scale', 1201 translation: 'position', 1202 rotation: 'quaternion', 1203 weights: 'morphTargetInfluences' 1204 }; 1205 1206 var INTERPOLATION = { 1207 CUBICSPLINE: undefined, // We use a custom interpolant (GLTFCubicSplineInterpolation) for CUBICSPLINE tracks. Each 1208 // keyframe track will be initialized with a default interpolation type, then modified. 1209 LINEAR: THREE.InterpolateLinear, 1210 STEP: THREE.InterpolateDiscrete 1211 }; 1212 1213 var STATES_ENABLES = { 1214 2884: 'CULL_FACE', 1215 2929: 'DEPTH_TEST', 1216 3042: 'BLEND', 1217 3089: 'SCISSOR_TEST', 1218 32823: 'POLYGON_OFFSET_FILL', 1219 32926: 'SAMPLE_ALPHA_TO_COVERAGE' 1220 }; 1221 1222 var ALPHA_MODES = { 1223 OPAQUE: 'OPAQUE', 1224 MASK: 'MASK', 1225 BLEND: 'BLEND' 1226 }; 1227 1228 var MIME_TYPE_FORMATS = { 1229 'image/png': THREE.RGBAFormat, 1230 'image/jpeg': THREE.RGBFormat 1231 }; 1232 1233 /* UTILITY FUNCTIONS */ 1234 1235 function resolveURL( url, path ) { 1236 1237 // Invalid URL 1238 if ( typeof url !== 'string' || url === '' ) return ''; 1239 1240 // Absolute URL http://,https://,// 1241 if ( /^(https?:)?\/\//i.test( url ) ) return url; 1242 1243 // Data URI 1244 if ( /^data:.*,.*$/i.test( url ) ) return url; 1245 1246 // Blob URL 1247 if ( /^blob:.*$/i.test( url ) ) return url; 1248 1249 // Relative URL 1250 return path + url; 1251 1252 } 1253 1254 var defaultMaterial; 1255 1256 /** 1257 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material 1258 */ 1259 function createDefaultMaterial() { 1260 1261 defaultMaterial = defaultMaterial || new THREE.MeshStandardMaterial( { 1262 color: 0xFFFFFF, 1263 emissive: 0x000000, 1264 metalness: 1, 1265 roughness: 1, 1266 transparent: false, 1267 depthTest: true, 1268 side: THREE.FrontSide 1269 } ); 1270 1271 return defaultMaterial; 1272 1273 } 1274 1275 function addUnknownExtensionsToUserData( knownExtensions, object, objectDef ) { 1276 1277 // Add unknown glTF extensions to an object's userData. 1278 1279 for ( var name in objectDef.extensions ) { 1280 1281 if ( knownExtensions[ name ] === undefined ) { 1282 1283 object.userData.gltfExtensions = object.userData.gltfExtensions || {}; 1284 object.userData.gltfExtensions[ name ] = objectDef.extensions[ name ]; 1285 1286 } 1287 1288 } 1289 1290 } 1291 1292 /** 1293 * @param {THREE.Object3D|THREE.Material|THREE.BufferGeometry} object 1294 * @param {GLTF.definition} gltfDef 1295 */ 1296 function assignExtrasToUserData( object, gltfDef ) { 1297 1298 if ( gltfDef.extras !== undefined ) { 1299 1300 if ( typeof gltfDef.extras === 'object' ) { 1301 1302 object.userData = gltfDef.extras; 1303 1304 } else { 1305 1306 console.warn( 'THREE.GLTFLoader: Ignoring primitive type .extras, ' + gltfDef.extras ); 1307 1308 } 1309 1310 } 1311 1312 } 1313 1314 /** 1315 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets 1316 * 1317 * @param {THREE.BufferGeometry} geometry 1318 * @param {Array<GLTF.Target>} targets 1319 * @param {GLTFParser} parser 1320 * @return {Promise<THREE.BufferGeometry>} 1321 */ 1322 function addMorphTargets( geometry, targets, parser ) { 1323 1324 var hasMorphPosition = false; 1325 var hasMorphNormal = false; 1326 1327 for ( var i = 0, il = targets.length; i < il; i ++ ) { 1328 1329 var target = targets[ i ]; 1330 1331 if ( target.POSITION !== undefined ) hasMorphPosition = true; 1332 if ( target.NORMAL !== undefined ) hasMorphNormal = true; 1333 1334 if ( hasMorphPosition && hasMorphNormal ) break; 1335 1336 } 1337 1338 if ( ! hasMorphPosition && ! hasMorphNormal ) return Promise.resolve( geometry ); 1339
1340 var pendingPositionAccessors = []; 1341 var pendingNormalAccessors = []; 1342 1343 for ( var i = 0, il = targets.length; i < il; i ++ ) { 1344 1345 var target = targets[ i ]; 1346 1347 if ( hasMorphPosition ) { 1348 1349 var pendingAccessor = target.POSITION !== undefined 1350 ? parser.getDependency( 'accessor', target.POSITION ) 1351 : geometry.attributes.position; 1352 1353 pendingPositionAccessors.push( pendingAccessor ); 1354 1355 } 1356 1357 if ( hasMorphNormal ) { 1358 1359 var pendingAccessor = target.NORMAL !== undefined 1360 ? parser.getDependency( 'accessor', target.NORMAL ) 1361 : geometry.attributes.normal; 1362 1363 pendingNormalAccessors.push( pendingAccessor ); 1364 1365 } 1366 1367 } 1368 1369 return Promise.all( [ 1370 Promise.all( pendingPositionAccessors ), 1371 Promise.all( pendingNormalAccessors ) 1372 ] ).then( function ( accessors ) { 1373 1374 var morphPositions = accessors[ 0 ]; 1375 var morphNormals = accessors[ 1 ]; 1376 1377 // Clone morph target accessors before modifying them. 1378 1379 for ( var i = 0, il = morphPositions.length; i < il; i ++ ) { 1380 1381 if ( geometry.attributes.position === morphPositions[ i ] ) continue; 1382 1383 morphPositions[ i ] = cloneBufferAttribute( morphPositions[ i ] ); 1384 1385 } 1386 1387 for ( var i = 0, il = morphNormals.length; i < il; i ++ ) { 1388 1389 if ( geometry.attributes.normal === morphNormals[ i ] ) continue; 1390 1391 morphNormals[ i ] = cloneBufferAttribute( morphNormals[ i ] ); 1392 1393 } 1394 1395 for ( var i = 0, il = targets.length; i < il; i ++ ) { 1396 1397 var target = targets[ i ]; 1398 var attributeName = 'morphTarget' + i; 1399 1400 if ( hasMorphPosition ) { 1401 1402 // Three.js morph position is absolute value. The formula is 1403 // basePosition 1404 // + weight0 * ( morphPosition0 - basePosition ) 1405 // + weight1 * ( morphPosition1 - basePosition ) 1406 // ... 1407 // while the glTF one is relative 1408 // basePosition 1409 // + weight0 * glTFmorphPosition0 1410 // + weight1 * glTFmorphPosition1 1411 // ... 1412 // then we need to convert from relative to absolute here. 1413 1414 if ( target.POSITION !== undefined ) { 1415 1416 var positionAttribute = morphPositions[ i ]; 1417 positionAttribute.name = attributeName; 1418 1419 var position = geometry.attributes.position; 1420 1421 for ( var j = 0, jl = positionAttribute.count; j < jl; j ++ ) { 1422 1423 positionAttribute.setXYZ( 1424 j, 1425 positionAttribute.getX( j ) + position.getX( j ), 1426 positionAttribute.getY( j ) + position.getY( j ), 1427 positionAttribute.getZ( j ) + position.getZ( j ) 1428 ); 1429 1430 } 1431 1432 } 1433 1434 } 1435 1436 if ( hasMorphNormal ) { 1437 1438 // see target.POSITION's comment 1439 1440 if ( target.NORMAL !== undefined ) { 1441 1442 var normalAttribute = morphNormals[ i ]; 1443 normalAttribute.name = attributeName; 1444 1445 var normal = geometry.attributes.normal; 1446 1447 for ( var j = 0, jl = normalAttribute.count; j < jl; j ++ ) { 1448 1449 normalAttribute.setXYZ( 1450 j, 1451 normalAttribute.getX( j ) + normal.getX( j ), 1452 normalAttribute.getY( j ) + normal.getY( j ), 1453 normalAttribute.getZ( j ) + normal.getZ( j ) 1454 ); 1455 1456 } 1457 1458 } 1459 1460 } 1461 1462 } 1463 1464 if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions; 1465 if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals; 1466 1467 return geometry; 1468 1469 } ); 1470 1471 } 1472 1473 /** 1474 * @param {THREE.Mesh} mesh 1475 * @param {GLTF.Mesh} meshDef 1476 */ 1477 function updateMorphTargets( mesh, meshDef ) { 1478 1479 mesh.updateMorphTargets(); 1480 1481 if ( meshDef.weights !== undefined ) { 1482 1483 for ( var i = 0, il = meshDef.weights.length; i < il; i ++ ) { 1484 1485 mesh.morphTargetInfluences[ i ] = meshDef.weights[ i ]; 1486 1487 } 1488 1489 } 1490 1491 // .extras has user-defined data, so check that .extras.targetNames is an array. 1492 if ( meshDef.extras && Array.isArray( meshDef.extras.targetNames ) ) { 1493 1494 var targetNames = meshDef.extras.targetNames; 1495 1496 if ( mesh.morphTargetInfluences.length === targetNames.length ) { 1497 1498 mesh.morphTargetDictionary = {}; 1499 1500 for ( var i = 0, il = targetNames.length; i < il; i ++ ) { 1501 1502 mesh.morphTargetDictionary[ targetNames[ i ] ] = i; 1503 1504 } 1505 1506 } else { 1507 1508 console.warn( 'THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.' ); 1509 1510 } 1511 1512 } 1513 1514 } 1515 function isObjectEqual( a, b ) { 1516 1517 if ( Object.keys( a ).length !== Object.keys( b ).length ) return false;
1518 1519 for ( var key in a ) { 1520 1521 if ( a[ key ] !== b[ key ] ) return false; 1522 1523 } 1524 1525 return true; 1526 1527 } 1528 1529 function createPrimitiveKey( primitiveDef ) { 1530 1531 var dracoExtension = primitiveDef.extensions && primitiveDef.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ]; 1532 var geometryKey; 1533 1534 if ( dracoExtension ) { 1535 1536 geometryKey = 'draco:' + dracoExtension.bufferView 1537 + ':' + dracoExtension.indices 1538 + ':' + createAttributesKey( dracoExtension.attributes ); 1539 1540 } else { 1541 1542 geometryKey = primitiveDef.indices + ':' + createAttributesKey( primitiveDef.attributes ) + ':' + primitiveDef.mode; 1543 1544 } 1545 1546 return geometryKey; 1547 1548 } 1549 1550 function createAttributesKey( attributes ) { 1551 1552 var attributesKey = ''; 1553 1554 var keys = Object.keys( attributes ).sort(); 1555 1556 for ( var i = 0, il = keys.length; i < il; i ++ ) { 1557 1558 attributesKey += keys[ i ] + ':' + attributes[ keys[ i ] ] + ';'; 1559 1560 } 1561 1562 return attributesKey; 1563 1564 } 1565 1566 function cloneBufferAttribute( attribute ) { 1567 1568 if ( attribute.isInterleavedBufferAttribute ) { 1569 1570 var count = attribute.count; 1571 var itemSize = attribute.itemSize; 1572 var array = attribute.array.slice( 0, count * itemSize ); 1573 1574 for ( var i = 0, j = 0; i < count; ++ i ) { 1575 1576 array[ j ++ ] = attribute.getX( i ); 1577 if ( itemSize >= 2 ) array[ j ++ ] = attribute.getY( i ); 1578 if ( itemSize >= 3 ) array[ j ++ ] = attribute.getZ( i ); 1579 if ( itemSize >= 4 ) array[ j ++ ] = attribute.getW( i ); 1580 1581 } 1582 1583 return new THREE.BufferAttribute( array, itemSize, attribute.normalized ); 1584 1585 } 1586 1587 return attribute.clone(); 1588 1589 } 1590 1591 /* GLTF PARSER */ 1592 1593 function GLTFParser( json, extensions, options ) { 1594 1595 this.json = json || {}; 1596 this.extensions = extensions || {}; 1597 this.options = options || {}; 1598 1599 // loader object cache 1600 this.cache = new GLTFRegistry(); 1601 1602 // BufferGeometry caching 1603 this.primitiveCache = {}; 1604 1605 this.textureLoader = new THREE.TextureLoader( this.options.manager ); 1606 this.textureLoader.setCrossOrigin( this.options.crossOrigin ); 1607 1608 this.fileLoader = new THREE.FileLoader( this.options.manager ); 1609 this.fileLoader.setResponseType( 'arraybuffer' ); 1610 1611 } 1612 1613 GLTFParser.prototype.parse = function ( onLoad, onError ) { 1614 1615 var parser = this; 1616 var json = this.json; 1617 var extensions = this.extensions; 1618 1619 // Clear the loader cache 1620 this.cache.removeAll(); 1621 1622 // Mark the special nodes/meshes in json for efficient parse 1623 this.markDefs(); 1624 1625 Promise.all( [ 1626 1627 this.getDependencies( 'scene' ), 1628 this.getDependencies( 'animation' ), 1629 this.getDependencies( 'camera' ), 1630 1631 ] ).then( function ( dependencies ) { 1632 1633 var result = { 1634 scene: dependencies[ 0 ][ json.scene || 0 ], 1635 scenes: dependencies[ 0 ], 1636 animations: dependencies[ 1 ], 1637 cameras: dependencies[ 2 ], 1638 asset: json.asset, 1639 parser: parser, 1640 userData: {} 1641 }; 1642 1643 addUnknownExtensionsToUserData( extensions, result, json ); 1644 1645 onLoad( result ); 1646 1647 } ).catch( onError ); 1648 1649 }; 1650 1651 /** 1652 * Marks the special nodes/meshes in json for efficient parse. 1653 */ 1654 GLTFParser.prototype.markDefs = function () { 1655 1656 var nodeDefs = this.json.nodes || []; 1657 var skinDefs = this.json.skins || []; 1658 var meshDefs = this.json.meshes || []; 1659 1660 var meshReferences = {}; 1661 var meshUses = {}; 1662 1663 // Nothing in the node definition indicates whether it is a Bone or an 1664 // Object3D. Use the skins' joint references to mark bones. 1665 for ( var skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex ++ ) { 1666 1667 var joints = skinDefs[ skinIndex ].joints; 1668 1669 for ( var i = 0, il = joints.length; i < il; i ++ ) { 1670 1671 nodeDefs[ joints[ i ] ].isBone = true; 1672 1673 } 1674 1675 } 1676 1677 // Meshes can (and should) be reused by multiple nodes in a glTF asset. To 1678 // avoid having more than one THREE.Mesh with the same name, count 1679 // references and rename instances below. 1680 // 1681 // Example: CesiumMilkTruck sample model reuses "Wheel" meshes. 1682 for ( var nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex ++ ) { 1683 1684 var nodeDef = nodeDefs[ nodeIndex ]; 1685 1686 if ( nodeDef.mesh !== undefined ) { 1687 1688 if ( meshReferences[ nodeDef.mesh ] === undefined ) { 1689 1690 meshReferences[ nodeDef.mesh ] = meshUses[ nodeDef.mesh ] = 0; 1691 1692 } 1693 1694 meshReferences[ nodeDef.mesh ] ++; 1695 1696 // Nothing in the mesh definition indicates whether it is 1697 // a SkinnedMesh or Mesh. Use the node's mesh reference 1698 // to mark SkinnedMesh if node has skin. 1699 if ( nodeDef.skin !== undefined ) { 1700 1701 meshDefs[ nodeDef.mesh ].isSkinnedMesh = true; 1702 1703 } 1704 1705 } 1706 1707 } 1708 1709 this.json.meshReferences = meshReferences; 1710 this.json.meshUses = meshUses; 1711 1712 }; 1713 1714 /** 1715 * Requests the specified dependency asynchronously, with caching. 1716 * @param {string} type 1717 * @param {number} index 1718 * @return {Promise<THREE.Object3D|THREE.Material|THREE.Texture|THREE.AnimationClip|ArrayBuffer|Object>} 1719 */ 1720 GLTFParser.prototype.getDependency = function ( type, index ) { 1721 1722 var cacheKey = type + ':' + index; 1723 var dependency = this.cache.get( cacheKey ); 1724 1725 if ( ! dependency ) { 1726 1727 switch ( type ) { 1728 1729 case 'scene': 1730 dependency = this.loadScene( index ); 1731 break; 1732
1733 case 'node': 1734 dependency = this.loadNode( index ); 1735 break; 1736 1737 case 'mesh': 1738 dependency = this.loadMesh( index ); 1739 break; 1740 1741 case 'accessor': 1742 dependency = this.loadAccessor( index ); 1743 break; 1744 1745 case 'bufferView': 1746 dependency = this.loadBufferView( index ); 1747 break; 1748 1749 case 'buffer': 1750 dependency = this.loadBuffer( index ); 1751 break; 1752 1753 case 'material': 1754 dependency = this.loadMaterial( index ); 1755 break; 1756 1757 case 'texture': 1758 dependency = this.loadTexture( index ); 1759 break; 1760 1761 case 'skin': 1762 dependency = this.loadSkin( index ); 1763 break; 1764 1765 case 'animation': 1766 dependency = this.loadAnimation( index ); 1767 break; 1768 1769 case 'camera': 1770 dependency = this.loadCamera( index ); 1771 break; 1772 1773 case 'light': 1774 dependency = this.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].loadLight( index ); 1775 break; 1776 1777 default: 1778 throw new Error( 'Unknown type: ' + type ); 1779 1780 } 1781 1782 this.cache.add( cacheKey, dependency ); 1783 1784 } 1785 1786 return dependency; 1787 1788 }; 1789 1790 /** 1791 * Requests all dependencies of the specified type asynchronously, with caching. 1792 * @param {string} type 1793 * @return {Promise<Array<Object>>} 1794 */ 1795 GLTFParser.prototype.getDependencies = function ( type ) { 1796 1797 var dependencies = this.cache.get( type ); 1798 1799 if ( ! dependencies ) { 1800 1801 var parser = this; 1802 var defs = this.json[ type + ( type === 'mesh' ? 'es' : 's' ) ] || []; 1803 1804 dependencies = Promise.all( defs.map( function ( def, index ) { 1805 1806 return parser.getDependency( type, index ); 1807 1808 } ) ); 1809 1810 this.cache.add( type, dependencies ); 1811 1812 } 1813 1814 return dependencies; 1815 1816 }; 1817 1818 /** 1819 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views 1820 * @param {number} bufferIndex 1821 * @return {Promise<ArrayBuffer>} 1822 */ 1823 GLTFParser.prototype.loadBuffer = function ( bufferIndex ) { 1824 1825 var bufferDef = this.json.buffers[ bufferIndex ]; 1826 var loader = this.fileLoader; 1827 1828 if ( bufferDef.type && bufferDef.type !== 'arraybuffer' ) { 1829 1830 throw new Error( 'THREE.GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.' ); 1831 1832 } 1833 1834 // If present, GLB container is required to be the first buffer. 1835 if ( bufferDef.uri === undefined && bufferIndex === 0 ) { 1836 1837 return Promise.resolve( this.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body ); 1838 1839 } 1840 1841 var options = this.options; 1842 1843 return new Promise( function ( resolve, reject ) { 1844 1845 loader.load( resolveURL( bufferDef.uri, options.path ), resolve, undefined, function () { 1846 1847 reject( new Error( 'THREE.GLTFLoader: Failed to load buffer "' + bufferDef.uri + '".' ) ); 1848 1849 } ); 1850 1851 } ); 1852 1853 }; 1854 1855 /** 1856 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views 1857 * @param {number} bufferViewIndex 1858 * @return {Promise<ArrayBuffer>} 1859 */ 1860 GLTFParser.prototype.loadBufferView = function ( bufferViewIndex ) { 1861 1862 var bufferViewDef = this.json.bufferViews[ bufferViewIndex ]; 1863 1864 return this.getDependency( 'buffer', bufferViewDef.buffer ).then( function ( buffer ) { 1865 1866 var byteLength = bufferViewDef.byteLength || 0; 1867 var byteOffset = bufferViewDef.byteOffset || 0; 1868 return buffer.slice( byteOffset, byteOffset + byteLength ); 1869 1870 } ); 1871 1872 }; 1873 1874 /** 1875 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors 1876 * @param {number} accessorIndex 1877 * @return {Promise<THREE.BufferAttribute|THREE.InterleavedBufferAttribute>} 1878 */ 1879 GLTFParser.prototype.loadAccessor = function ( accessorIndex ) { 1880 1881 var parser = this; 1882 var json = this.json; 1883 1884 var accessorDef = this.json.accessors[ accessorIndex ]; 1885 1886 if ( accessorDef.bufferView === undefined && accessorDef.sparse === undefined ) { 1887 1888 // Ignore empty accessors, which may be used to declare runtime 1889 // information about attributes coming from another source (e.g. Draco 1890 // compression extension). 1891 return Promise.resolve( null ); 1892 1893 } 1894 1895 var pendingBufferViews = []; 1896 1897 if ( accessorDef.bufferView !== undefined ) { 1898 1899 pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.bufferView ) ); 1900 1901 } else { 1902 1903 pendingBufferViews.push( null ); 1904 1905 } 1906 1907 if ( accessorDef.sparse !== undefined ) { 1908 1909 pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.indices.bufferView ) ); 1910 pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.values.bufferView ) ); 1911 1912 } 1913 1914 return Promise.all( pendingBufferViews ).then( function ( bufferViews ) { 1915 1916 var bufferView = bufferViews[ 0 ]; 1917 1918 var itemSize = WEBGL_TYPE_SIZES[ accessorDef.type ]; 1919 var TypedArray = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ]; 1920 1921 // For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12. 1922 var elementBytes = TypedArray.BYTES_PER_ELEMENT; 1923 var itemBytes = elementBytes * itemSize; 1924 var byteOffset = accessorDef.byteOffset || 0; 1925 var byteStride = accessorDef.bufferView !== undefined ? json.bufferViews[ accessorDef.bufferView ].byteStride : undefined; 1926 var normalized = accessorDef.normalized === true; 1927 var array, bufferAttribute; 1928 1929 // The buffer is not interleaved if the stride is the item size in bytes. 1930 if ( byteStride && byteStride !== itemBytes ) { 1931 1932 var ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType; 1933 var ib = parser.cache.get( ibCacheKey ); 1934 1935 if ( ! ib ) { 1936 1937 // Use the full buffer if it's interleaved. 1938 array = new TypedArray( bufferView ); 1939 1940 // Integer parameters to IB/IBA are in array elements, not bytes. 1941 ib = new THREE.InterleavedBuffer( array, byteStride / elementBytes ); 1942 1943 parser.cache.add( ibCacheKey, ib ); 1944 1945 } 1946 1947 bufferAttribute = new THREE.InterleavedBufferAttribute( ib, itemSize, byteOffset / elementBytes, normalized ); 1948 1949 } else { 1950 1951 if ( bufferView === null ) { 1952 1953 array = new TypedArray( accessorDef.count * itemSize ); 1954 1955 } else { 1956
1957 array = new TypedArray( bufferView, byteOffset, accessorDef.count * itemSize ); 1958 1959 } 1960 1961 bufferAttribute = new THREE.BufferAttribute( array, itemSize, normalized ); 1962 1963 } 1964 1965 // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessors 1966 if ( accessorDef.sparse !== undefined ) { 1967 1968 var itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR; 1969 var TypedArrayIndices = WEBGL_COMPONENT_TYPES[ accessorDef.sparse.indices.componentType ]; 1970 1971 var byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0; 1972 var byteOffsetValues = accessorDef.sparse.values.byteOffset || 0; 1973 1974 var sparseIndices = new TypedArrayIndices( bufferViews[ 1 ], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices ); 1975 var sparseValues = new TypedArray( bufferViews[ 2 ], byteOffsetValues, accessorDef.sparse.count * itemSize ); 1976 1977 if ( bufferView !== null ) { 1978 1979 // Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes. 1980 bufferAttribute.setArray( bufferAttribute.array.slice() ); 1981 1982 } 1983 1984 for ( var i = 0, il = sparseIndices.length; i < il; i ++ ) { 1985 1986 var index = sparseIndices[ i ]; 1987 1988 bufferAttribute.setX( index, sparseValues[ i * itemSize ] ); 1989 if ( itemSize >= 2 ) bufferAttribute.setY( index, sparseValues[ i * itemSize + 1 ] ); 1990 if ( itemSize >= 3 ) bufferAttribute.setZ( index, sparseValues[ i * itemSize + 2 ] ); 1991 if ( itemSize >= 4 ) bufferAttribute.setW( index, sparseValues[ i * itemSize + 3 ] ); 1992 if ( itemSize >= 5 ) throw new Error( 'THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.' ); 1993 1994 } 1995 1996 } 1997 1998 return bufferAttribute; 1999 2000 } ); 2001 2002 }; 2003 2004 /** 2005 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures 2006 * @param {number} textureIndex 2007 * @return {Promise<THREE.Texture>} 2008 */ 2009 GLTFParser.prototype.loadTexture = function ( textureIndex ) { 2010 2011 var parser = this; 2012 var json = this.json; 2013 var options = this.options; 2014 var textureLoader = this.textureLoader; 2015 2016 var URL = window.URL || window.webkitURL; 2017 2018 var textureDef = json.textures[ textureIndex ]; 2019 2020 var textureExtensions = textureDef.extensions || {}; 2021 2022 var source; 2023 2024 if ( textureExtensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] ) { 2025 2026 source = json.images[ textureExtensions[ EXTENSIONS.MSFT_TEXTURE_DDS ].source ]; 2027 2028 } else { 2029 2030 source = json.images[ textureDef.source ]; 2031 2032 } 2033 2034 var sourceURI = source.uri; 2035 var isObjectURL = false; 2036 2037 if ( source.bufferView !== undefined ) { 2038 2039 // Load binary image data from bufferView, if provided. 2040 2041 sourceURI = parser.getDependency( 'bufferView', source.bufferView ).then( function ( bufferView ) { 2042 2043 isObjectURL = true; 2044 var blob = new Blob( [ bufferView ], { type: source.mimeType } ); 2045 sourceURI = URL.createObjectURL( blob ); 2046 return sourceURI; 2047 2048 } ); 2049 2050 } 2051 2052 return Promise.resolve( sourceURI ).then( function ( sourceURI ) { 2053 2054 // Load Texture resource. 2055 2056 var loader = THREE.Loader.Handlers.get( sourceURI ); 2057 2058 if ( ! loader ) { 2059 2060 loader = textureExtensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] 2061 ? parser.extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ].ddsLoader 2062 : textureLoader; 2063 2064 } 2065 2066 return new Promise( function ( resolve, reject ) { 2067 2068 loader.load( resolveURL( sourceURI, options.path ), resolve, undefined, reject ); 2069 2070 } ); 2071 2072 } ).then( function ( texture ) { 2073 2074 // Clean up resources and configure Texture. 2075 2076 if ( isObjectURL === true ) { 2077 2078 URL.revokeObjectURL( sourceURI ); 2079 2080 } 2081 2082 texture.flipY = false; 2083 2084 if ( textureDef.name !== undefined ) texture.name = textureDef.name; 2085 2086 // Ignore unknown mime types, like DDS files. 2087 if ( source.mimeType in MIME_TYPE_FORMATS ) { 2088 2089 texture.format = MIME_TYPE_FORMATS[ source.mimeType ]; 2090 2091 } 2092 2093 var samplers = json.samplers || {}; 2094 var sampler = samplers[ textureDef.sampler ] || {}; 2095 2096 texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || THREE.LinearFilter; 2097 texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || THREE.LinearMipMapLinearFilter; 2098 texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || THREE.RepeatWrapping; 2099 texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || THREE.RepeatWrapping; 2100 2101 return texture; 2102 2103 } ); 2104 2105 }; 2106 2107 /** 2108 * Asynchronously assigns a texture to the given material parameters. 2109 * @param {Object} materialParams 2110 * @param {string} mapName 2111 * @param {Object} mapDef 2112 * @return {Promise} 2113 */ 2114 GLTFParser.prototype.assignTexture = function ( materialParams, mapName, mapDef ) { 2115 2116 var parser = this; 2117 2118 return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) { 2119 2120 switch ( mapName ) { 2121 2122 case 'aoMap':
2123 case 'emissiveMap': 2124 case 'metalnessMap': 2125 case 'normalMap': 2126 case 'roughnessMap': 2127 texture.format = THREE.RGBFormat; 2128 break; 2129 2130 } 2131 2132 if ( parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] ) { 2133 2134 var transform = mapDef.extensions !== undefined ? mapDef.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] : undefined; 2135 2136 if ( transform ) { 2137 2138 texture = parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ].extendTexture( texture, transform ); 2139 2140 } 2141 2142 } 2143 2144 materialParams[ mapName ] = texture; 2145 2146 } ); 2147 2148 }; 2149 2150 /** 2151 * Assigns final material to a Mesh, Line, or Points instance. The instance 2152 * already has a material (generated from the glTF material options alone) 2153 * but reuse of the same glTF material may require multiple threejs materials 2154 * to accomodate different primitive types, defines, etc. New materials will 2155 * be created if necessary, and reused from a cache. 2156 * @param {THREE.Object3D} mesh Mesh, Line, or Points instance. 2157 */ 2158 GLTFParser.prototype.assignFinalMaterial = function ( mesh ) { 2159 2160 var geometry = mesh.geometry; 2161 var material = mesh.material; 2162 var extensions = this.extensions; 2163 2164 var useVertexTangents = geometry.attributes.tangent !== undefined; 2165 var useVertexColors = geometry.attributes.color !== undefined; 2166 var useFlatShading = geometry.attributes.normal === undefined; 2167 var useSkinning = mesh.isSkinnedMesh === true; 2168 var useMorphTargets = Object.keys( geometry.morphAttributes ).length > 0; 2169 var useMorphNormals = useMorphTargets && geometry.morphAttributes.normal !== undefined; 2170 2171 if ( mesh.isPoints ) { 2172 2173 var cacheKey = 'PointsMaterial:' + material.uuid; 2174 2175 var pointsMaterial = this.cache.get( cacheKey ); 2176 2177 if ( ! pointsMaterial ) { 2178 2179 pointsMaterial = new THREE.PointsMaterial(); 2180 THREE.Material.prototype.copy.call( pointsMaterial, material ); 2181 pointsMaterial.color.copy( material.color ); 2182 pointsMaterial.map = material.map; 2183 pointsMaterial.lights = false; // PointsMaterial doesn't support lights yet 2184 2185 this.cache.add( cacheKey, pointsMaterial ); 2186 2187 } 2188 2189 material = pointsMaterial; 2190 2191 } else if ( mesh.isLine ) { 2192 2193 var cacheKey = 'LineBasicMaterial:' + material.uuid; 2194 2195 var lineMaterial = this.cache.get( cacheKey ); 2196 2197 if ( ! lineMaterial ) { 2198 2199 lineMaterial = new THREE.LineBasicMaterial(); 2200 THREE.Material.prototype.copy.call( lineMaterial, material ); 2201 lineMaterial.color.copy( material.color ); 2202 lineMaterial.lights = false; // LineBasicMaterial doesn't support lights yet 2203 2204 this.cache.add( cacheKey, lineMaterial ); 2205 2206 } 2207 2208 material = lineMaterial; 2209 2210 } 2211 2212 // Clone the material if it will be modified 2213 if ( useVertexTangents || useVertexColors || useFlatShading || useSkinning || useMorphTargets ) { 2214 2215 var cacheKey = 'ClonedMaterial:' + material.uuid + ':'; 2216 2217 if ( material.isGLTFSpecularGlossinessMaterial ) cacheKey += 'specular-glossiness:'; 2218 if ( useSkinning ) cacheKey += 'skinning:'; 2219 if ( useVertexTangents ) cacheKey += 'vertex-tangents:'; 2220 if ( useVertexColors ) cacheKey += 'vertex-colors:'; 2221 if ( useFlatShading ) cacheKey += 'flat-shading:'; 2222 if ( useMorphTargets ) cacheKey += 'morph-targets:'; 2223 if ( useMorphNormals ) cacheKey += 'morph-normals:'; 2224 2225 var cachedMaterial = this.cache.get( cacheKey ); 2226 2227 if ( ! cachedMaterial ) { 2228 2229 cachedMaterial = material.isGLTFSpecularGlossinessMaterial 2230 ? extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].cloneMaterial( material ) 2231 : material.clone(); 2232 2233 if ( useSkinning ) cachedMaterial.skinning = true; 2234 if ( useVertexTangents ) cachedMaterial.vertexTangents = true; 2235 if ( useVertexColors ) cachedMaterial.vertexColors = THREE.VertexColors; 2236 if ( useFlatShading ) cachedMaterial.flatShading = true; 2237 if ( useMorphTargets ) cachedMaterial.morphTargets = true; 2238 if ( useMorphNormals ) cachedMaterial.morphNormals = true; 2239 2240 this.cache.add( cacheKey, cachedMaterial ); 2241 2242 } 2243 2244 material = cachedMaterial; 2245 2246 } 2247 2248 // workarounds for mesh and geometry 2249 2250 if ( material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined ) { 2251 2252 console.log( 'THREE.GLTFLoader: Duplicating UVs to support aoMap.' ); 2253 geometry.addAttribute( 'uv2', new THREE.BufferAttribute( geometry.attributes.uv.array, 2 ) ); 2254 2255 } 2256 2257 if ( material.isGLTFSpecularGlossinessMaterial ) { 2258 2259 // for GLTFSpecularGlossinessMaterial(ShaderMaterial) uniforms runtime update 2260 mesh.onBeforeRender = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].refreshUniforms; 2261 2262 } 2263 2264 mesh.material = material; 2265 2266 }; 2267 2268 /** 2269 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials 2270 * @param {number} materialIndex 2271 * @return {Promise<THREE.Material>} 2272 */ 2273 GLTFParser.prototype.loadMaterial = function ( materialIndex ) { 2274 2275 var parser = this; 2276 var json = this.json; 2277 var extensions = this.extensions; 2278 var materialDef = json.materials[ materialIndex ]; 2279 2280 var materialType; 2281 var materialParams = {}; 2282 var materialExtensions = materialDef.extensions || {}; 2283
2284 var pending = []; 2285 2286 if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] ) { 2287 2288 var sgExtension = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ]; 2289 materialType = sgExtension.getMaterialType( materialDef ); 2290 pending.push( sgExtension.extendParams( materialParams, materialDef, parser ) ); 2291 2292 } else if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ] ) { 2293 2294 var kmuExtension = extensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ]; 2295 materialType = kmuExtension.getMaterialType( materialDef ); 2296 pending.push( kmuExtension.extendParams( materialParams, materialDef, parser ) ); 2297 2298 } else { 2299 2300 // Specification: 2301 // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material 2302 2303 materialType = THREE.MeshStandardMaterial; 2304 2305 var metallicRoughness = materialDef.pbrMetallicRoughness || {}; 2306 2307 materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 ); 2308 materialParams.opacity = 1.0; 2309 2310 if ( Array.isArray( metallicRoughness.baseColorFactor ) ) { 2311 2312 var array = metallicRoughness.baseColorFactor; 2313 2314 materialParams.color.fromArray( array ); 2315 materialParams.opacity = array[ 3 ]; 2316 2317 } 2318 2319 if ( metallicRoughness.baseColorTexture !== undefined ) { 2320 2321 pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) ); 2322 2323 } 2324 2325 materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0; 2326 materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0; 2327 2328 if ( metallicRoughness.metallicRoughnessTexture !== undefined ) { 2329 2330 pending.push( parser.assignTexture( materialParams, 'metalnessMap', metallicRoughness.metallicRoughnessTexture ) ); 2331 pending.push( parser.assignTexture( materialParams, 'roughnessMap', metallicRoughness.metallicRoughnessTexture ) ); 2332 2333 } 2334 2335 } 2336 2337 if ( materialDef.doubleSided === true ) { 2338 2339 materialParams.side = THREE.DoubleSide; 2340 2341 } 2342 2343 var alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE; 2344 2345 if ( alphaMode === ALPHA_MODES.BLEND ) { 2346 2347 materialParams.transparent = true; 2348 2349 } else { 2350 2351 materialParams.transparent = false; 2352 2353 if ( alphaMode === ALPHA_MODES.MASK ) { 2354 2355 materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5; 2356 2357 } 2358 2359 } 2360 2361 if ( materialDef.normalTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) { 2362 2363 pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture ) ); 2364 2365 materialParams.normalScale = new THREE.Vector2( 1, 1 ); 2366 2367 if ( materialDef.normalTexture.scale !== undefined ) { 2368 2369 materialParams.normalScale.set( materialDef.normalTexture.scale, materialDef.normalTexture.scale ); 2370 2371 } 2372 2373 } 2374 2375 if ( materialDef.occlusionTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) { 2376 2377 pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture ) ); 2378 2379 if ( materialDef.occlusionTexture.strength !== undefined ) { 2380 2381 materialParams.aoMapIntensity = materialDef.occlusionTexture.strength; 2382 2383 } 2384 2385 } 2386 2387 if ( materialDef.emissiveFactor !== undefined && materialType !== THREE.MeshBasicMaterial ) { 2388 2389 materialParams.emissive = new THREE.Color().fromArray( materialDef.emissiveFactor ); 2390 2391 } 2392 2393 if ( materialDef.emissiveTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) { 2394 2395 pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture ) ); 2396 2397 } 2398 2399 return Promise.all( pending ).then( function () { 2400 2401 var material; 2402 2403 if ( materialType === THREE.ShaderMaterial ) { 2404 2405 material = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].createMaterial( materialParams ); 2406 2407 } else { 2408 2409 material = new materialType( materialParams ); 2410 2411 } 2412 2413 if ( materialDef.name !== undefined ) material.name = materialDef.name; 2414 2415 // baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding. 2416 if ( material.map ) material.map.encoding = THREE.sRGBEncoding; 2417 if ( material.emissiveMap ) material.emissiveMap.encoding = THREE.sRGBEncoding; 2418 if ( material.specularMap ) material.specularMap.encoding = THREE.sRGBEncoding; 2419 2420 assignExtrasToUserData( material, materialDef ); 2421 2422 if ( materialDef.extensions ) addUnknownExtensionsToUserData( extensions, material, materialDef ); 2423 2424 return material; 2425 2426 } ); 2427 2428 }; 2429 2430 /** 2431 * @param {THREE.BufferGeometry} geometry 2432 * @param {GLTF.Primitive} primitiveDef 2433 * @param {GLTFParser} parser 2434 * @return {Promise<THREE.BufferGeometry>} 2435 */ 2436 function addPrimitiveAttributes( geometry, primitiveDef, parser ) { 2437 2438 var attributes = primitiveDef.attributes; 2439
2440 var pending = []; 2441 2442 function assignAttributeAccessor( accessorIndex, attributeName ) { 2443 2444 return parser.getDependency( 'accessor', accessorIndex ) 2445 .then( function ( accessor ) { 2446 2447 geometry.addAttribute( attributeName, accessor ); 2448 2449 } ); 2450 2451 } 2452 2453 for ( var gltfAttributeName in attributes ) { 2454 2455 var threeAttributeName = ATTRIBUTES[ gltfAttributeName ] || gltfAttributeName.toLowerCase(); 2456 2457 // Skip attributes already provided by e.g. Draco extension. 2458 if ( threeAttributeName in geometry.attributes ) continue; 2459 2460 pending.push( assignAttributeAccessor( attributes[ gltfAttributeName ], threeAttributeName ) ); 2461 2462 } 2463 2464 if ( primitiveDef.indices !== undefined && ! geometry.index ) { 2465 2466 var accessor = parser.getDependency( 'accessor', primitiveDef.indices ).then( function ( accessor ) { 2467 2468 geometry.setIndex( accessor ); 2469 2470 } ); 2471 2472 pending.push( accessor ); 2473 2474 } 2475 2476 assignExtrasToUserData( geometry, primitiveDef ); 2477 2478 return Promise.all( pending ).then( function () { 2479 2480 return primitiveDef.targets !== undefined 2481 ? addMorphTargets( geometry, primitiveDef.targets, parser ) 2482 : geometry; 2483 2484 } ); 2485 2486 } 2487 2488 /** 2489 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry 2490 * 2491 * Creates BufferGeometries from primitives. 2492 * 2493 * @param {Array<GLTF.Primitive>} primitives 2494 * @return {Promise<Array<THREE.BufferGeometry>>} 2495 */ 2496 GLTFParser.prototype.loadGeometries = function ( primitives ) { 2497 2498 var parser = this; 2499 var extensions = this.extensions; 2500 var cache = this.primitiveCache; 2501 2502 function createDracoPrimitive( primitive ) { 2503 2504 return extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] 2505 .decodePrimitive( primitive, parser ) 2506 .then( function ( geometry ) { 2507 2508 return addPrimitiveAttributes( geometry, primitive, parser ); 2509 2510 } ); 2511 2512 } 2513 2514 var pending = []; 2515 2516 for ( var i = 0, il = primitives.length; i < il; i ++ ) { 2517 2518 var primitive = primitives[ i ]; 2519 var cacheKey = createPrimitiveKey( primitive ); 2520 2521 // See if we've already created this geometry 2522 var cached = cache[ cacheKey ]; 2523 2524 if ( cached ) { 2525 2526 // Use the cached geometry if it exists 2527 pending.push( cached.promise ); 2528 2529 } else { 2530 2531 var geometryPromise; 2532 2533 if ( primitive.extensions && primitive.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] ) { 2534 2535 // Use DRACO geometry if available 2536 geometryPromise = createDracoPrimitive( primitive ); 2537 2538 } else { 2539 2540 // Otherwise create a new geometry 2541 geometryPromise = addPrimitiveAttributes( new THREE.BufferGeometry(), primitive, parser ); 2542 2543 } 2544 2545 // Cache this geometry 2546 cache[ cacheKey ] = { primitive: primitive, promise: geometryPromise }; 2547 2548 pending.push( geometryPromise ); 2549 2550 } 2551 2552 } 2553 2554 return Promise.all( pending ); 2555 2556 }; 2557 2558 /** 2559 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes 2560 * @param {number} meshIndex 2561 * @return {Promise<THREE.Group|THREE.Mesh|THREE.SkinnedMesh>} 2562 */ 2563 GLTFParser.prototype.loadMesh = function ( meshIndex ) { 2564 2565 var parser = this; 2566 var json = this.json; 2567 var extensions = this.extensions; 2568 2569 var meshDef = json.meshes[ meshIndex ]; 2570 var primitives = meshDef.primitives; 2571
2572 var pending = []; 2573 2574 for ( var i = 0, il = primitives.length; i < il; i ++ ) { 2575 2576 var material = primitives[ i ].material === undefined 2577 ? createDefaultMaterial() 2578 : this.getDependency( 'material', primitives[ i ].material ); 2579 2580 pending.push( material ); 2581 2582 } 2583 2584 return Promise.all( pending ).then( function ( originalMaterials ) { 2585 2586 return parser.loadGeometries( primitives ).then( function ( geometries ) { 2587 2588 var meshes = []; 2589 2590 for ( var i = 0, il = geometries.length; i < il; i ++ ) { 2591 2592 var geometry = geometries[ i ]; 2593 var primitive = primitives[ i ]; 2594 2595 // 1. create Mesh 2596 2597 var mesh; 2598 2599 var material = originalMaterials[ i ]; 2600 2601 if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES || 2602 primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP || 2603 primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN || 2604 primitive.mode === undefined ) { 2605 2606 // .isSkinnedMesh isn't in glTF spec. See .markDefs() 2607 mesh = meshDef.isSkinnedMesh === true 2608 ? new THREE.SkinnedMesh( geometry, material ) 2609 : new THREE.Mesh( geometry, material ); 2610 2611 if ( mesh.isSkinnedMesh === true ) mesh.normalizeSkinWeights(); // #15319 2612 2613 if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) { 2614 2615 mesh.drawMode = THREE.TriangleStripDrawMode; 2616 2617 } else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) { 2618 2619 mesh.drawMode = THREE.TriangleFanDrawMode; 2620 2621 } 2622 2623 } else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) { 2624 2625 mesh = new THREE.LineSegments( geometry, material ); 2626 2627 } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) { 2628 2629 mesh = new THREE.Line( geometry, material ); 2630 2631 } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) { 2632 2633 mesh = new THREE.LineLoop( geometry, material ); 2634 2635 } else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) { 2636 2637 mesh = new THREE.Points( geometry, material ); 2638 2639 } else { 2640 2641 throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode ); 2642 2643 } 2644 2645 if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) { 2646 2647 updateMorphTargets( mesh, meshDef ); 2648 2649 } 2650 2651 mesh.name = meshDef.name || ( 'mesh_' + meshIndex ); 2652 2653 if ( geometries.length > 1 ) mesh.name += '_' + i; 2654 2655 assignExtrasToUserData( mesh, meshDef ); 2656 2657 parser.assignFinalMaterial( mesh ); 2658 2659 meshes.push( mesh ); 2660 2661 } 2662 2663 if ( meshes.length === 1 ) { 2664 2665 return meshes[ 0 ]; 2666 2667 } 2668 2669 var group = new THREE.Group(); 2670 2671 for ( var i = 0, il = meshes.length; i < il; i ++ ) { 2672 2673 group.add( meshes[ i ] ); 2674 2675 } 2676 2677 return group; 2678 2679 } ); 2680 2681 } ); 2682 2683 }; 2684 2685 /** 2686 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras 2687 * @param {number} cameraIndex 2688 * @return {Promise<THREE.Camera>} 2689 */ 2690 GLTFParser.prototype.loadCamera = function ( cameraIndex ) { 2691 2692 var camera; 2693 var cameraDef = this.json.cameras[ cameraIndex ]; 2694 var params = cameraDef[ cameraDef.type ]; 2695 2696 if ( ! params ) { 2697 2698 console.warn( 'THREE.GLTFLoader: Missing camera parameters.' ); 2699 return; 2700 2701 } 2702 2703 if ( cameraDef.type === 'perspective' ) { 2704 2705 camera = new THREE.PerspectiveCamera( THREE.Math.radToDeg( params.yfov ), params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6 ); 2706 2707 } else if ( cameraDef.type === 'orthographic' ) { 2708 2709 camera = new THREE.OrthographicCamera( params.xmag / - 2, params.xmag / 2, params.ymag / 2, params.ymag / - 2, params.znear, params.zfar ); 2710 2711 } 2712 2713 if ( cameraDef.name !== undefined ) camera.name = cameraDef.name; 2714 2715 assignExtrasToUserData( camera, cameraDef ); 2716 2717 return Promise.resolve( camera ); 2718 2719 }; 2720 2721 /** 2722 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins 2723 * @param {number} skinIndex 2724 * @return {Promise<Object>} 2725 */ 2726 GLTFParser.prototype.loadSkin = function ( skinIndex ) { 2727 2728 var skinDef = this.json.skins[ skinIndex ]; 2729 2730 var skinEntry = { joints: skinDef.joints }; 2731 2732 if ( skinDef.inverseBindMatrices === undefined ) { 2733 2734 return Promise.resolve( skinEntry ); 2735 2736 } 2737 2738 return this.getDependency( 'accessor', skinDef.inverseBindMatrices ).then( function ( accessor ) { 2739 2740 skinEntry.inverseBindMatrices = accessor; 2741 2742 return skinEntry; 2743 2744 } ); 2745 2746 }; 2747 2748 /** 2749 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations 2750 * @param {number} animationIndex 2751 * @return {Promise<THREE.AnimationClip>} 2752 */ 2753 GLTFParser.prototype.loadAnimation = function ( animationIndex ) { 2754 2755 var json = this.json; 2756 2757 var animationDef = json.animations[ animationIndex ]; 2758
2759 var pendingNodes = []; 2760 var pendingInputAccessors = []; 2761 var pendingOutputAccessors = []; 2762 var pendingSamplers = []; 2763 var pendingTargets = []; 2764 2765 for ( var i = 0, il = animationDef.channels.length; i < il; i ++ ) { 2766 2767 var channel = animationDef.channels[ i ]; 2768 var sampler = animationDef.samplers[ channel.sampler ]; 2769 var target = channel.target; 2770 var name = target.node !== undefined ? target.node : target.id; // NOTE: target.id is deprecated. 2771 var input = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.input ] : sampler.input; 2772 var output = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.output ] : sampler.output; 2773 2774 pendingNodes.push( this.getDependency( 'node', name ) ); 2775 pendingInputAccessors.push( this.getDependency( 'accessor', input ) ); 2776 pendingOutputAccessors.push( this.getDependency( 'accessor', output ) ); 2777 pendingSamplers.push( sampler ); 2778 pendingTargets.push( target ); 2779 2780 } 2781 2782 return Promise.all( [ 2783 2784 Promise.all( pendingNodes ), 2785 Promise.all( pendingInputAccessors ), 2786 Promise.all( pendingOutputAccessors ), 2787 Promise.all( pendingSamplers ), 2788 Promise.all( pendingTargets ) 2789 2790 ] ).then( function ( dependencies ) { 2791 2792 var nodes = dependencies[ 0 ]; 2793 var inputAccessors = dependencies[ 1 ]; 2794 var outputAccessors = dependencies[ 2 ]; 2795 var samplers = dependencies[ 3 ]; 2796 var targets = dependencies[ 4 ]; 2797 2798 var tracks = []; 2799 2800 for ( var i = 0, il = nodes.length; i < il; i ++ ) { 2801 2802 var node = nodes[ i ]; 2803 var inputAccessor = inputAccessors[ i ]; 2804 var outputAccessor = outputAccessors[ i ]; 2805 var sampler = samplers[ i ]; 2806 var target = targets[ i ]; 2807 2808 if ( node === undefined ) continue; 2809 2810 node.updateMatrix(); 2811 node.matrixAutoUpdate = true; 2812 2813 var TypedKeyframeTrack; 2814 2815 switch ( PATH_PROPERTIES[ target.path ] ) { 2816 2817 case PATH_PROPERTIES.weights: 2818 2819 TypedKeyframeTrack = THREE.NumberKeyframeTrack; 2820 break; 2821 2822 case PATH_PROPERTIES.rotation: 2823 2824 TypedKeyframeTrack = THREE.QuaternionKeyframeTrack; 2825 break; 2826 2827 case PATH_PROPERTIES.position: 2828 case PATH_PROPERTIES.scale: 2829 default: 2830 2831 TypedKeyframeTrack = THREE.VectorKeyframeTrack; 2832 break; 2833 2834 } 2835 2836 var targetName = node.name ? node.name : node.uuid; 2837 2838 var interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : THREE.InterpolateLinear; 2839 2840 var targetNames = []; 2841 2842 if ( PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.weights ) { 2843 2844 // Node may be a THREE.Group (glTF mesh with several primitives) or a THREE.Mesh. 2845 node.traverse( function ( object ) { 2846 2847 if ( object.isMesh === true && object.morphTargetInfluences ) { 2848 2849 targetNames.push( object.name ? object.name : object.uuid ); 2850 2851 } 2852 2853 } ); 2854 2855 } else { 2856 2857 targetNames.push( targetName ); 2858 2859 } 2860 2861 for ( var j = 0, jl = targetNames.length; j < jl; j ++ ) { 2862 2863 var track = new TypedKeyframeTrack( 2864 targetNames[ j ] + '.' + PATH_PROPERTIES[ target.path ], 2865 inputAccessor.array, 2866 outputAccessor.array, 2867 interpolation 2868 ); 2869 2870 // Override interpolation with custom factory method. 2871 if ( sampler.interpolation === 'CUBICSPLINE' ) { 2872 2873 track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline( result ) { 2874 2875 // A CUBICSPLINE keyframe in glTF has three output values for each input value, 2876 // representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize() 2877 // must be divided by three to get the interpolant's sampleSize argument. 2878 2879 return new GLTFCubicSplineInterpolant( this.times, this.values, this.getValueSize() / 3, result ); 2880 2881 }; 2882 2883 // Mark as CUBICSPLINE. `track.getInterpolation()` doesn't support custom interpolants. 2884 track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true; 2885 2886 } 2887 2888 tracks.push( track ); 2889 2890 } 2891 2892 } 2893 2894 var name = animationDef.name !== undefined ? animationDef.name : 'animation_' + animationIndex; 2895 2896 return new THREE.AnimationClip( name, undefined, tracks ); 2897 2898 } ); 2899 2900 }; 2901 2902 /** 2903 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy 2904 * @param {number} nodeIndex 2905 * @return {Promise<THREE.Object3D>} 2906 */ 2907 GLTFParser.prototype.loadNode = function ( nodeIndex ) { 2908 2909 var json = this.json; 2910 var extensions = this.extensions; 2911 var parser = this; 2912 2913 var meshReferences = json.meshReferences; 2914 var meshUses = json.meshUses; 2915 2916 var nodeDef = json.nodes[ nodeIndex ]; 2917 2918 return ( function () { 2919 2920 // .isBone isn't in glTF spec. See .markDefs 2921 if ( nodeDef.isBone === true ) { 2922 2923 return Promise.resolve( new THREE.Bone() ); 2924 2925 } else if ( nodeDef.mesh !== undefined ) { 2926 2927 return parser.getDependency( 'mesh', nodeDef.mesh ).then( function ( mesh ) { 2928 2929 var node; 2930 2931 if ( meshReferences[ nodeDef.mesh ] > 1 ) { 2932 2933 var instanceNum = meshUses[ nodeDef.mesh ] ++; 2934 2935 node = mesh.clone(); 2936 node.name += '_instance_' + instanceNum; 2937 2938 // onBeforeRender copy for Specular-Glossiness 2939 node.onBeforeRender = mesh.onBeforeRender; 2940 2941 for ( var i = 0, il = node.children.length; i < il; i ++ ) { 2942 2943 node.children[ i ].name += '_instance_' + instanceNum; 2944 node.children[ i ].onBeforeRender = mesh.children[ i ].onBeforeRender; 2945 2946 } 2947 2948 } else { 2949 2950 node = mesh; 2951 2952 } 2953 2954 // if weights are provided on the node, override weights on the mesh. 2955 if ( nodeDef.weights !== undefined ) { 2956 2957 node.traverse( function ( o ) { 2958 2959 if ( ! o.isMesh ) return; 2960 2961 for ( var i = 0, il = nodeDef.weights.length; i < il; i ++ ) { 2962 2963 o.morphTargetInfluences[ i ] = nodeDef.weights[ i ]; 2964 2965 } 2966 2967 } ); 2968 2969 } 2970 2971 return node; 2972 2973 } ); 2974 2975 } else if ( nodeDef.camera !== undefined ) { 2976 2977 return parser.getDependency( 'camera', nodeDef.camera ); 2978 2979 } else if ( nodeDef.extensions 2980 && nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ] 2981 && nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light !== undefined ) { 2982 2983 return parser.getDependency( 'light', nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light ); 2984 2985 } else { 2986 2987 return Promise.resolve( new THREE.Object3D() ); 2988 2989 } 2990 2991 }() ).then( function ( node ) { 2992 2993 if ( nodeDef.name !== undefined ) { 2994 2995 node.name = THREE.PropertyBinding.sanitizeNodeName( nodeDef.name ); 2996 2997 } 2998 2999 assignExtrasToUserData( node, nodeDef ); 3000 3001 if ( nodeDef.extensions ) addUnknownExtensionsToUserData( extensions, node, nodeDef ); 3002 3003 if ( nodeDef.matrix !== undefined ) { 3004 3005 var matrix = new THREE.Matrix4(); 3006 matrix.fromArray( nodeDef.matrix );
3007 node.applyMatrix( matrix ); 3008 3009 } else { 3010 3011 if ( nodeDef.translation !== undefined ) { 3012 3013 node.position.fromArray( nodeDef.translation ); 3014 3015 } 3016 3017 if ( nodeDef.rotation !== undefined ) { 3018 3019 node.quaternion.fromArray( nodeDef.rotation ); 3020 3021 } 3022 3023 if ( nodeDef.scale !== undefined ) { 3024 3025 node.scale.fromArray( nodeDef.scale ); 3026 3027 } 3028 3029 } 3030 3031 return node; 3032 3033 } ); 3034 3035 }; 3036 3037 /** 3038 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes 3039 * @param {number} sceneIndex 3040 * @return {Promise<THREE.Scene>} 3041 */ 3042 GLTFParser.prototype.loadScene = function () { 3043 3044 // scene node hierachy builder 3045 3046 function buildNodeHierachy( nodeId, parentObject, json, parser ) { 3047 3048 var nodeDef = json.nodes[ nodeId ]; 3049 3050 return parser.getDependency( 'node', nodeId ).then( function ( node ) { 3051 3052 if ( nodeDef.skin === undefined ) return node; 3053 3054 // build skeleton here as well 3055 3056 var skinEntry; 3057 3058 return parser.getDependency( 'skin', nodeDef.skin ).then( function ( skin ) { 3059 3060 skinEntry = skin; 3061 3062 var pendingJoints = []; 3063 3064 for ( var i = 0, il = skinEntry.joints.length; i < il; i ++ ) { 3065 3066 pendingJoints.push( parser.getDependency( 'node', skinEntry.joints[ i ] ) ); 3067 3068 } 3069 3070 return Promise.all( pendingJoints ); 3071 3072 } ).then( function ( jointNodes ) { 3073 3074 var meshes = node.isGroup === true ? node.children : [ node ]; 3075 3076 for ( var i = 0, il = meshes.length; i < il; i ++ ) { 3077 3078 var mesh = meshes[ i ]; 3079 3080 var bones = []; 3081 var boneInverses = []; 3082 3083 for ( var j = 0, jl = jointNodes.length; j < jl; j ++ ) { 3084 3085 var jointNode = jointNodes[ j ]; 3086 3087 if ( jointNode ) { 3088 3089 bones.push( jointNode ); 3090 3091 var mat = new THREE.Matrix4(); 3092 3093 if ( skinEntry.inverseBindMatrices !== undefined ) { 3094 3095 mat.fromArray( skinEntry.inverseBindMatrices.array, j * 16 ); 3096 3097 } 3098 3099 boneInverses.push( mat ); 3100 3101 } else { 3102 3103 console.warn( 'THREE.GLTFLoader: Joint "%s" could not be found.', skinEntry.joints[ j ] ); 3104 3105 } 3106 3107 } 3108 3109 mesh.bind( new THREE.Skeleton( bones, boneInverses ), mesh.matrixWorld ); 3110 3111 } 3112 3113 return node; 3114 3115 } ); 3116 3117 } ).then( function ( node ) { 3118 3119 // build node hierachy 3120 3121 parentObject.add( node ); 3122 3123 var pending = []; 3124 3125 if ( nodeDef.children ) { 3126 3127 var children = nodeDef.children; 3128 3129 for ( var i = 0, il = children.length; i < il; i ++ ) { 3130 3131 var child = children[ i ]; 3132 pending.push( buildNodeHierachy( child, node, json, parser ) ); 3133 3134 } 3135 3136 } 3137 3138 return Promise.all( pending ); 3139 3140 } ); 3141 3142 } 3143 3144 return function loadScene( sceneIndex ) { 3145 3146 var json = this.json; 3147 var extensions = this.extensions; 3148 var sceneDef = this.json.scenes[ sceneIndex ]; 3149 var parser = this; 3150 3151 var scene = new THREE.Scene(); 3152 if ( sceneDef.name !== undefined ) scene.name = sceneDef.name; 3153 3154 assignExtrasToUserData( scene, sceneDef ); 3155 3156 if ( sceneDef.extensions ) addUnknownExtensionsToUserData( extensions, scene, sceneDef ); 3157 3158 var nodeIds = sceneDef.nodes || []; 3159 3160 var pending = []; 3161 3162 for ( var i = 0, il = nodeIds.length; i < il; i ++ ) { 3163 3164 pending.push( buildNodeHierachy( nodeIds[ i ], scene, json, parser ) ); 3165 3166 } 3167 3168 return Promise.all( pending ).then( function () { 3169 3170 return scene; 3171 3172 } ); 3173 3174 }; 3175 3176 }(); 3177 3178 return GLTFLoader; 3179 3180} )();
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.