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