PageSourceSearch

https://binomial.biz/gltf/GLTFLoader.js

js binomial.biz collected 2026-09-25 22:09:10 UTC 80,979 bytes, 3,205 lines download raw bytes

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.