@threlte/gltf 0.0.1

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