@inweb/viewer-three 26.9.2 → 26.9.4
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.
- package/dist/plugins/components/AxesHelperComponent.js +23 -22
- package/dist/plugins/components/AxesHelperComponent.js.map +1 -1
- package/dist/plugins/components/AxesHelperComponent.min.js +24 -1
- package/dist/plugins/components/AxesHelperComponent.module.js +31 -9
- package/dist/plugins/components/AxesHelperComponent.module.js.map +1 -1
- package/dist/plugins/components/ExtentsHelperComponent.js +23 -22
- package/dist/plugins/components/ExtentsHelperComponent.js.map +1 -1
- package/dist/plugins/components/ExtentsHelperComponent.min.js +24 -1
- package/dist/plugins/components/ExtentsHelperComponent.module.js +28 -6
- package/dist/plugins/components/ExtentsHelperComponent.module.js.map +1 -1
- package/dist/plugins/components/LightHelperComponent.js +23 -22
- package/dist/plugins/components/LightHelperComponent.js.map +1 -1
- package/dist/plugins/components/LightHelperComponent.min.js +24 -1
- package/dist/plugins/components/LightHelperComponent.module.js +38 -12
- package/dist/plugins/components/LightHelperComponent.module.js.map +1 -1
- package/dist/plugins/components/RoomEnvironmentComponent.js +23 -97
- package/dist/plugins/components/RoomEnvironmentComponent.js.map +1 -1
- package/dist/plugins/components/RoomEnvironmentComponent.min.js +24 -1
- package/dist/plugins/components/RoomEnvironmentComponent.module.js +27 -7
- package/dist/plugins/components/RoomEnvironmentComponent.module.js.map +1 -1
- package/dist/plugins/components/StatsPanelComponent.js +23 -92
- package/dist/plugins/components/StatsPanelComponent.js.map +1 -1
- package/dist/plugins/components/StatsPanelComponent.min.js +24 -1
- package/dist/plugins/components/StatsPanelComponent.module.js +26 -5
- package/dist/plugins/components/StatsPanelComponent.module.js.map +1 -1
- package/dist/plugins/loaders/GLTFCloudLoader.js +31 -2515
- package/dist/plugins/loaders/GLTFCloudLoader.js.map +1 -1
- package/dist/plugins/loaders/GLTFCloudLoader.min.js +24 -1
- package/dist/plugins/loaders/GLTFCloudLoader.module.js +35 -20
- package/dist/plugins/loaders/GLTFCloudLoader.module.js.map +1 -1
- package/dist/plugins/loaders/IFCXLoader.js +39 -693
- package/dist/plugins/loaders/IFCXLoader.js.map +1 -1
- package/dist/plugins/loaders/IFCXLoader.min.js +24 -1
- package/dist/plugins/loaders/IFCXLoader.module.js +839 -865
- package/dist/plugins/loaders/IFCXLoader.module.js.map +1 -1
- package/dist/plugins/loaders/PotreeLoader.js +27 -71
- package/dist/plugins/loaders/PotreeLoader.js.map +1 -1
- package/dist/plugins/loaders/PotreeLoader.min.js +24 -1
- package/dist/plugins/loaders/PotreeLoader.module.js +37 -15
- package/dist/plugins/loaders/PotreeLoader.module.js.map +1 -1
- package/dist/viewer-three.js +2653 -55920
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +26 -3
- package/dist/viewer-three.module.js +3850 -3637
- package/dist/viewer-three.module.js.map +1 -1
- package/lib/Viewer/controls/FlyControls.d.ts +34 -0
- package/lib/Viewer/controls/WalkControls.d.ts +19 -3
- package/lib/Viewer/draggers/FlyDragger.d.ts +14 -0
- package/package.json +5 -5
- package/src/Viewer/controls/FlyControls.ts +205 -0
- package/src/Viewer/controls/WalkControls.ts +129 -20
- package/src/Viewer/draggers/FlyDragger.ts +73 -0
- package/src/Viewer/draggers/WalkDragger.ts +10 -2
- package/src/Viewer/draggers/index.ts +2 -0
|
@@ -1,652 +1,301 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
|
|
3
|
+
// All rights reserved.
|
|
4
|
+
//
|
|
5
|
+
// This software and its documentation and related materials are owned by
|
|
6
|
+
// the Alliance. The software may only be incorporated into application
|
|
7
|
+
// programs owned by members of the Alliance, subject to a signed
|
|
8
|
+
// Membership Agreement and Supplemental Software License Agreement with the
|
|
9
|
+
// Alliance. The structure and organization of this software are the valuable
|
|
10
|
+
// trade secrets of the Alliance and its suppliers. The software is also
|
|
11
|
+
// protected by copyright law and international treaty provisions. Application
|
|
12
|
+
// programs incorporating this software must include the following statement
|
|
13
|
+
// with their copyright notices:
|
|
14
|
+
//
|
|
15
|
+
// This application incorporates Open Design Alliance software pursuant to a
|
|
16
|
+
// license agreement with Open Design Alliance.
|
|
17
|
+
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
|
|
18
|
+
// All rights reserved.
|
|
19
|
+
//
|
|
20
|
+
// By use of this software, its documentation or related materials, you
|
|
21
|
+
// acknowledge and accept the above terms.
|
|
22
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
23
|
+
|
|
1
24
|
(function (global, factory) {
|
|
2
25
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('three'), require('@inweb/viewer-three')) :
|
|
3
26
|
typeof define === 'function' && define.amd ? define(['three', '@inweb/viewer-three'], factory) :
|
|
4
27
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.THREE, global.ODA.Three));
|
|
5
28
|
})(this, (function (three, viewerThree) { 'use strict';
|
|
6
29
|
|
|
7
|
-
/**
|
|
8
|
-
* Returns a new indexed geometry based on `TrianglesDrawMode` draw mode.
|
|
9
|
-
* This mode corresponds to the `gl.TRIANGLES` primitive in WebGL.
|
|
10
|
-
*
|
|
11
|
-
* @param {BufferGeometry} geometry - The geometry to convert.
|
|
12
|
-
* @param {number} drawMode - The current draw mode.
|
|
13
|
-
* @return {BufferGeometry} The new geometry using `TrianglesDrawMode`.
|
|
14
|
-
*/
|
|
15
30
|
function toTrianglesDrawMode( geometry, drawMode ) {
|
|
16
|
-
|
|
17
31
|
if ( drawMode === three.TrianglesDrawMode ) {
|
|
18
|
-
|
|
19
32
|
console.warn( 'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.' );
|
|
20
33
|
return geometry;
|
|
21
|
-
|
|
22
34
|
}
|
|
23
|
-
|
|
24
35
|
if ( drawMode === three.TriangleFanDrawMode || drawMode === three.TriangleStripDrawMode ) {
|
|
25
|
-
|
|
26
36
|
let index = geometry.getIndex();
|
|
27
|
-
|
|
28
|
-
// generate index if not present
|
|
29
|
-
|
|
30
37
|
if ( index === null ) {
|
|
31
|
-
|
|
32
38
|
const indices = [];
|
|
33
|
-
|
|
34
39
|
const position = geometry.getAttribute( 'position' );
|
|
35
|
-
|
|
36
40
|
if ( position !== undefined ) {
|
|
37
|
-
|
|
38
41
|
for ( let i = 0; i < position.count; i ++ ) {
|
|
39
|
-
|
|
40
42
|
indices.push( i );
|
|
41
|
-
|
|
42
43
|
}
|
|
43
|
-
|
|
44
44
|
geometry.setIndex( indices );
|
|
45
45
|
index = geometry.getIndex();
|
|
46
|
-
|
|
47
46
|
} else {
|
|
48
|
-
|
|
49
47
|
console.error( 'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Undefined position attribute. Processing not possible.' );
|
|
50
48
|
return geometry;
|
|
51
|
-
|
|
52
49
|
}
|
|
53
|
-
|
|
54
50
|
}
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
|
|
58
51
|
const numberOfTriangles = index.count - 2;
|
|
59
52
|
const newIndices = [];
|
|
60
|
-
|
|
61
53
|
if ( drawMode === three.TriangleFanDrawMode ) {
|
|
62
|
-
|
|
63
|
-
// gl.TRIANGLE_FAN
|
|
64
|
-
|
|
65
54
|
for ( let i = 1; i <= numberOfTriangles; i ++ ) {
|
|
66
|
-
|
|
67
55
|
newIndices.push( index.getX( 0 ) );
|
|
68
56
|
newIndices.push( index.getX( i ) );
|
|
69
57
|
newIndices.push( index.getX( i + 1 ) );
|
|
70
|
-
|
|
71
58
|
}
|
|
72
|
-
|
|
73
59
|
} else {
|
|
74
|
-
|
|
75
|
-
// gl.TRIANGLE_STRIP
|
|
76
|
-
|
|
77
60
|
for ( let i = 0; i < numberOfTriangles; i ++ ) {
|
|
78
|
-
|
|
79
61
|
if ( i % 2 === 0 ) {
|
|
80
|
-
|
|
81
62
|
newIndices.push( index.getX( i ) );
|
|
82
63
|
newIndices.push( index.getX( i + 1 ) );
|
|
83
64
|
newIndices.push( index.getX( i + 2 ) );
|
|
84
|
-
|
|
85
65
|
} else {
|
|
86
|
-
|
|
87
66
|
newIndices.push( index.getX( i + 2 ) );
|
|
88
67
|
newIndices.push( index.getX( i + 1 ) );
|
|
89
68
|
newIndices.push( index.getX( i ) );
|
|
90
|
-
|
|
91
69
|
}
|
|
92
|
-
|
|
93
70
|
}
|
|
94
|
-
|
|
95
71
|
}
|
|
96
|
-
|
|
97
72
|
if ( ( newIndices.length / 3 ) !== numberOfTriangles ) {
|
|
98
|
-
|
|
99
73
|
console.error( 'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unable to generate correct amount of triangles.' );
|
|
100
|
-
|
|
101
74
|
}
|
|
102
|
-
|
|
103
|
-
// build final geometry
|
|
104
|
-
|
|
105
75
|
const newGeometry = geometry.clone();
|
|
106
76
|
newGeometry.setIndex( newIndices );
|
|
107
77
|
newGeometry.clearGroups();
|
|
108
|
-
|
|
109
78
|
return newGeometry;
|
|
110
|
-
|
|
111
79
|
} else {
|
|
112
|
-
|
|
113
80
|
console.error( 'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unknown draw mode:', drawMode );
|
|
114
81
|
return geometry;
|
|
115
|
-
|
|
116
82
|
}
|
|
117
|
-
|
|
118
83
|
}
|
|
119
84
|
|
|
120
|
-
/**
|
|
121
|
-
* A loader for the glTF 2.0 format.
|
|
122
|
-
*
|
|
123
|
-
* [glTF]{@link https://www.khronos.org/gltf/} (GL Transmission Format) is an [open format specification]{@link https://github.com/KhronosGroup/glTF/tree/main/specification/2.0}
|
|
124
|
-
* for efficient delivery and loading of 3D content. Assets may be provided either in JSON (.gltf) or binary (.glb)
|
|
125
|
-
* format. External files store textures (.jpg, .png) and additional binary data (.bin). A glTF asset may deliver
|
|
126
|
-
* one or more scenes, including meshes, materials, textures, skins, skeletons, morph targets, animations, lights,
|
|
127
|
-
* and/or cameras.
|
|
128
|
-
*
|
|
129
|
-
* `GLTFLoader` uses {@link ImageBitmapLoader} whenever possible. Be advised that image bitmaps are not
|
|
130
|
-
* automatically GC-collected when they are no longer referenced, and they require special handling during
|
|
131
|
-
* the disposal process.
|
|
132
|
-
*
|
|
133
|
-
* `GLTFLoader` supports the following glTF 2.0 extensions:
|
|
134
|
-
* - KHR_draco_mesh_compression
|
|
135
|
-
* - KHR_materials_clearcoat
|
|
136
|
-
* - KHR_materials_dispersion
|
|
137
|
-
* - KHR_materials_ior
|
|
138
|
-
* - KHR_materials_specular
|
|
139
|
-
* - KHR_materials_transmission
|
|
140
|
-
* - KHR_materials_iridescence
|
|
141
|
-
* - KHR_materials_unlit
|
|
142
|
-
* - KHR_materials_volume
|
|
143
|
-
* - KHR_mesh_quantization
|
|
144
|
-
* - KHR_lights_punctual
|
|
145
|
-
* - KHR_texture_basisu
|
|
146
|
-
* - KHR_texture_transform
|
|
147
|
-
* - EXT_texture_webp
|
|
148
|
-
* - EXT_meshopt_compression
|
|
149
|
-
* - EXT_mesh_gpu_instancing
|
|
150
|
-
*
|
|
151
|
-
* The following glTF 2.0 extension is supported by an external user plugin:
|
|
152
|
-
* - [KHR_materials_variants]{@link https://github.com/takahirox/three-gltf-extensions}
|
|
153
|
-
* - [MSFT_texture_dds]{@link https://github.com/takahirox/three-gltf-extensions}
|
|
154
|
-
*
|
|
155
|
-
* ```js
|
|
156
|
-
* const loader = new GLTFLoader();
|
|
157
|
-
*
|
|
158
|
-
* // Optional: Provide a DRACOLoader instance to decode compressed mesh data
|
|
159
|
-
* const dracoLoader = new DRACOLoader();
|
|
160
|
-
* dracoLoader.setDecoderPath( '/examples/jsm/libs/draco/' );
|
|
161
|
-
* loader.setDRACOLoader( dracoLoader );
|
|
162
|
-
*
|
|
163
|
-
* const gltf = await loader.loadAsync( 'models/gltf/duck/duck.gltf' );
|
|
164
|
-
* scene.add( gltf.scene );
|
|
165
|
-
* ```
|
|
166
|
-
*
|
|
167
|
-
* @augments Loader
|
|
168
|
-
* @three_import import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
|
169
|
-
*/
|
|
170
85
|
class GLTFLoader extends three.Loader {
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Constructs a new glTF loader.
|
|
174
|
-
*
|
|
175
|
-
* @param {LoadingManager} [manager] - The loading manager.
|
|
176
|
-
*/
|
|
177
86
|
constructor( manager ) {
|
|
178
|
-
|
|
179
87
|
super( manager );
|
|
180
|
-
|
|
181
88
|
this.dracoLoader = null;
|
|
182
89
|
this.ktx2Loader = null;
|
|
183
90
|
this.meshoptDecoder = null;
|
|
184
|
-
|
|
185
91
|
this.pluginCallbacks = [];
|
|
186
|
-
|
|
187
92
|
this.register( function ( parser ) {
|
|
188
|
-
|
|
189
93
|
return new GLTFMaterialsClearcoatExtension( parser );
|
|
190
|
-
|
|
191
94
|
} );
|
|
192
|
-
|
|
193
95
|
this.register( function ( parser ) {
|
|
194
|
-
|
|
195
96
|
return new GLTFMaterialsDispersionExtension( parser );
|
|
196
|
-
|
|
197
97
|
} );
|
|
198
|
-
|
|
199
98
|
this.register( function ( parser ) {
|
|
200
|
-
|
|
201
99
|
return new GLTFTextureBasisUExtension( parser );
|
|
202
|
-
|
|
203
100
|
} );
|
|
204
|
-
|
|
205
101
|
this.register( function ( parser ) {
|
|
206
|
-
|
|
207
102
|
return new GLTFTextureWebPExtension( parser );
|
|
208
|
-
|
|
209
103
|
} );
|
|
210
|
-
|
|
211
104
|
this.register( function ( parser ) {
|
|
212
|
-
|
|
213
105
|
return new GLTFTextureAVIFExtension( parser );
|
|
214
|
-
|
|
215
106
|
} );
|
|
216
|
-
|
|
217
107
|
this.register( function ( parser ) {
|
|
218
|
-
|
|
219
108
|
return new GLTFMaterialsSheenExtension( parser );
|
|
220
|
-
|
|
221
109
|
} );
|
|
222
|
-
|
|
223
110
|
this.register( function ( parser ) {
|
|
224
|
-
|
|
225
111
|
return new GLTFMaterialsTransmissionExtension( parser );
|
|
226
|
-
|
|
227
112
|
} );
|
|
228
|
-
|
|
229
113
|
this.register( function ( parser ) {
|
|
230
|
-
|
|
231
114
|
return new GLTFMaterialsVolumeExtension( parser );
|
|
232
|
-
|
|
233
115
|
} );
|
|
234
|
-
|
|
235
116
|
this.register( function ( parser ) {
|
|
236
|
-
|
|
237
117
|
return new GLTFMaterialsIorExtension( parser );
|
|
238
|
-
|
|
239
118
|
} );
|
|
240
|
-
|
|
241
119
|
this.register( function ( parser ) {
|
|
242
|
-
|
|
243
120
|
return new GLTFMaterialsEmissiveStrengthExtension( parser );
|
|
244
|
-
|
|
245
121
|
} );
|
|
246
|
-
|
|
247
122
|
this.register( function ( parser ) {
|
|
248
|
-
|
|
249
123
|
return new GLTFMaterialsSpecularExtension( parser );
|
|
250
|
-
|
|
251
124
|
} );
|
|
252
|
-
|
|
253
125
|
this.register( function ( parser ) {
|
|
254
|
-
|
|
255
126
|
return new GLTFMaterialsIridescenceExtension( parser );
|
|
256
|
-
|
|
257
127
|
} );
|
|
258
|
-
|
|
259
128
|
this.register( function ( parser ) {
|
|
260
|
-
|
|
261
129
|
return new GLTFMaterialsAnisotropyExtension( parser );
|
|
262
|
-
|
|
263
130
|
} );
|
|
264
|
-
|
|
265
131
|
this.register( function ( parser ) {
|
|
266
|
-
|
|
267
132
|
return new GLTFMaterialsBumpExtension( parser );
|
|
268
|
-
|
|
269
133
|
} );
|
|
270
|
-
|
|
271
134
|
this.register( function ( parser ) {
|
|
272
|
-
|
|
273
135
|
return new GLTFLightsExtension( parser );
|
|
274
|
-
|
|
275
136
|
} );
|
|
276
|
-
|
|
277
137
|
this.register( function ( parser ) {
|
|
278
|
-
|
|
279
138
|
return new GLTFMeshoptCompression( parser );
|
|
280
|
-
|
|
281
139
|
} );
|
|
282
|
-
|
|
283
140
|
this.register( function ( parser ) {
|
|
284
|
-
|
|
285
141
|
return new GLTFMeshGpuInstancing( parser );
|
|
286
|
-
|
|
287
142
|
} );
|
|
288
|
-
|
|
289
143
|
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Starts loading from the given URL and passes the loaded glTF asset
|
|
293
|
-
* to the `onLoad()` callback.
|
|
294
|
-
*
|
|
295
|
-
* @param {string} url - The path/URL of the file to be loaded. This can also be a data URI.
|
|
296
|
-
* @param {function(GLTFLoader~LoadObject)} onLoad - Executed when the loading process has been finished.
|
|
297
|
-
* @param {onProgressCallback} onProgress - Executed while the loading is in progress.
|
|
298
|
-
* @param {onErrorCallback} onError - Executed when errors occur.
|
|
299
|
-
*/
|
|
300
144
|
load( url, onLoad, onProgress, onError ) {
|
|
301
|
-
|
|
302
145
|
const scope = this;
|
|
303
|
-
|
|
304
146
|
let resourcePath;
|
|
305
|
-
|
|
306
147
|
if ( this.resourcePath !== '' ) {
|
|
307
|
-
|
|
308
148
|
resourcePath = this.resourcePath;
|
|
309
|
-
|
|
310
149
|
} else if ( this.path !== '' ) {
|
|
311
|
-
|
|
312
|
-
// If a base path is set, resources will be relative paths from that plus the relative path of the gltf file
|
|
313
|
-
// Example path = 'https://my-cnd-server.com/', url = 'assets/models/model.gltf'
|
|
314
|
-
// resourcePath = 'https://my-cnd-server.com/assets/models/'
|
|
315
|
-
// referenced resource 'model.bin' will be loaded from 'https://my-cnd-server.com/assets/models/model.bin'
|
|
316
|
-
// referenced resource '../textures/texture.png' will be loaded from 'https://my-cnd-server.com/assets/textures/texture.png'
|
|
317
150
|
const relativeUrl = three.LoaderUtils.extractUrlBase( url );
|
|
318
151
|
resourcePath = three.LoaderUtils.resolveURL( relativeUrl, this.path );
|
|
319
|
-
|
|
320
152
|
} else {
|
|
321
|
-
|
|
322
153
|
resourcePath = three.LoaderUtils.extractUrlBase( url );
|
|
323
|
-
|
|
324
154
|
}
|
|
325
|
-
|
|
326
|
-
// Tells the LoadingManager to track an extra item, which resolves after
|
|
327
|
-
// the model is fully loaded. This means the count of items loaded will
|
|
328
|
-
// be incorrect, but ensures manager.onLoad() does not fire early.
|
|
329
155
|
this.manager.itemStart( url );
|
|
330
|
-
|
|
331
156
|
const _onError = function ( e ) {
|
|
332
|
-
|
|
333
157
|
if ( onError ) {
|
|
334
|
-
|
|
335
158
|
onError( e );
|
|
336
|
-
|
|
337
159
|
} else {
|
|
338
|
-
|
|
339
160
|
console.error( e );
|
|
340
|
-
|
|
341
161
|
}
|
|
342
|
-
|
|
343
162
|
scope.manager.itemError( url );
|
|
344
163
|
scope.manager.itemEnd( url );
|
|
345
|
-
|
|
346
164
|
};
|
|
347
|
-
|
|
348
165
|
const loader = new three.FileLoader( this.manager );
|
|
349
|
-
|
|
350
166
|
loader.setPath( this.path );
|
|
351
167
|
loader.setResponseType( 'arraybuffer' );
|
|
352
168
|
loader.setRequestHeader( this.requestHeader );
|
|
353
169
|
loader.setWithCredentials( this.withCredentials );
|
|
354
|
-
|
|
355
170
|
loader.load( url, function ( data ) {
|
|
356
|
-
|
|
357
171
|
try {
|
|
358
|
-
|
|
359
172
|
scope.parse( data, resourcePath, function ( gltf ) {
|
|
360
|
-
|
|
361
173
|
onLoad( gltf );
|
|
362
|
-
|
|
363
174
|
scope.manager.itemEnd( url );
|
|
364
|
-
|
|
365
175
|
}, _onError );
|
|
366
|
-
|
|
367
176
|
} catch ( e ) {
|
|
368
|
-
|
|
369
177
|
_onError( e );
|
|
370
|
-
|
|
371
178
|
}
|
|
372
|
-
|
|
373
179
|
}, onProgress, _onError );
|
|
374
|
-
|
|
375
180
|
}
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Sets the given Draco loader to this loader. Required for decoding assets
|
|
379
|
-
* compressed with the `KHR_draco_mesh_compression` extension.
|
|
380
|
-
*
|
|
381
|
-
* @param {DRACOLoader} dracoLoader - The Draco loader to set.
|
|
382
|
-
* @return {GLTFLoader} A reference to this loader.
|
|
383
|
-
*/
|
|
384
181
|
setDRACOLoader( dracoLoader ) {
|
|
385
|
-
|
|
386
182
|
this.dracoLoader = dracoLoader;
|
|
387
183
|
return this;
|
|
388
|
-
|
|
389
184
|
}
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* Sets the given KTX2 loader to this loader. Required for loading KTX2
|
|
393
|
-
* compressed textures.
|
|
394
|
-
*
|
|
395
|
-
* @param {KTX2Loader} ktx2Loader - The KTX2 loader to set.
|
|
396
|
-
* @return {GLTFLoader} A reference to this loader.
|
|
397
|
-
*/
|
|
398
185
|
setKTX2Loader( ktx2Loader ) {
|
|
399
|
-
|
|
400
186
|
this.ktx2Loader = ktx2Loader;
|
|
401
187
|
return this;
|
|
402
|
-
|
|
403
188
|
}
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Sets the given meshopt decoder. Required for decoding assets
|
|
407
|
-
* compressed with the `EXT_meshopt_compression` extension.
|
|
408
|
-
*
|
|
409
|
-
* @param {Object} meshoptDecoder - The meshopt decoder to set.
|
|
410
|
-
* @return {GLTFLoader} A reference to this loader.
|
|
411
|
-
*/
|
|
412
189
|
setMeshoptDecoder( meshoptDecoder ) {
|
|
413
|
-
|
|
414
190
|
this.meshoptDecoder = meshoptDecoder;
|
|
415
191
|
return this;
|
|
416
|
-
|
|
417
192
|
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Registers a plugin callback. This API is internally used to implement the various
|
|
421
|
-
* glTF extensions but can also used by third-party code to add additional logic
|
|
422
|
-
* to the loader.
|
|
423
|
-
*
|
|
424
|
-
* @param {function(parser:GLTFParser)} callback - The callback function to register.
|
|
425
|
-
* @return {GLTFLoader} A reference to this loader.
|
|
426
|
-
*/
|
|
427
193
|
register( callback ) {
|
|
428
|
-
|
|
429
194
|
if ( this.pluginCallbacks.indexOf( callback ) === -1 ) {
|
|
430
|
-
|
|
431
195
|
this.pluginCallbacks.push( callback );
|
|
432
|
-
|
|
433
196
|
}
|
|
434
|
-
|
|
435
197
|
return this;
|
|
436
|
-
|
|
437
198
|
}
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Unregisters a plugin callback.
|
|
441
|
-
*
|
|
442
|
-
* @param {Function} callback - The callback function to unregister.
|
|
443
|
-
* @return {GLTFLoader} A reference to this loader.
|
|
444
|
-
*/
|
|
445
199
|
unregister( callback ) {
|
|
446
|
-
|
|
447
200
|
if ( this.pluginCallbacks.indexOf( callback ) !== -1 ) {
|
|
448
|
-
|
|
449
201
|
this.pluginCallbacks.splice( this.pluginCallbacks.indexOf( callback ), 1 );
|
|
450
|
-
|
|
451
202
|
}
|
|
452
|
-
|
|
453
203
|
return this;
|
|
454
|
-
|
|
455
204
|
}
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* Parses the given FBX data and returns the resulting group.
|
|
459
|
-
*
|
|
460
|
-
* @param {string|ArrayBuffer} data - The raw glTF data.
|
|
461
|
-
* @param {string} path - The URL base path.
|
|
462
|
-
* @param {function(GLTFLoader~LoadObject)} onLoad - Executed when the loading process has been finished.
|
|
463
|
-
* @param {onErrorCallback} onError - Executed when errors occur.
|
|
464
|
-
*/
|
|
465
205
|
parse( data, path, onLoad, onError ) {
|
|
466
|
-
|
|
467
206
|
let json;
|
|
468
207
|
const extensions = {};
|
|
469
208
|
const plugins = {};
|
|
470
209
|
const textDecoder = new TextDecoder();
|
|
471
|
-
|
|
472
210
|
if ( typeof data === 'string' ) {
|
|
473
|
-
|
|
474
211
|
json = JSON.parse( data );
|
|
475
|
-
|
|
476
212
|
} else if ( data instanceof ArrayBuffer ) {
|
|
477
|
-
|
|
478
213
|
const magic = textDecoder.decode( new Uint8Array( data, 0, 4 ) );
|
|
479
|
-
|
|
480
214
|
if ( magic === BINARY_EXTENSION_HEADER_MAGIC ) {
|
|
481
|
-
|
|
482
215
|
try {
|
|
483
|
-
|
|
484
216
|
extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data );
|
|
485
|
-
|
|
486
217
|
} catch ( error ) {
|
|
487
|
-
|
|
488
218
|
if ( onError ) onError( error );
|
|
489
219
|
return;
|
|
490
|
-
|
|
491
220
|
}
|
|
492
|
-
|
|
493
221
|
json = JSON.parse( extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content );
|
|
494
|
-
|
|
495
222
|
} else {
|
|
496
|
-
|
|
497
223
|
json = JSON.parse( textDecoder.decode( data ) );
|
|
498
|
-
|
|
499
224
|
}
|
|
500
|
-
|
|
501
225
|
} else {
|
|
502
|
-
|
|
503
226
|
json = data;
|
|
504
|
-
|
|
505
227
|
}
|
|
506
|
-
|
|
507
228
|
if ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) {
|
|
508
|
-
|
|
509
229
|
if ( onError ) onError( new Error( 'THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported.' ) );
|
|
510
230
|
return;
|
|
511
|
-
|
|
512
231
|
}
|
|
513
|
-
|
|
514
232
|
const parser = new GLTFParser( json, {
|
|
515
|
-
|
|
516
233
|
path: path || this.resourcePath || '',
|
|
517
234
|
crossOrigin: this.crossOrigin,
|
|
518
235
|
requestHeader: this.requestHeader,
|
|
519
236
|
manager: this.manager,
|
|
520
237
|
ktx2Loader: this.ktx2Loader,
|
|
521
238
|
meshoptDecoder: this.meshoptDecoder
|
|
522
|
-
|
|
523
239
|
} );
|
|
524
|
-
|
|
525
240
|
parser.fileLoader.setRequestHeader( this.requestHeader );
|
|
526
|
-
|
|
527
241
|
for ( let i = 0; i < this.pluginCallbacks.length; i ++ ) {
|
|
528
|
-
|
|
529
242
|
const plugin = this.pluginCallbacks[ i ]( parser );
|
|
530
|
-
|
|
531
243
|
if ( ! plugin.name ) console.error( 'THREE.GLTFLoader: Invalid plugin found: missing name' );
|
|
532
|
-
|
|
533
244
|
plugins[ plugin.name ] = plugin;
|
|
534
|
-
|
|
535
|
-
// Workaround to avoid determining as unknown extension
|
|
536
|
-
// in addUnknownExtensionsToUserData().
|
|
537
|
-
// Remove this workaround if we move all the existing
|
|
538
|
-
// extension handlers to plugin system
|
|
539
245
|
extensions[ plugin.name ] = true;
|
|
540
|
-
|
|
541
246
|
}
|
|
542
|
-
|
|
543
247
|
if ( json.extensionsUsed ) {
|
|
544
|
-
|
|
545
248
|
for ( let i = 0; i < json.extensionsUsed.length; ++ i ) {
|
|
546
|
-
|
|
547
249
|
const extensionName = json.extensionsUsed[ i ];
|
|
548
250
|
const extensionsRequired = json.extensionsRequired || [];
|
|
549
|
-
|
|
550
251
|
switch ( extensionName ) {
|
|
551
|
-
|
|
552
252
|
case EXTENSIONS.KHR_MATERIALS_UNLIT:
|
|
553
253
|
extensions[ extensionName ] = new GLTFMaterialsUnlitExtension();
|
|
554
254
|
break;
|
|
555
|
-
|
|
556
255
|
case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
|
|
557
256
|
extensions[ extensionName ] = new GLTFDracoMeshCompressionExtension( json, this.dracoLoader );
|
|
558
257
|
break;
|
|
559
|
-
|
|
560
258
|
case EXTENSIONS.KHR_TEXTURE_TRANSFORM:
|
|
561
259
|
extensions[ extensionName ] = new GLTFTextureTransformExtension();
|
|
562
260
|
break;
|
|
563
|
-
|
|
564
261
|
case EXTENSIONS.KHR_MESH_QUANTIZATION:
|
|
565
262
|
extensions[ extensionName ] = new GLTFMeshQuantizationExtension();
|
|
566
263
|
break;
|
|
567
|
-
|
|
568
264
|
default:
|
|
569
|
-
|
|
570
265
|
if ( extensionsRequired.indexOf( extensionName ) >= 0 && plugins[ extensionName ] === undefined ) {
|
|
571
|
-
|
|
572
266
|
console.warn( 'THREE.GLTFLoader: Unknown extension "' + extensionName + '".' );
|
|
573
|
-
|
|
574
267
|
}
|
|
575
|
-
|
|
576
268
|
}
|
|
577
|
-
|
|
578
269
|
}
|
|
579
|
-
|
|
580
270
|
}
|
|
581
|
-
|
|
582
271
|
parser.setExtensions( extensions );
|
|
583
272
|
parser.setPlugins( plugins );
|
|
584
273
|
parser.parse( onLoad, onError );
|
|
585
|
-
|
|
586
274
|
}
|
|
587
|
-
|
|
588
|
-
/**
|
|
589
|
-
* Async version of {@link GLTFLoader#parse}.
|
|
590
|
-
*
|
|
591
|
-
* @async
|
|
592
|
-
* @param {string|ArrayBuffer} data - The raw glTF data.
|
|
593
|
-
* @param {string} path - The URL base path.
|
|
594
|
-
* @return {Promise<GLTFLoader~LoadObject>} A Promise that resolves with the loaded glTF when the parsing has been finished.
|
|
595
|
-
*/
|
|
596
275
|
parseAsync( data, path ) {
|
|
597
|
-
|
|
598
276
|
const scope = this;
|
|
599
|
-
|
|
600
277
|
return new Promise( function ( resolve, reject ) {
|
|
601
|
-
|
|
602
278
|
scope.parse( data, path, resolve, reject );
|
|
603
|
-
|
|
604
279
|
} );
|
|
605
|
-
|
|
606
280
|
}
|
|
607
|
-
|
|
608
281
|
}
|
|
609
|
-
|
|
610
|
-
/* GLTFREGISTRY */
|
|
611
|
-
|
|
612
282
|
function GLTFRegistry() {
|
|
613
|
-
|
|
614
283
|
let objects = {};
|
|
615
|
-
|
|
616
284
|
return {
|
|
617
|
-
|
|
618
285
|
get: function ( key ) {
|
|
619
|
-
|
|
620
286
|
return objects[ key ];
|
|
621
|
-
|
|
622
287
|
},
|
|
623
|
-
|
|
624
288
|
add: function ( key, object ) {
|
|
625
|
-
|
|
626
289
|
objects[ key ] = object;
|
|
627
|
-
|
|
628
290
|
},
|
|
629
|
-
|
|
630
291
|
remove: function ( key ) {
|
|
631
|
-
|
|
632
292
|
delete objects[ key ];
|
|
633
|
-
|
|
634
293
|
},
|
|
635
|
-
|
|
636
294
|
removeAll: function () {
|
|
637
|
-
|
|
638
295
|
objects = {};
|
|
639
|
-
|
|
640
296
|
}
|
|
641
|
-
|
|
642
297
|
};
|
|
643
|
-
|
|
644
298
|
}
|
|
645
|
-
|
|
646
|
-
/*********************************/
|
|
647
|
-
/********** EXTENSIONS ***********/
|
|
648
|
-
/*********************************/
|
|
649
|
-
|
|
650
299
|
const EXTENSIONS = {
|
|
651
300
|
KHR_BINARY_GLTF: 'KHR_binary_glTF',
|
|
652
301
|
KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',
|
|
@@ -671,84 +320,50 @@
|
|
|
671
320
|
EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression',
|
|
672
321
|
EXT_MESH_GPU_INSTANCING: 'EXT_mesh_gpu_instancing'
|
|
673
322
|
};
|
|
674
|
-
|
|
675
|
-
/**
|
|
676
|
-
* Punctual Lights Extension
|
|
677
|
-
*
|
|
678
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
|
|
679
|
-
*
|
|
680
|
-
* @private
|
|
681
|
-
*/
|
|
682
323
|
class GLTFLightsExtension {
|
|
683
|
-
|
|
684
324
|
constructor( parser ) {
|
|
685
|
-
|
|
686
325
|
this.parser = parser;
|
|
687
326
|
this.name = EXTENSIONS.KHR_LIGHTS_PUNCTUAL;
|
|
688
|
-
|
|
689
|
-
// Object3D instance caches
|
|
690
327
|
this.cache = { refs: {}, uses: {} };
|
|
691
|
-
|
|
692
328
|
}
|
|
693
|
-
|
|
694
329
|
_markDefs() {
|
|
695
|
-
|
|
696
330
|
const parser = this.parser;
|
|
697
331
|
const nodeDefs = this.parser.json.nodes || [];
|
|
698
|
-
|
|
699
332
|
for ( let nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex ++ ) {
|
|
700
|
-
|
|
701
333
|
const nodeDef = nodeDefs[ nodeIndex ];
|
|
702
|
-
|
|
703
334
|
if ( nodeDef.extensions
|
|
704
335
|
&& nodeDef.extensions[ this.name ]
|
|
705
336
|
&& nodeDef.extensions[ this.name ].light !== undefined ) {
|
|
706
|
-
|
|
707
337
|
parser._addNodeRef( this.cache, nodeDef.extensions[ this.name ].light );
|
|
708
|
-
|
|
709
338
|
}
|
|
710
|
-
|
|
711
339
|
}
|
|
712
|
-
|
|
713
340
|
}
|
|
714
|
-
|
|
715
341
|
_loadLight( lightIndex ) {
|
|
716
|
-
|
|
717
342
|
const parser = this.parser;
|
|
718
343
|
const cacheKey = 'light:' + lightIndex;
|
|
719
344
|
let dependency = parser.cache.get( cacheKey );
|
|
720
|
-
|
|
721
345
|
if ( dependency ) return dependency;
|
|
722
|
-
|
|
723
346
|
const json = parser.json;
|
|
724
347
|
const extensions = ( json.extensions && json.extensions[ this.name ] ) || {};
|
|
725
348
|
const lightDefs = extensions.lights || [];
|
|
726
349
|
const lightDef = lightDefs[ lightIndex ];
|
|
727
350
|
let lightNode;
|
|
728
|
-
|
|
729
351
|
const color = new three.Color( 0xffffff );
|
|
730
|
-
|
|
731
352
|
if ( lightDef.color !== undefined ) color.setRGB( lightDef.color[ 0 ], lightDef.color[ 1 ], lightDef.color[ 2 ], three.LinearSRGBColorSpace );
|
|
732
|
-
|
|
733
353
|
const range = lightDef.range !== undefined ? lightDef.range : 0;
|
|
734
|
-
|
|
735
354
|
switch ( lightDef.type ) {
|
|
736
|
-
|
|
737
355
|
case 'directional':
|
|
738
356
|
lightNode = new three.DirectionalLight( color );
|
|
739
357
|
lightNode.target.position.set( 0, 0, -1 );
|
|
740
358
|
lightNode.add( lightNode.target );
|
|
741
359
|
break;
|
|
742
|
-
|
|
743
360
|
case 'point':
|
|
744
361
|
lightNode = new three.PointLight( color );
|
|
745
362
|
lightNode.distance = range;
|
|
746
363
|
break;
|
|
747
|
-
|
|
748
364
|
case 'spot':
|
|
749
365
|
lightNode = new three.SpotLight( color );
|
|
750
366
|
lightNode.distance = range;
|
|
751
|
-
// Handle spotlight properties.
|
|
752
367
|
lightDef.spot = lightDef.spot || {};
|
|
753
368
|
lightDef.spot.innerConeAngle = lightDef.spot.innerConeAngle !== undefined ? lightDef.spot.innerConeAngle : 0;
|
|
754
369
|
lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0;
|
|
@@ -757,1303 +372,634 @@
|
|
|
757
372
|
lightNode.target.position.set( 0, 0, -1 );
|
|
758
373
|
lightNode.add( lightNode.target );
|
|
759
374
|
break;
|
|
760
|
-
|
|
761
375
|
default:
|
|
762
376
|
throw new Error( 'THREE.GLTFLoader: Unexpected light type: ' + lightDef.type );
|
|
763
|
-
|
|
764
377
|
}
|
|
765
|
-
|
|
766
|
-
// Some lights (e.g. spot) default to a position other than the origin. Reset the position
|
|
767
|
-
// here, because node-level parsing will only override position if explicitly specified.
|
|
768
378
|
lightNode.position.set( 0, 0, 0 );
|
|
769
|
-
|
|
770
379
|
assignExtrasToUserData( lightNode, lightDef );
|
|
771
|
-
|
|
772
380
|
if ( lightDef.intensity !== undefined ) lightNode.intensity = lightDef.intensity;
|
|
773
|
-
|
|
774
381
|
lightNode.name = parser.createUniqueName( lightDef.name || ( 'light_' + lightIndex ) );
|
|
775
|
-
|
|
776
382
|
dependency = Promise.resolve( lightNode );
|
|
777
|
-
|
|
778
383
|
parser.cache.add( cacheKey, dependency );
|
|
779
|
-
|
|
780
384
|
return dependency;
|
|
781
|
-
|
|
782
385
|
}
|
|
783
|
-
|
|
784
386
|
getDependency( type, index ) {
|
|
785
|
-
|
|
786
387
|
if ( type !== 'light' ) return;
|
|
787
|
-
|
|
788
388
|
return this._loadLight( index );
|
|
789
|
-
|
|
790
389
|
}
|
|
791
|
-
|
|
792
390
|
createNodeAttachment( nodeIndex ) {
|
|
793
|
-
|
|
794
391
|
const self = this;
|
|
795
392
|
const parser = this.parser;
|
|
796
393
|
const json = parser.json;
|
|
797
394
|
const nodeDef = json.nodes[ nodeIndex ];
|
|
798
395
|
const lightDef = ( nodeDef.extensions && nodeDef.extensions[ this.name ] ) || {};
|
|
799
396
|
const lightIndex = lightDef.light;
|
|
800
|
-
|
|
801
397
|
if ( lightIndex === undefined ) return null;
|
|
802
|
-
|
|
803
398
|
return this._loadLight( lightIndex ).then( function ( light ) {
|
|
804
|
-
|
|
805
399
|
return parser._getNodeRef( self.cache, lightIndex, light );
|
|
806
|
-
|
|
807
400
|
} );
|
|
808
|
-
|
|
809
401
|
}
|
|
810
|
-
|
|
811
402
|
}
|
|
812
|
-
|
|
813
|
-
/**
|
|
814
|
-
* Unlit Materials Extension
|
|
815
|
-
*
|
|
816
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit
|
|
817
|
-
*
|
|
818
|
-
* @private
|
|
819
|
-
*/
|
|
820
403
|
class GLTFMaterialsUnlitExtension {
|
|
821
|
-
|
|
822
404
|
constructor() {
|
|
823
|
-
|
|
824
405
|
this.name = EXTENSIONS.KHR_MATERIALS_UNLIT;
|
|
825
|
-
|
|
826
406
|
}
|
|
827
|
-
|
|
828
407
|
getMaterialType() {
|
|
829
|
-
|
|
830
408
|
return three.MeshBasicMaterial;
|
|
831
|
-
|
|
832
409
|
}
|
|
833
|
-
|
|
834
410
|
extendParams( materialParams, materialDef, parser ) {
|
|
835
|
-
|
|
836
411
|
const pending = [];
|
|
837
|
-
|
|
838
412
|
materialParams.color = new three.Color( 1.0, 1.0, 1.0 );
|
|
839
413
|
materialParams.opacity = 1.0;
|
|
840
|
-
|
|
841
414
|
const metallicRoughness = materialDef.pbrMetallicRoughness;
|
|
842
|
-
|
|
843
415
|
if ( metallicRoughness ) {
|
|
844
|
-
|
|
845
416
|
if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
|
|
846
|
-
|
|
847
417
|
const array = metallicRoughness.baseColorFactor;
|
|
848
|
-
|
|
849
418
|
materialParams.color.setRGB( array[ 0 ], array[ 1 ], array[ 2 ], three.LinearSRGBColorSpace );
|
|
850
419
|
materialParams.opacity = array[ 3 ];
|
|
851
|
-
|
|
852
420
|
}
|
|
853
|
-
|
|
854
421
|
if ( metallicRoughness.baseColorTexture !== undefined ) {
|
|
855
|
-
|
|
856
422
|
pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture, three.SRGBColorSpace ) );
|
|
857
|
-
|
|
858
423
|
}
|
|
859
|
-
|
|
860
424
|
}
|
|
861
|
-
|
|
862
425
|
return Promise.all( pending );
|
|
863
|
-
|
|
864
426
|
}
|
|
865
|
-
|
|
866
427
|
}
|
|
867
|
-
|
|
868
|
-
/**
|
|
869
|
-
* Materials Emissive Strength Extension
|
|
870
|
-
*
|
|
871
|
-
* Specification: https://github.com/KhronosGroup/glTF/blob/5768b3ce0ef32bc39cdf1bef10b948586635ead3/extensions/2.0/Khronos/KHR_materials_emissive_strength/README.md
|
|
872
|
-
*
|
|
873
|
-
* @private
|
|
874
|
-
*/
|
|
875
428
|
class GLTFMaterialsEmissiveStrengthExtension {
|
|
876
|
-
|
|
877
429
|
constructor( parser ) {
|
|
878
|
-
|
|
879
430
|
this.parser = parser;
|
|
880
431
|
this.name = EXTENSIONS.KHR_MATERIALS_EMISSIVE_STRENGTH;
|
|
881
|
-
|
|
882
432
|
}
|
|
883
|
-
|
|
884
433
|
extendMaterialParams( materialIndex, materialParams ) {
|
|
885
|
-
|
|
886
434
|
const parser = this.parser;
|
|
887
435
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
888
|
-
|
|
889
436
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
|
|
890
|
-
|
|
891
437
|
return Promise.resolve();
|
|
892
|
-
|
|
893
438
|
}
|
|
894
|
-
|
|
895
439
|
const emissiveStrength = materialDef.extensions[ this.name ].emissiveStrength;
|
|
896
|
-
|
|
897
440
|
if ( emissiveStrength !== undefined ) {
|
|
898
|
-
|
|
899
441
|
materialParams.emissiveIntensity = emissiveStrength;
|
|
900
|
-
|
|
901
442
|
}
|
|
902
|
-
|
|
903
443
|
return Promise.resolve();
|
|
904
|
-
|
|
905
444
|
}
|
|
906
|
-
|
|
907
445
|
}
|
|
908
|
-
|
|
909
|
-
/**
|
|
910
|
-
* Clearcoat Materials Extension
|
|
911
|
-
*
|
|
912
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_clearcoat
|
|
913
|
-
*
|
|
914
|
-
* @private
|
|
915
|
-
*/
|
|
916
446
|
class GLTFMaterialsClearcoatExtension {
|
|
917
|
-
|
|
918
447
|
constructor( parser ) {
|
|
919
|
-
|
|
920
448
|
this.parser = parser;
|
|
921
449
|
this.name = EXTENSIONS.KHR_MATERIALS_CLEARCOAT;
|
|
922
|
-
|
|
923
450
|
}
|
|
924
|
-
|
|
925
451
|
getMaterialType( materialIndex ) {
|
|
926
|
-
|
|
927
452
|
const parser = this.parser;
|
|
928
453
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
929
|
-
|
|
930
454
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
|
|
931
|
-
|
|
932
455
|
return three.MeshPhysicalMaterial;
|
|
933
|
-
|
|
934
456
|
}
|
|
935
|
-
|
|
936
457
|
extendMaterialParams( materialIndex, materialParams ) {
|
|
937
|
-
|
|
938
458
|
const parser = this.parser;
|
|
939
459
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
940
|
-
|
|
941
460
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
|
|
942
|
-
|
|
943
461
|
return Promise.resolve();
|
|
944
|
-
|
|
945
462
|
}
|
|
946
|
-
|
|
947
463
|
const pending = [];
|
|
948
|
-
|
|
949
464
|
const extension = materialDef.extensions[ this.name ];
|
|
950
|
-
|
|
951
465
|
if ( extension.clearcoatFactor !== undefined ) {
|
|
952
|
-
|
|
953
466
|
materialParams.clearcoat = extension.clearcoatFactor;
|
|
954
|
-
|
|
955
467
|
}
|
|
956
|
-
|
|
957
468
|
if ( extension.clearcoatTexture !== undefined ) {
|
|
958
|
-
|
|
959
469
|
pending.push( parser.assignTexture( materialParams, 'clearcoatMap', extension.clearcoatTexture ) );
|
|
960
|
-
|
|
961
470
|
}
|
|
962
|
-
|
|
963
471
|
if ( extension.clearcoatRoughnessFactor !== undefined ) {
|
|
964
|
-
|
|
965
472
|
materialParams.clearcoatRoughness = extension.clearcoatRoughnessFactor;
|
|
966
|
-
|
|
967
473
|
}
|
|
968
|
-
|
|
969
474
|
if ( extension.clearcoatRoughnessTexture !== undefined ) {
|
|
970
|
-
|
|
971
475
|
pending.push( parser.assignTexture( materialParams, 'clearcoatRoughnessMap', extension.clearcoatRoughnessTexture ) );
|
|
972
|
-
|
|
973
476
|
}
|
|
974
|
-
|
|
975
477
|
if ( extension.clearcoatNormalTexture !== undefined ) {
|
|
976
|
-
|
|
977
478
|
pending.push( parser.assignTexture( materialParams, 'clearcoatNormalMap', extension.clearcoatNormalTexture ) );
|
|
978
|
-
|
|
979
479
|
if ( extension.clearcoatNormalTexture.scale !== undefined ) {
|
|
980
|
-
|
|
981
480
|
const scale = extension.clearcoatNormalTexture.scale;
|
|
982
|
-
|
|
983
481
|
materialParams.clearcoatNormalScale = new three.Vector2( scale, scale );
|
|
984
|
-
|
|
985
482
|
}
|
|
986
|
-
|
|
987
483
|
}
|
|
988
|
-
|
|
989
484
|
return Promise.all( pending );
|
|
990
|
-
|
|
991
485
|
}
|
|
992
|
-
|
|
993
486
|
}
|
|
994
|
-
|
|
995
|
-
/**
|
|
996
|
-
* Materials dispersion Extension
|
|
997
|
-
*
|
|
998
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_dispersion
|
|
999
|
-
*
|
|
1000
|
-
* @private
|
|
1001
|
-
*/
|
|
1002
487
|
class GLTFMaterialsDispersionExtension {
|
|
1003
|
-
|
|
1004
488
|
constructor( parser ) {
|
|
1005
|
-
|
|
1006
489
|
this.parser = parser;
|
|
1007
490
|
this.name = EXTENSIONS.KHR_MATERIALS_DISPERSION;
|
|
1008
|
-
|
|
1009
491
|
}
|
|
1010
|
-
|
|
1011
492
|
getMaterialType( materialIndex ) {
|
|
1012
|
-
|
|
1013
493
|
const parser = this.parser;
|
|
1014
494
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1015
|
-
|
|
1016
495
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
|
|
1017
|
-
|
|
1018
496
|
return three.MeshPhysicalMaterial;
|
|
1019
|
-
|
|
1020
497
|
}
|
|
1021
|
-
|
|
1022
498
|
extendMaterialParams( materialIndex, materialParams ) {
|
|
1023
|
-
|
|
1024
499
|
const parser = this.parser;
|
|
1025
500
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1026
|
-
|
|
1027
501
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
|
|
1028
|
-
|
|
1029
502
|
return Promise.resolve();
|
|
1030
|
-
|
|
1031
503
|
}
|
|
1032
|
-
|
|
1033
504
|
const extension = materialDef.extensions[ this.name ];
|
|
1034
|
-
|
|
1035
505
|
materialParams.dispersion = extension.dispersion !== undefined ? extension.dispersion : 0;
|
|
1036
|
-
|
|
1037
506
|
return Promise.resolve();
|
|
1038
|
-
|
|
1039
507
|
}
|
|
1040
|
-
|
|
1041
508
|
}
|
|
1042
|
-
|
|
1043
|
-
/**
|
|
1044
|
-
* Iridescence Materials Extension
|
|
1045
|
-
*
|
|
1046
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_iridescence
|
|
1047
|
-
*
|
|
1048
|
-
* @private
|
|
1049
|
-
*/
|
|
1050
509
|
class GLTFMaterialsIridescenceExtension {
|
|
1051
|
-
|
|
1052
510
|
constructor( parser ) {
|
|
1053
|
-
|
|
1054
511
|
this.parser = parser;
|
|
1055
512
|
this.name = EXTENSIONS.KHR_MATERIALS_IRIDESCENCE;
|
|
1056
|
-
|
|
1057
513
|
}
|
|
1058
|
-
|
|
1059
514
|
getMaterialType( materialIndex ) {
|
|
1060
|
-
|
|
1061
515
|
const parser = this.parser;
|
|
1062
516
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1063
|
-
|
|
1064
517
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
|
|
1065
|
-
|
|
1066
518
|
return three.MeshPhysicalMaterial;
|
|
1067
|
-
|
|
1068
519
|
}
|
|
1069
|
-
|
|
1070
520
|
extendMaterialParams( materialIndex, materialParams ) {
|
|
1071
|
-
|
|
1072
521
|
const parser = this.parser;
|
|
1073
522
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1074
|
-
|
|
1075
523
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
|
|
1076
|
-
|
|
1077
524
|
return Promise.resolve();
|
|
1078
|
-
|
|
1079
525
|
}
|
|
1080
|
-
|
|
1081
526
|
const pending = [];
|
|
1082
|
-
|
|
1083
527
|
const extension = materialDef.extensions[ this.name ];
|
|
1084
|
-
|
|
1085
528
|
if ( extension.iridescenceFactor !== undefined ) {
|
|
1086
|
-
|
|
1087
529
|
materialParams.iridescence = extension.iridescenceFactor;
|
|
1088
|
-
|
|
1089
530
|
}
|
|
1090
|
-
|
|
1091
531
|
if ( extension.iridescenceTexture !== undefined ) {
|
|
1092
|
-
|
|
1093
532
|
pending.push( parser.assignTexture( materialParams, 'iridescenceMap', extension.iridescenceTexture ) );
|
|
1094
|
-
|
|
1095
533
|
}
|
|
1096
|
-
|
|
1097
534
|
if ( extension.iridescenceIor !== undefined ) {
|
|
1098
|
-
|
|
1099
535
|
materialParams.iridescenceIOR = extension.iridescenceIor;
|
|
1100
|
-
|
|
1101
536
|
}
|
|
1102
|
-
|
|
1103
537
|
if ( materialParams.iridescenceThicknessRange === undefined ) {
|
|
1104
|
-
|
|
1105
538
|
materialParams.iridescenceThicknessRange = [ 100, 400 ];
|
|
1106
|
-
|
|
1107
539
|
}
|
|
1108
|
-
|
|
1109
540
|
if ( extension.iridescenceThicknessMinimum !== undefined ) {
|
|
1110
|
-
|
|
1111
541
|
materialParams.iridescenceThicknessRange[ 0 ] = extension.iridescenceThicknessMinimum;
|
|
1112
|
-
|
|
1113
542
|
}
|
|
1114
|
-
|
|
1115
543
|
if ( extension.iridescenceThicknessMaximum !== undefined ) {
|
|
1116
|
-
|
|
1117
544
|
materialParams.iridescenceThicknessRange[ 1 ] = extension.iridescenceThicknessMaximum;
|
|
1118
|
-
|
|
1119
545
|
}
|
|
1120
|
-
|
|
1121
546
|
if ( extension.iridescenceThicknessTexture !== undefined ) {
|
|
1122
|
-
|
|
1123
547
|
pending.push( parser.assignTexture( materialParams, 'iridescenceThicknessMap', extension.iridescenceThicknessTexture ) );
|
|
1124
|
-
|
|
1125
548
|
}
|
|
1126
|
-
|
|
1127
549
|
return Promise.all( pending );
|
|
1128
|
-
|
|
1129
550
|
}
|
|
1130
|
-
|
|
1131
551
|
}
|
|
1132
|
-
|
|
1133
|
-
/**
|
|
1134
|
-
* Sheen Materials Extension
|
|
1135
|
-
*
|
|
1136
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_sheen
|
|
1137
|
-
*
|
|
1138
|
-
* @private
|
|
1139
|
-
*/
|
|
1140
552
|
class GLTFMaterialsSheenExtension {
|
|
1141
|
-
|
|
1142
553
|
constructor( parser ) {
|
|
1143
|
-
|
|
1144
554
|
this.parser = parser;
|
|
1145
555
|
this.name = EXTENSIONS.KHR_MATERIALS_SHEEN;
|
|
1146
|
-
|
|
1147
556
|
}
|
|
1148
|
-
|
|
1149
557
|
getMaterialType( materialIndex ) {
|
|
1150
|
-
|
|
1151
558
|
const parser = this.parser;
|
|
1152
559
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1153
|
-
|
|
1154
560
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
|
|
1155
|
-
|
|
1156
561
|
return three.MeshPhysicalMaterial;
|
|
1157
|
-
|
|
1158
562
|
}
|
|
1159
|
-
|
|
1160
563
|
extendMaterialParams( materialIndex, materialParams ) {
|
|
1161
|
-
|
|
1162
564
|
const parser = this.parser;
|
|
1163
565
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1164
|
-
|
|
1165
566
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
|
|
1166
|
-
|
|
1167
567
|
return Promise.resolve();
|
|
1168
|
-
|
|
1169
568
|
}
|
|
1170
|
-
|
|
1171
569
|
const pending = [];
|
|
1172
|
-
|
|
1173
570
|
materialParams.sheenColor = new three.Color( 0, 0, 0 );
|
|
1174
571
|
materialParams.sheenRoughness = 0;
|
|
1175
572
|
materialParams.sheen = 1;
|
|
1176
|
-
|
|
1177
573
|
const extension = materialDef.extensions[ this.name ];
|
|
1178
|
-
|
|
1179
574
|
if ( extension.sheenColorFactor !== undefined ) {
|
|
1180
|
-
|
|
1181
575
|
const colorFactor = extension.sheenColorFactor;
|
|
1182
576
|
materialParams.sheenColor.setRGB( colorFactor[ 0 ], colorFactor[ 1 ], colorFactor[ 2 ], three.LinearSRGBColorSpace );
|
|
1183
|
-
|
|
1184
577
|
}
|
|
1185
|
-
|
|
1186
578
|
if ( extension.sheenRoughnessFactor !== undefined ) {
|
|
1187
|
-
|
|
1188
579
|
materialParams.sheenRoughness = extension.sheenRoughnessFactor;
|
|
1189
|
-
|
|
1190
580
|
}
|
|
1191
|
-
|
|
1192
581
|
if ( extension.sheenColorTexture !== undefined ) {
|
|
1193
|
-
|
|
1194
582
|
pending.push( parser.assignTexture( materialParams, 'sheenColorMap', extension.sheenColorTexture, three.SRGBColorSpace ) );
|
|
1195
|
-
|
|
1196
583
|
}
|
|
1197
|
-
|
|
1198
584
|
if ( extension.sheenRoughnessTexture !== undefined ) {
|
|
1199
|
-
|
|
1200
585
|
pending.push( parser.assignTexture( materialParams, 'sheenRoughnessMap', extension.sheenRoughnessTexture ) );
|
|
1201
|
-
|
|
1202
586
|
}
|
|
1203
|
-
|
|
1204
587
|
return Promise.all( pending );
|
|
1205
|
-
|
|
1206
588
|
}
|
|
1207
|
-
|
|
1208
589
|
}
|
|
1209
|
-
|
|
1210
|
-
/**
|
|
1211
|
-
* Transmission Materials Extension
|
|
1212
|
-
*
|
|
1213
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_transmission
|
|
1214
|
-
* Draft: https://github.com/KhronosGroup/glTF/pull/1698
|
|
1215
|
-
*
|
|
1216
|
-
* @private
|
|
1217
|
-
*/
|
|
1218
590
|
class GLTFMaterialsTransmissionExtension {
|
|
1219
|
-
|
|
1220
591
|
constructor( parser ) {
|
|
1221
|
-
|
|
1222
592
|
this.parser = parser;
|
|
1223
593
|
this.name = EXTENSIONS.KHR_MATERIALS_TRANSMISSION;
|
|
1224
|
-
|
|
1225
594
|
}
|
|
1226
|
-
|
|
1227
595
|
getMaterialType( materialIndex ) {
|
|
1228
|
-
|
|
1229
596
|
const parser = this.parser;
|
|
1230
597
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1231
|
-
|
|
1232
598
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
|
|
1233
|
-
|
|
1234
599
|
return three.MeshPhysicalMaterial;
|
|
1235
|
-
|
|
1236
600
|
}
|
|
1237
|
-
|
|
1238
601
|
extendMaterialParams( materialIndex, materialParams ) {
|
|
1239
|
-
|
|
1240
602
|
const parser = this.parser;
|
|
1241
603
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1242
|
-
|
|
1243
604
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
|
|
1244
|
-
|
|
1245
605
|
return Promise.resolve();
|
|
1246
|
-
|
|
1247
606
|
}
|
|
1248
|
-
|
|
1249
607
|
const pending = [];
|
|
1250
|
-
|
|
1251
608
|
const extension = materialDef.extensions[ this.name ];
|
|
1252
|
-
|
|
1253
609
|
if ( extension.transmissionFactor !== undefined ) {
|
|
1254
|
-
|
|
1255
610
|
materialParams.transmission = extension.transmissionFactor;
|
|
1256
|
-
|
|
1257
611
|
}
|
|
1258
|
-
|
|
1259
612
|
if ( extension.transmissionTexture !== undefined ) {
|
|
1260
|
-
|
|
1261
613
|
pending.push( parser.assignTexture( materialParams, 'transmissionMap', extension.transmissionTexture ) );
|
|
1262
|
-
|
|
1263
614
|
}
|
|
1264
|
-
|
|
1265
615
|
return Promise.all( pending );
|
|
1266
|
-
|
|
1267
616
|
}
|
|
1268
|
-
|
|
1269
617
|
}
|
|
1270
|
-
|
|
1271
|
-
/**
|
|
1272
|
-
* Materials Volume Extension
|
|
1273
|
-
*
|
|
1274
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_volume
|
|
1275
|
-
*
|
|
1276
|
-
* @private
|
|
1277
|
-
*/
|
|
1278
618
|
class GLTFMaterialsVolumeExtension {
|
|
1279
|
-
|
|
1280
619
|
constructor( parser ) {
|
|
1281
|
-
|
|
1282
620
|
this.parser = parser;
|
|
1283
621
|
this.name = EXTENSIONS.KHR_MATERIALS_VOLUME;
|
|
1284
|
-
|
|
1285
622
|
}
|
|
1286
|
-
|
|
1287
623
|
getMaterialType( materialIndex ) {
|
|
1288
|
-
|
|
1289
624
|
const parser = this.parser;
|
|
1290
625
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1291
|
-
|
|
1292
626
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
|
|
1293
|
-
|
|
1294
627
|
return three.MeshPhysicalMaterial;
|
|
1295
|
-
|
|
1296
628
|
}
|
|
1297
|
-
|
|
1298
629
|
extendMaterialParams( materialIndex, materialParams ) {
|
|
1299
|
-
|
|
1300
630
|
const parser = this.parser;
|
|
1301
631
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1302
|
-
|
|
1303
632
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
|
|
1304
|
-
|
|
1305
633
|
return Promise.resolve();
|
|
1306
|
-
|
|
1307
634
|
}
|
|
1308
|
-
|
|
1309
635
|
const pending = [];
|
|
1310
|
-
|
|
1311
636
|
const extension = materialDef.extensions[ this.name ];
|
|
1312
|
-
|
|
1313
637
|
materialParams.thickness = extension.thicknessFactor !== undefined ? extension.thicknessFactor : 0;
|
|
1314
|
-
|
|
1315
638
|
if ( extension.thicknessTexture !== undefined ) {
|
|
1316
|
-
|
|
1317
639
|
pending.push( parser.assignTexture( materialParams, 'thicknessMap', extension.thicknessTexture ) );
|
|
1318
|
-
|
|
1319
640
|
}
|
|
1320
|
-
|
|
1321
641
|
materialParams.attenuationDistance = extension.attenuationDistance || Infinity;
|
|
1322
|
-
|
|
1323
642
|
const colorArray = extension.attenuationColor || [ 1, 1, 1 ];
|
|
1324
643
|
materialParams.attenuationColor = new three.Color().setRGB( colorArray[ 0 ], colorArray[ 1 ], colorArray[ 2 ], three.LinearSRGBColorSpace );
|
|
1325
|
-
|
|
1326
644
|
return Promise.all( pending );
|
|
1327
|
-
|
|
1328
645
|
}
|
|
1329
|
-
|
|
1330
646
|
}
|
|
1331
|
-
|
|
1332
|
-
/**
|
|
1333
|
-
* Materials ior Extension
|
|
1334
|
-
*
|
|
1335
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_ior
|
|
1336
|
-
*
|
|
1337
|
-
* @private
|
|
1338
|
-
*/
|
|
1339
647
|
class GLTFMaterialsIorExtension {
|
|
1340
|
-
|
|
1341
648
|
constructor( parser ) {
|
|
1342
|
-
|
|
1343
649
|
this.parser = parser;
|
|
1344
650
|
this.name = EXTENSIONS.KHR_MATERIALS_IOR;
|
|
1345
|
-
|
|
1346
651
|
}
|
|
1347
|
-
|
|
1348
652
|
getMaterialType( materialIndex ) {
|
|
1349
|
-
|
|
1350
653
|
const parser = this.parser;
|
|
1351
654
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1352
|
-
|
|
1353
655
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
|
|
1354
|
-
|
|
1355
656
|
return three.MeshPhysicalMaterial;
|
|
1356
|
-
|
|
1357
657
|
}
|
|
1358
|
-
|
|
1359
658
|
extendMaterialParams( materialIndex, materialParams ) {
|
|
1360
|
-
|
|
1361
659
|
const parser = this.parser;
|
|
1362
660
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1363
|
-
|
|
1364
661
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
|
|
1365
|
-
|
|
1366
662
|
return Promise.resolve();
|
|
1367
|
-
|
|
1368
663
|
}
|
|
1369
|
-
|
|
1370
664
|
const extension = materialDef.extensions[ this.name ];
|
|
1371
|
-
|
|
1372
665
|
materialParams.ior = extension.ior !== undefined ? extension.ior : 1.5;
|
|
1373
|
-
|
|
1374
666
|
return Promise.resolve();
|
|
1375
|
-
|
|
1376
667
|
}
|
|
1377
|
-
|
|
1378
668
|
}
|
|
1379
|
-
|
|
1380
|
-
/**
|
|
1381
|
-
* Materials specular Extension
|
|
1382
|
-
*
|
|
1383
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_specular
|
|
1384
|
-
*
|
|
1385
|
-
* @private
|
|
1386
|
-
*/
|
|
1387
669
|
class GLTFMaterialsSpecularExtension {
|
|
1388
|
-
|
|
1389
670
|
constructor( parser ) {
|
|
1390
|
-
|
|
1391
671
|
this.parser = parser;
|
|
1392
672
|
this.name = EXTENSIONS.KHR_MATERIALS_SPECULAR;
|
|
1393
|
-
|
|
1394
673
|
}
|
|
1395
|
-
|
|
1396
674
|
getMaterialType( materialIndex ) {
|
|
1397
|
-
|
|
1398
675
|
const parser = this.parser;
|
|
1399
676
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1400
|
-
|
|
1401
677
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
|
|
1402
|
-
|
|
1403
678
|
return three.MeshPhysicalMaterial;
|
|
1404
|
-
|
|
1405
679
|
}
|
|
1406
|
-
|
|
1407
680
|
extendMaterialParams( materialIndex, materialParams ) {
|
|
1408
|
-
|
|
1409
681
|
const parser = this.parser;
|
|
1410
682
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1411
|
-
|
|
1412
683
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
|
|
1413
|
-
|
|
1414
684
|
return Promise.resolve();
|
|
1415
|
-
|
|
1416
685
|
}
|
|
1417
|
-
|
|
1418
686
|
const pending = [];
|
|
1419
|
-
|
|
1420
687
|
const extension = materialDef.extensions[ this.name ];
|
|
1421
|
-
|
|
1422
688
|
materialParams.specularIntensity = extension.specularFactor !== undefined ? extension.specularFactor : 1.0;
|
|
1423
|
-
|
|
1424
689
|
if ( extension.specularTexture !== undefined ) {
|
|
1425
|
-
|
|
1426
690
|
pending.push( parser.assignTexture( materialParams, 'specularIntensityMap', extension.specularTexture ) );
|
|
1427
|
-
|
|
1428
691
|
}
|
|
1429
|
-
|
|
1430
692
|
const colorArray = extension.specularColorFactor || [ 1, 1, 1 ];
|
|
1431
693
|
materialParams.specularColor = new three.Color().setRGB( colorArray[ 0 ], colorArray[ 1 ], colorArray[ 2 ], three.LinearSRGBColorSpace );
|
|
1432
|
-
|
|
1433
694
|
if ( extension.specularColorTexture !== undefined ) {
|
|
1434
|
-
|
|
1435
695
|
pending.push( parser.assignTexture( materialParams, 'specularColorMap', extension.specularColorTexture, three.SRGBColorSpace ) );
|
|
1436
|
-
|
|
1437
696
|
}
|
|
1438
|
-
|
|
1439
697
|
return Promise.all( pending );
|
|
1440
|
-
|
|
1441
698
|
}
|
|
1442
|
-
|
|
1443
699
|
}
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
/**
|
|
1447
|
-
* Materials bump Extension
|
|
1448
|
-
*
|
|
1449
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/EXT_materials_bump
|
|
1450
|
-
*
|
|
1451
|
-
* @private
|
|
1452
|
-
*/
|
|
1453
700
|
class GLTFMaterialsBumpExtension {
|
|
1454
|
-
|
|
1455
701
|
constructor( parser ) {
|
|
1456
|
-
|
|
1457
702
|
this.parser = parser;
|
|
1458
703
|
this.name = EXTENSIONS.EXT_MATERIALS_BUMP;
|
|
1459
|
-
|
|
1460
704
|
}
|
|
1461
|
-
|
|
1462
705
|
getMaterialType( materialIndex ) {
|
|
1463
|
-
|
|
1464
706
|
const parser = this.parser;
|
|
1465
707
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1466
|
-
|
|
1467
708
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
|
|
1468
|
-
|
|
1469
709
|
return three.MeshPhysicalMaterial;
|
|
1470
|
-
|
|
1471
710
|
}
|
|
1472
|
-
|
|
1473
711
|
extendMaterialParams( materialIndex, materialParams ) {
|
|
1474
|
-
|
|
1475
712
|
const parser = this.parser;
|
|
1476
713
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1477
|
-
|
|
1478
714
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
|
|
1479
|
-
|
|
1480
715
|
return Promise.resolve();
|
|
1481
|
-
|
|
1482
716
|
}
|
|
1483
|
-
|
|
1484
717
|
const pending = [];
|
|
1485
|
-
|
|
1486
718
|
const extension = materialDef.extensions[ this.name ];
|
|
1487
|
-
|
|
1488
719
|
materialParams.bumpScale = extension.bumpFactor !== undefined ? extension.bumpFactor : 1.0;
|
|
1489
|
-
|
|
1490
720
|
if ( extension.bumpTexture !== undefined ) {
|
|
1491
|
-
|
|
1492
721
|
pending.push( parser.assignTexture( materialParams, 'bumpMap', extension.bumpTexture ) );
|
|
1493
|
-
|
|
1494
722
|
}
|
|
1495
|
-
|
|
1496
723
|
return Promise.all( pending );
|
|
1497
|
-
|
|
1498
724
|
}
|
|
1499
|
-
|
|
1500
725
|
}
|
|
1501
|
-
|
|
1502
|
-
/**
|
|
1503
|
-
* Materials anisotropy Extension
|
|
1504
|
-
*
|
|
1505
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_anisotropy
|
|
1506
|
-
*
|
|
1507
|
-
* @private
|
|
1508
|
-
*/
|
|
1509
726
|
class GLTFMaterialsAnisotropyExtension {
|
|
1510
|
-
|
|
1511
727
|
constructor( parser ) {
|
|
1512
|
-
|
|
1513
728
|
this.parser = parser;
|
|
1514
729
|
this.name = EXTENSIONS.KHR_MATERIALS_ANISOTROPY;
|
|
1515
|
-
|
|
1516
730
|
}
|
|
1517
|
-
|
|
1518
731
|
getMaterialType( materialIndex ) {
|
|
1519
|
-
|
|
1520
732
|
const parser = this.parser;
|
|
1521
733
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1522
|
-
|
|
1523
734
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
|
|
1524
|
-
|
|
1525
735
|
return three.MeshPhysicalMaterial;
|
|
1526
|
-
|
|
1527
736
|
}
|
|
1528
|
-
|
|
1529
737
|
extendMaterialParams( materialIndex, materialParams ) {
|
|
1530
|
-
|
|
1531
738
|
const parser = this.parser;
|
|
1532
739
|
const materialDef = parser.json.materials[ materialIndex ];
|
|
1533
|
-
|
|
1534
740
|
if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
|
|
1535
|
-
|
|
1536
741
|
return Promise.resolve();
|
|
1537
|
-
|
|
1538
742
|
}
|
|
1539
|
-
|
|
1540
743
|
const pending = [];
|
|
1541
|
-
|
|
1542
744
|
const extension = materialDef.extensions[ this.name ];
|
|
1543
|
-
|
|
1544
745
|
if ( extension.anisotropyStrength !== undefined ) {
|
|
1545
|
-
|
|
1546
746
|
materialParams.anisotropy = extension.anisotropyStrength;
|
|
1547
|
-
|
|
1548
747
|
}
|
|
1549
|
-
|
|
1550
748
|
if ( extension.anisotropyRotation !== undefined ) {
|
|
1551
|
-
|
|
1552
749
|
materialParams.anisotropyRotation = extension.anisotropyRotation;
|
|
1553
|
-
|
|
1554
750
|
}
|
|
1555
|
-
|
|
1556
751
|
if ( extension.anisotropyTexture !== undefined ) {
|
|
1557
|
-
|
|
1558
752
|
pending.push( parser.assignTexture( materialParams, 'anisotropyMap', extension.anisotropyTexture ) );
|
|
1559
|
-
|
|
1560
753
|
}
|
|
1561
|
-
|
|
1562
754
|
return Promise.all( pending );
|
|
1563
|
-
|
|
1564
755
|
}
|
|
1565
|
-
|
|
1566
756
|
}
|
|
1567
|
-
|
|
1568
|
-
/**
|
|
1569
|
-
* BasisU Texture Extension
|
|
1570
|
-
*
|
|
1571
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_basisu
|
|
1572
|
-
*
|
|
1573
|
-
* @private
|
|
1574
|
-
*/
|
|
1575
757
|
class GLTFTextureBasisUExtension {
|
|
1576
|
-
|
|
1577
758
|
constructor( parser ) {
|
|
1578
|
-
|
|
1579
759
|
this.parser = parser;
|
|
1580
760
|
this.name = EXTENSIONS.KHR_TEXTURE_BASISU;
|
|
1581
|
-
|
|
1582
761
|
}
|
|
1583
|
-
|
|
1584
762
|
loadTexture( textureIndex ) {
|
|
1585
|
-
|
|
1586
763
|
const parser = this.parser;
|
|
1587
764
|
const json = parser.json;
|
|
1588
|
-
|
|
1589
765
|
const textureDef = json.textures[ textureIndex ];
|
|
1590
|
-
|
|
1591
766
|
if ( ! textureDef.extensions || ! textureDef.extensions[ this.name ] ) {
|
|
1592
|
-
|
|
1593
767
|
return null;
|
|
1594
|
-
|
|
1595
768
|
}
|
|
1596
|
-
|
|
1597
769
|
const extension = textureDef.extensions[ this.name ];
|
|
1598
770
|
const loader = parser.options.ktx2Loader;
|
|
1599
|
-
|
|
1600
771
|
if ( ! loader ) {
|
|
1601
|
-
|
|
1602
772
|
if ( json.extensionsRequired && json.extensionsRequired.indexOf( this.name ) >= 0 ) {
|
|
1603
|
-
|
|
1604
773
|
throw new Error( 'THREE.GLTFLoader: setKTX2Loader must be called before loading KTX2 textures' );
|
|
1605
|
-
|
|
1606
774
|
} else {
|
|
1607
|
-
|
|
1608
|
-
// Assumes that the extension is optional and that a fallback texture is present
|
|
1609
775
|
return null;
|
|
1610
|
-
|
|
1611
776
|
}
|
|
1612
|
-
|
|
1613
777
|
}
|
|
1614
|
-
|
|
1615
778
|
return parser.loadTextureImage( textureIndex, extension.source, loader );
|
|
1616
|
-
|
|
1617
779
|
}
|
|
1618
|
-
|
|
1619
780
|
}
|
|
1620
|
-
|
|
1621
|
-
/**
|
|
1622
|
-
* WebP Texture Extension
|
|
1623
|
-
*
|
|
1624
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_texture_webp
|
|
1625
|
-
*
|
|
1626
|
-
* @private
|
|
1627
|
-
*/
|
|
1628
781
|
class GLTFTextureWebPExtension {
|
|
1629
|
-
|
|
1630
782
|
constructor( parser ) {
|
|
1631
|
-
|
|
1632
783
|
this.parser = parser;
|
|
1633
784
|
this.name = EXTENSIONS.EXT_TEXTURE_WEBP;
|
|
1634
|
-
|
|
1635
785
|
}
|
|
1636
|
-
|
|
1637
786
|
loadTexture( textureIndex ) {
|
|
1638
|
-
|
|
1639
787
|
const name = this.name;
|
|
1640
788
|
const parser = this.parser;
|
|
1641
789
|
const json = parser.json;
|
|
1642
|
-
|
|
1643
790
|
const textureDef = json.textures[ textureIndex ];
|
|
1644
|
-
|
|
1645
791
|
if ( ! textureDef.extensions || ! textureDef.extensions[ name ] ) {
|
|
1646
|
-
|
|
1647
792
|
return null;
|
|
1648
|
-
|
|
1649
793
|
}
|
|
1650
|
-
|
|
1651
794
|
const extension = textureDef.extensions[ name ];
|
|
1652
795
|
const source = json.images[ extension.source ];
|
|
1653
|
-
|
|
1654
796
|
let loader = parser.textureLoader;
|
|
1655
797
|
if ( source.uri ) {
|
|
1656
|
-
|
|
1657
798
|
const handler = parser.options.manager.getHandler( source.uri );
|
|
1658
799
|
if ( handler !== null ) loader = handler;
|
|
1659
|
-
|
|
1660
800
|
}
|
|
1661
|
-
|
|
1662
801
|
return parser.loadTextureImage( textureIndex, extension.source, loader );
|
|
1663
|
-
|
|
1664
802
|
}
|
|
1665
|
-
|
|
1666
803
|
}
|
|
1667
|
-
|
|
1668
|
-
/**
|
|
1669
|
-
* AVIF Texture Extension
|
|
1670
|
-
*
|
|
1671
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_texture_avif
|
|
1672
|
-
*
|
|
1673
|
-
* @private
|
|
1674
|
-
*/
|
|
1675
804
|
class GLTFTextureAVIFExtension {
|
|
1676
|
-
|
|
1677
805
|
constructor( parser ) {
|
|
1678
|
-
|
|
1679
806
|
this.parser = parser;
|
|
1680
807
|
this.name = EXTENSIONS.EXT_TEXTURE_AVIF;
|
|
1681
|
-
|
|
1682
808
|
}
|
|
1683
|
-
|
|
1684
809
|
loadTexture( textureIndex ) {
|
|
1685
|
-
|
|
1686
810
|
const name = this.name;
|
|
1687
811
|
const parser = this.parser;
|
|
1688
812
|
const json = parser.json;
|
|
1689
|
-
|
|
1690
813
|
const textureDef = json.textures[ textureIndex ];
|
|
1691
|
-
|
|
1692
814
|
if ( ! textureDef.extensions || ! textureDef.extensions[ name ] ) {
|
|
1693
|
-
|
|
1694
815
|
return null;
|
|
1695
|
-
|
|
1696
816
|
}
|
|
1697
|
-
|
|
1698
817
|
const extension = textureDef.extensions[ name ];
|
|
1699
818
|
const source = json.images[ extension.source ];
|
|
1700
|
-
|
|
1701
819
|
let loader = parser.textureLoader;
|
|
1702
820
|
if ( source.uri ) {
|
|
1703
|
-
|
|
1704
821
|
const handler = parser.options.manager.getHandler( source.uri );
|
|
1705
822
|
if ( handler !== null ) loader = handler;
|
|
1706
|
-
|
|
1707
823
|
}
|
|
1708
|
-
|
|
1709
824
|
return parser.loadTextureImage( textureIndex, extension.source, loader );
|
|
1710
|
-
|
|
1711
825
|
}
|
|
1712
|
-
|
|
1713
826
|
}
|
|
1714
|
-
|
|
1715
|
-
/**
|
|
1716
|
-
* meshopt BufferView Compression Extension
|
|
1717
|
-
*
|
|
1718
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_meshopt_compression
|
|
1719
|
-
*
|
|
1720
|
-
* @private
|
|
1721
|
-
*/
|
|
1722
827
|
class GLTFMeshoptCompression {
|
|
1723
|
-
|
|
1724
828
|
constructor( parser ) {
|
|
1725
|
-
|
|
1726
829
|
this.name = EXTENSIONS.EXT_MESHOPT_COMPRESSION;
|
|
1727
830
|
this.parser = parser;
|
|
1728
|
-
|
|
1729
831
|
}
|
|
1730
|
-
|
|
1731
832
|
loadBufferView( index ) {
|
|
1732
|
-
|
|
1733
833
|
const json = this.parser.json;
|
|
1734
834
|
const bufferView = json.bufferViews[ index ];
|
|
1735
|
-
|
|
1736
835
|
if ( bufferView.extensions && bufferView.extensions[ this.name ] ) {
|
|
1737
|
-
|
|
1738
836
|
const extensionDef = bufferView.extensions[ this.name ];
|
|
1739
|
-
|
|
1740
837
|
const buffer = this.parser.getDependency( 'buffer', extensionDef.buffer );
|
|
1741
838
|
const decoder = this.parser.options.meshoptDecoder;
|
|
1742
|
-
|
|
1743
839
|
if ( ! decoder || ! decoder.supported ) {
|
|
1744
|
-
|
|
1745
840
|
if ( json.extensionsRequired && json.extensionsRequired.indexOf( this.name ) >= 0 ) {
|
|
1746
|
-
|
|
1747
841
|
throw new Error( 'THREE.GLTFLoader: setMeshoptDecoder must be called before loading compressed files' );
|
|
1748
|
-
|
|
1749
842
|
} else {
|
|
1750
|
-
|
|
1751
|
-
// Assumes that the extension is optional and that fallback buffer data is present
|
|
1752
843
|
return null;
|
|
1753
|
-
|
|
1754
844
|
}
|
|
1755
|
-
|
|
1756
845
|
}
|
|
1757
|
-
|
|
1758
846
|
return buffer.then( function ( res ) {
|
|
1759
|
-
|
|
1760
847
|
const byteOffset = extensionDef.byteOffset || 0;
|
|
1761
848
|
const byteLength = extensionDef.byteLength || 0;
|
|
1762
|
-
|
|
1763
849
|
const count = extensionDef.count;
|
|
1764
850
|
const stride = extensionDef.byteStride;
|
|
1765
|
-
|
|
1766
851
|
const source = new Uint8Array( res, byteOffset, byteLength );
|
|
1767
|
-
|
|
1768
852
|
if ( decoder.decodeGltfBufferAsync ) {
|
|
1769
|
-
|
|
1770
853
|
return decoder.decodeGltfBufferAsync( count, stride, source, extensionDef.mode, extensionDef.filter ).then( function ( res ) {
|
|
1771
|
-
|
|
1772
854
|
return res.buffer;
|
|
1773
|
-
|
|
1774
855
|
} );
|
|
1775
|
-
|
|
1776
856
|
} else {
|
|
1777
|
-
|
|
1778
|
-
// Support for MeshoptDecoder 0.18 or earlier, without decodeGltfBufferAsync
|
|
1779
857
|
return decoder.ready.then( function () {
|
|
1780
|
-
|
|
1781
858
|
const result = new ArrayBuffer( count * stride );
|
|
1782
859
|
decoder.decodeGltfBuffer( new Uint8Array( result ), count, stride, source, extensionDef.mode, extensionDef.filter );
|
|
1783
860
|
return result;
|
|
1784
|
-
|
|
1785
861
|
} );
|
|
1786
|
-
|
|
1787
862
|
}
|
|
1788
|
-
|
|
1789
863
|
} );
|
|
1790
|
-
|
|
1791
864
|
} else {
|
|
1792
|
-
|
|
1793
865
|
return null;
|
|
1794
|
-
|
|
1795
866
|
}
|
|
1796
|
-
|
|
1797
867
|
}
|
|
1798
|
-
|
|
1799
868
|
}
|
|
1800
|
-
|
|
1801
|
-
/**
|
|
1802
|
-
* GPU Instancing Extension
|
|
1803
|
-
*
|
|
1804
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_mesh_gpu_instancing
|
|
1805
|
-
*
|
|
1806
|
-
* @private
|
|
1807
|
-
*/
|
|
1808
869
|
class GLTFMeshGpuInstancing {
|
|
1809
|
-
|
|
1810
870
|
constructor( parser ) {
|
|
1811
|
-
|
|
1812
871
|
this.name = EXTENSIONS.EXT_MESH_GPU_INSTANCING;
|
|
1813
872
|
this.parser = parser;
|
|
1814
|
-
|
|
1815
873
|
}
|
|
1816
|
-
|
|
1817
874
|
createNodeMesh( nodeIndex ) {
|
|
1818
|
-
|
|
1819
875
|
const json = this.parser.json;
|
|
1820
876
|
const nodeDef = json.nodes[ nodeIndex ];
|
|
1821
|
-
|
|
1822
877
|
if ( ! nodeDef.extensions || ! nodeDef.extensions[ this.name ] ||
|
|
1823
878
|
nodeDef.mesh === undefined ) {
|
|
1824
|
-
|
|
1825
879
|
return null;
|
|
1826
|
-
|
|
1827
880
|
}
|
|
1828
|
-
|
|
1829
881
|
const meshDef = json.meshes[ nodeDef.mesh ];
|
|
1830
|
-
|
|
1831
|
-
// No Points or Lines + Instancing support yet
|
|
1832
|
-
|
|
1833
882
|
for ( const primitive of meshDef.primitives ) {
|
|
1834
|
-
|
|
1835
883
|
if ( primitive.mode !== WEBGL_CONSTANTS.TRIANGLES &&
|
|
1836
884
|
primitive.mode !== WEBGL_CONSTANTS.TRIANGLE_STRIP &&
|
|
1837
885
|
primitive.mode !== WEBGL_CONSTANTS.TRIANGLE_FAN &&
|
|
1838
886
|
primitive.mode !== undefined ) {
|
|
1839
|
-
|
|
1840
887
|
return null;
|
|
1841
|
-
|
|
1842
888
|
}
|
|
1843
|
-
|
|
1844
889
|
}
|
|
1845
|
-
|
|
1846
890
|
const extensionDef = nodeDef.extensions[ this.name ];
|
|
1847
891
|
const attributesDef = extensionDef.attributes;
|
|
1848
|
-
|
|
1849
|
-
// @TODO: Can we support InstancedMesh + SkinnedMesh?
|
|
1850
|
-
|
|
1851
892
|
const pending = [];
|
|
1852
893
|
const attributes = {};
|
|
1853
|
-
|
|
1854
894
|
for ( const key in attributesDef ) {
|
|
1855
|
-
|
|
1856
895
|
pending.push( this.parser.getDependency( 'accessor', attributesDef[ key ] ).then( accessor => {
|
|
1857
|
-
|
|
1858
896
|
attributes[ key ] = accessor;
|
|
1859
897
|
return attributes[ key ];
|
|
1860
|
-
|
|
1861
898
|
} ) );
|
|
1862
|
-
|
|
1863
899
|
}
|
|
1864
|
-
|
|
1865
900
|
if ( pending.length < 1 ) {
|
|
1866
|
-
|
|
1867
901
|
return null;
|
|
1868
|
-
|
|
1869
902
|
}
|
|
1870
|
-
|
|
1871
903
|
pending.push( this.parser.createNodeMesh( nodeIndex ) );
|
|
1872
|
-
|
|
1873
904
|
return Promise.all( pending ).then( results => {
|
|
1874
|
-
|
|
1875
905
|
const nodeObject = results.pop();
|
|
1876
906
|
const meshes = nodeObject.isGroup ? nodeObject.children : [ nodeObject ];
|
|
1877
|
-
const count = results[ 0 ].count;
|
|
907
|
+
const count = results[ 0 ].count;
|
|
1878
908
|
const instancedMeshes = [];
|
|
1879
|
-
|
|
1880
909
|
for ( const mesh of meshes ) {
|
|
1881
|
-
|
|
1882
|
-
// Temporal variables
|
|
1883
910
|
const m = new three.Matrix4();
|
|
1884
911
|
const p = new three.Vector3();
|
|
1885
912
|
const q = new three.Quaternion();
|
|
1886
913
|
const s = new three.Vector3( 1, 1, 1 );
|
|
1887
|
-
|
|
1888
914
|
const instancedMesh = new three.InstancedMesh( mesh.geometry, mesh.material, count );
|
|
1889
|
-
|
|
1890
915
|
for ( let i = 0; i < count; i ++ ) {
|
|
1891
|
-
|
|
1892
916
|
if ( attributes.TRANSLATION ) {
|
|
1893
|
-
|
|
1894
917
|
p.fromBufferAttribute( attributes.TRANSLATION, i );
|
|
1895
|
-
|
|
1896
918
|
}
|
|
1897
|
-
|
|
1898
919
|
if ( attributes.ROTATION ) {
|
|
1899
|
-
|
|
1900
920
|
q.fromBufferAttribute( attributes.ROTATION, i );
|
|
1901
|
-
|
|
1902
921
|
}
|
|
1903
|
-
|
|
1904
922
|
if ( attributes.SCALE ) {
|
|
1905
|
-
|
|
1906
923
|
s.fromBufferAttribute( attributes.SCALE, i );
|
|
1907
|
-
|
|
1908
924
|
}
|
|
1909
|
-
|
|
1910
925
|
instancedMesh.setMatrixAt( i, m.compose( p, q, s ) );
|
|
1911
|
-
|
|
1912
926
|
}
|
|
1913
|
-
|
|
1914
|
-
// Add instance attributes to the geometry, excluding TRS.
|
|
1915
927
|
for ( const attributeName in attributes ) {
|
|
1916
|
-
|
|
1917
928
|
if ( attributeName === '_COLOR_0' ) {
|
|
1918
|
-
|
|
1919
929
|
const attr = attributes[ attributeName ];
|
|
1920
930
|
instancedMesh.instanceColor = new three.InstancedBufferAttribute( attr.array, attr.itemSize, attr.normalized );
|
|
1921
|
-
|
|
1922
931
|
} else if ( attributeName !== 'TRANSLATION' &&
|
|
1923
932
|
attributeName !== 'ROTATION' &&
|
|
1924
933
|
attributeName !== 'SCALE' ) {
|
|
1925
|
-
|
|
1926
934
|
mesh.geometry.setAttribute( attributeName, attributes[ attributeName ] );
|
|
1927
|
-
|
|
1928
935
|
}
|
|
1929
|
-
|
|
1930
936
|
}
|
|
1931
|
-
|
|
1932
|
-
// Just in case
|
|
1933
937
|
three.Object3D.prototype.copy.call( instancedMesh, mesh );
|
|
1934
|
-
|
|
1935
938
|
this.parser.assignFinalMaterial( instancedMesh );
|
|
1936
|
-
|
|
1937
939
|
instancedMeshes.push( instancedMesh );
|
|
1938
|
-
|
|
1939
940
|
}
|
|
1940
|
-
|
|
1941
941
|
if ( nodeObject.isGroup ) {
|
|
1942
|
-
|
|
1943
942
|
nodeObject.clear();
|
|
1944
|
-
|
|
1945
943
|
nodeObject.add( ... instancedMeshes );
|
|
1946
|
-
|
|
1947
944
|
return nodeObject;
|
|
1948
|
-
|
|
1949
945
|
}
|
|
1950
|
-
|
|
1951
946
|
return instancedMeshes[ 0 ];
|
|
1952
|
-
|
|
1953
947
|
} );
|
|
1954
|
-
|
|
1955
948
|
}
|
|
1956
|
-
|
|
1957
949
|
}
|
|
1958
|
-
|
|
1959
|
-
/* BINARY EXTENSION */
|
|
1960
950
|
const BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
|
|
1961
951
|
const BINARY_EXTENSION_HEADER_LENGTH = 12;
|
|
1962
952
|
const BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
|
|
1963
|
-
|
|
1964
953
|
class GLTFBinaryExtension {
|
|
1965
|
-
|
|
1966
954
|
constructor( data ) {
|
|
1967
|
-
|
|
1968
955
|
this.name = EXTENSIONS.KHR_BINARY_GLTF;
|
|
1969
956
|
this.content = null;
|
|
1970
957
|
this.body = null;
|
|
1971
|
-
|
|
1972
958
|
const headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH );
|
|
1973
959
|
const textDecoder = new TextDecoder();
|
|
1974
|
-
|
|
1975
960
|
this.header = {
|
|
1976
961
|
magic: textDecoder.decode( new Uint8Array( data.slice( 0, 4 ) ) ),
|
|
1977
962
|
version: headerView.getUint32( 4, true ),
|
|
1978
963
|
length: headerView.getUint32( 8, true )
|
|
1979
964
|
};
|
|
1980
|
-
|
|
1981
965
|
if ( this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC ) {
|
|
1982
|
-
|
|
1983
966
|
throw new Error( 'THREE.GLTFLoader: Unsupported glTF-Binary header.' );
|
|
1984
|
-
|
|
1985
967
|
} else if ( this.header.version < 2.0 ) {
|
|
1986
|
-
|
|
1987
968
|
throw new Error( 'THREE.GLTFLoader: Legacy binary file detected.' );
|
|
1988
|
-
|
|
1989
969
|
}
|
|
1990
|
-
|
|
1991
970
|
const chunkContentsLength = this.header.length - BINARY_EXTENSION_HEADER_LENGTH;
|
|
1992
971
|
const chunkView = new DataView( data, BINARY_EXTENSION_HEADER_LENGTH );
|
|
1993
972
|
let chunkIndex = 0;
|
|
1994
|
-
|
|
1995
973
|
while ( chunkIndex < chunkContentsLength ) {
|
|
1996
|
-
|
|
1997
974
|
const chunkLength = chunkView.getUint32( chunkIndex, true );
|
|
1998
975
|
chunkIndex += 4;
|
|
1999
|
-
|
|
2000
976
|
const chunkType = chunkView.getUint32( chunkIndex, true );
|
|
2001
977
|
chunkIndex += 4;
|
|
2002
|
-
|
|
2003
978
|
if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON ) {
|
|
2004
|
-
|
|
2005
979
|
const contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength );
|
|
2006
980
|
this.content = textDecoder.decode( contentArray );
|
|
2007
|
-
|
|
2008
981
|
} else if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN ) {
|
|
2009
|
-
|
|
2010
982
|
const byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
|
|
2011
983
|
this.body = data.slice( byteOffset, byteOffset + chunkLength );
|
|
2012
|
-
|
|
2013
984
|
}
|
|
2014
|
-
|
|
2015
|
-
// Clients must ignore chunks with unknown types.
|
|
2016
|
-
|
|
2017
985
|
chunkIndex += chunkLength;
|
|
2018
|
-
|
|
2019
986
|
}
|
|
2020
|
-
|
|
2021
987
|
if ( this.content === null ) {
|
|
2022
|
-
|
|
2023
988
|
throw new Error( 'THREE.GLTFLoader: JSON content not found.' );
|
|
2024
|
-
|
|
2025
989
|
}
|
|
2026
|
-
|
|
2027
990
|
}
|
|
2028
|
-
|
|
2029
991
|
}
|
|
2030
|
-
|
|
2031
|
-
/**
|
|
2032
|
-
* DRACO Mesh Compression Extension
|
|
2033
|
-
*
|
|
2034
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression
|
|
2035
|
-
*
|
|
2036
|
-
* @private
|
|
2037
|
-
*/
|
|
2038
992
|
class GLTFDracoMeshCompressionExtension {
|
|
2039
|
-
|
|
2040
993
|
constructor( json, dracoLoader ) {
|
|
2041
|
-
|
|
2042
994
|
if ( ! dracoLoader ) {
|
|
2043
|
-
|
|
2044
995
|
throw new Error( 'THREE.GLTFLoader: No DRACOLoader instance provided.' );
|
|
2045
|
-
|
|
2046
996
|
}
|
|
2047
|
-
|
|
2048
997
|
this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION;
|
|
2049
998
|
this.json = json;
|
|
2050
999
|
this.dracoLoader = dracoLoader;
|
|
2051
1000
|
this.dracoLoader.preload();
|
|
2052
|
-
|
|
2053
1001
|
}
|
|
2054
|
-
|
|
2055
1002
|
decodePrimitive( primitive, parser ) {
|
|
2056
|
-
|
|
2057
1003
|
const json = this.json;
|
|
2058
1004
|
const dracoLoader = this.dracoLoader;
|
|
2059
1005
|
const bufferViewIndex = primitive.extensions[ this.name ].bufferView;
|
|
@@ -2061,235 +1007,114 @@
|
|
|
2061
1007
|
const threeAttributeMap = {};
|
|
2062
1008
|
const attributeNormalizedMap = {};
|
|
2063
1009
|
const attributeTypeMap = {};
|
|
2064
|
-
|
|
2065
1010
|
for ( const attributeName in gltfAttributeMap ) {
|
|
2066
|
-
|
|
2067
1011
|
const threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase();
|
|
2068
|
-
|
|
2069
1012
|
threeAttributeMap[ threeAttributeName ] = gltfAttributeMap[ attributeName ];
|
|
2070
|
-
|
|
2071
1013
|
}
|
|
2072
|
-
|
|
2073
1014
|
for ( const attributeName in primitive.attributes ) {
|
|
2074
|
-
|
|
2075
1015
|
const threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase();
|
|
2076
|
-
|
|
2077
1016
|
if ( gltfAttributeMap[ attributeName ] !== undefined ) {
|
|
2078
|
-
|
|
2079
1017
|
const accessorDef = json.accessors[ primitive.attributes[ attributeName ] ];
|
|
2080
1018
|
const componentType = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
|
|
2081
|
-
|
|
2082
1019
|
attributeTypeMap[ threeAttributeName ] = componentType.name;
|
|
2083
1020
|
attributeNormalizedMap[ threeAttributeName ] = accessorDef.normalized === true;
|
|
2084
|
-
|
|
2085
1021
|
}
|
|
2086
|
-
|
|
2087
1022
|
}
|
|
2088
|
-
|
|
2089
1023
|
return parser.getDependency( 'bufferView', bufferViewIndex ).then( function ( bufferView ) {
|
|
2090
|
-
|
|
2091
1024
|
return new Promise( function ( resolve, reject ) {
|
|
2092
|
-
|
|
2093
1025
|
dracoLoader.decodeDracoFile( bufferView, function ( geometry ) {
|
|
2094
|
-
|
|
2095
1026
|
for ( const attributeName in geometry.attributes ) {
|
|
2096
|
-
|
|
2097
1027
|
const attribute = geometry.attributes[ attributeName ];
|
|
2098
1028
|
const normalized = attributeNormalizedMap[ attributeName ];
|
|
2099
|
-
|
|
2100
1029
|
if ( normalized !== undefined ) attribute.normalized = normalized;
|
|
2101
|
-
|
|
2102
1030
|
}
|
|
2103
|
-
|
|
2104
1031
|
resolve( geometry );
|
|
2105
|
-
|
|
2106
1032
|
}, threeAttributeMap, attributeTypeMap, three.LinearSRGBColorSpace, reject );
|
|
2107
|
-
|
|
2108
1033
|
} );
|
|
2109
|
-
|
|
2110
1034
|
} );
|
|
2111
|
-
|
|
2112
1035
|
}
|
|
2113
|
-
|
|
2114
1036
|
}
|
|
2115
|
-
|
|
2116
|
-
/**
|
|
2117
|
-
* Texture Transform Extension
|
|
2118
|
-
*
|
|
2119
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_transform
|
|
2120
|
-
*
|
|
2121
|
-
* @private
|
|
2122
|
-
*/
|
|
2123
1037
|
class GLTFTextureTransformExtension {
|
|
2124
|
-
|
|
2125
1038
|
constructor() {
|
|
2126
|
-
|
|
2127
1039
|
this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM;
|
|
2128
|
-
|
|
2129
1040
|
}
|
|
2130
|
-
|
|
2131
1041
|
extendTexture( texture, transform ) {
|
|
2132
|
-
|
|
2133
1042
|
if ( ( transform.texCoord === undefined || transform.texCoord === texture.channel )
|
|
2134
1043
|
&& transform.offset === undefined
|
|
2135
1044
|
&& transform.rotation === undefined
|
|
2136
1045
|
&& transform.scale === undefined ) {
|
|
2137
|
-
|
|
2138
|
-
// See https://github.com/mrdoob/three.js/issues/21819.
|
|
2139
1046
|
return texture;
|
|
2140
|
-
|
|
2141
1047
|
}
|
|
2142
|
-
|
|
2143
1048
|
texture = texture.clone();
|
|
2144
|
-
|
|
2145
1049
|
if ( transform.texCoord !== undefined ) {
|
|
2146
|
-
|
|
2147
1050
|
texture.channel = transform.texCoord;
|
|
2148
|
-
|
|
2149
1051
|
}
|
|
2150
|
-
|
|
2151
1052
|
if ( transform.offset !== undefined ) {
|
|
2152
|
-
|
|
2153
1053
|
texture.offset.fromArray( transform.offset );
|
|
2154
|
-
|
|
2155
1054
|
}
|
|
2156
|
-
|
|
2157
1055
|
if ( transform.rotation !== undefined ) {
|
|
2158
|
-
|
|
2159
1056
|
texture.rotation = transform.rotation;
|
|
2160
|
-
|
|
2161
1057
|
}
|
|
2162
|
-
|
|
2163
1058
|
if ( transform.scale !== undefined ) {
|
|
2164
|
-
|
|
2165
1059
|
texture.repeat.fromArray( transform.scale );
|
|
2166
|
-
|
|
2167
1060
|
}
|
|
2168
|
-
|
|
2169
1061
|
texture.needsUpdate = true;
|
|
2170
|
-
|
|
2171
1062
|
return texture;
|
|
2172
|
-
|
|
2173
1063
|
}
|
|
2174
|
-
|
|
2175
1064
|
}
|
|
2176
|
-
|
|
2177
|
-
/**
|
|
2178
|
-
* Mesh Quantization Extension
|
|
2179
|
-
*
|
|
2180
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization
|
|
2181
|
-
*
|
|
2182
|
-
* @private
|
|
2183
|
-
*/
|
|
2184
1065
|
class GLTFMeshQuantizationExtension {
|
|
2185
|
-
|
|
2186
1066
|
constructor() {
|
|
2187
|
-
|
|
2188
1067
|
this.name = EXTENSIONS.KHR_MESH_QUANTIZATION;
|
|
2189
|
-
|
|
2190
1068
|
}
|
|
2191
|
-
|
|
2192
1069
|
}
|
|
2193
|
-
|
|
2194
|
-
/*********************************/
|
|
2195
|
-
/********** INTERPOLATION ********/
|
|
2196
|
-
/*********************************/
|
|
2197
|
-
|
|
2198
|
-
// Spline Interpolation
|
|
2199
|
-
// Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation
|
|
2200
1070
|
class GLTFCubicSplineInterpolant extends three.Interpolant {
|
|
2201
|
-
|
|
2202
1071
|
constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
|
|
2203
|
-
|
|
2204
1072
|
super( parameterPositions, sampleValues, sampleSize, resultBuffer );
|
|
2205
|
-
|
|
2206
1073
|
}
|
|
2207
|
-
|
|
2208
1074
|
copySampleValue_( index ) {
|
|
2209
|
-
|
|
2210
|
-
// Copies a sample value to the result buffer. See description of glTF
|
|
2211
|
-
// CUBICSPLINE values layout in interpolate_() function below.
|
|
2212
|
-
|
|
2213
1075
|
const result = this.resultBuffer,
|
|
2214
1076
|
values = this.sampleValues,
|
|
2215
1077
|
valueSize = this.valueSize,
|
|
2216
1078
|
offset = index * valueSize * 3 + valueSize;
|
|
2217
|
-
|
|
2218
1079
|
for ( let i = 0; i !== valueSize; i ++ ) {
|
|
2219
|
-
|
|
2220
1080
|
result[ i ] = values[ offset + i ];
|
|
2221
|
-
|
|
2222
1081
|
}
|
|
2223
|
-
|
|
2224
1082
|
return result;
|
|
2225
|
-
|
|
2226
1083
|
}
|
|
2227
|
-
|
|
2228
1084
|
interpolate_( i1, t0, t, t1 ) {
|
|
2229
|
-
|
|
2230
1085
|
const result = this.resultBuffer;
|
|
2231
1086
|
const values = this.sampleValues;
|
|
2232
1087
|
const stride = this.valueSize;
|
|
2233
|
-
|
|
2234
1088
|
const stride2 = stride * 2;
|
|
2235
1089
|
const stride3 = stride * 3;
|
|
2236
|
-
|
|
2237
1090
|
const td = t1 - t0;
|
|
2238
|
-
|
|
2239
1091
|
const p = ( t - t0 ) / td;
|
|
2240
1092
|
const pp = p * p;
|
|
2241
1093
|
const ppp = pp * p;
|
|
2242
|
-
|
|
2243
1094
|
const offset1 = i1 * stride3;
|
|
2244
1095
|
const offset0 = offset1 - stride3;
|
|
2245
|
-
|
|
2246
1096
|
const s2 = -2 * ppp + 3 * pp;
|
|
2247
1097
|
const s3 = ppp - pp;
|
|
2248
1098
|
const s0 = 1 - s2;
|
|
2249
1099
|
const s1 = s3 - pp + p;
|
|
2250
|
-
|
|
2251
|
-
// Layout of keyframe output values for CUBICSPLINE animations:
|
|
2252
|
-
// [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ]
|
|
2253
1100
|
for ( let i = 0; i !== stride; i ++ ) {
|
|
2254
|
-
|
|
2255
|
-
const
|
|
2256
|
-
const
|
|
2257
|
-
const
|
|
2258
|
-
const m1 = values[ offset1 + i ] * td; // inTangent_k+1 * (t_k+1 - t_k)
|
|
2259
|
-
|
|
1101
|
+
const p0 = values[ offset0 + i + stride ];
|
|
1102
|
+
const m0 = values[ offset0 + i + stride2 ] * td;
|
|
1103
|
+
const p1 = values[ offset1 + i + stride ];
|
|
1104
|
+
const m1 = values[ offset1 + i ] * td;
|
|
2260
1105
|
result[ i ] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1;
|
|
2261
|
-
|
|
2262
1106
|
}
|
|
2263
|
-
|
|
2264
1107
|
return result;
|
|
2265
|
-
|
|
2266
1108
|
}
|
|
2267
|
-
|
|
2268
1109
|
}
|
|
2269
|
-
|
|
2270
1110
|
const _quaternion = new three.Quaternion();
|
|
2271
|
-
|
|
2272
1111
|
class GLTFCubicSplineQuaternionInterpolant extends GLTFCubicSplineInterpolant {
|
|
2273
|
-
|
|
2274
1112
|
interpolate_( i1, t0, t, t1 ) {
|
|
2275
|
-
|
|
2276
1113
|
const result = super.interpolate_( i1, t0, t, t1 );
|
|
2277
|
-
|
|
2278
1114
|
_quaternion.fromArray( result ).normalize().toArray( result );
|
|
2279
|
-
|
|
2280
1115
|
return result;
|
|
2281
|
-
|
|
2282
1116
|
}
|
|
2283
|
-
|
|
2284
1117
|
}
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
/*********************************/
|
|
2288
|
-
/********** INTERNALS ************/
|
|
2289
|
-
/*********************************/
|
|
2290
|
-
|
|
2291
|
-
/* CONSTANTS */
|
|
2292
|
-
|
|
2293
1118
|
const WEBGL_CONSTANTS = {
|
|
2294
1119
|
POINTS: 0,
|
|
2295
1120
|
LINES: 1,
|
|
@@ -2298,7 +1123,6 @@
|
|
|
2298
1123
|
TRIANGLES: 4,
|
|
2299
1124
|
TRIANGLE_STRIP: 5,
|
|
2300
1125
|
TRIANGLE_FAN: 6};
|
|
2301
|
-
|
|
2302
1126
|
const WEBGL_COMPONENT_TYPES = {
|
|
2303
1127
|
5120: Int8Array,
|
|
2304
1128
|
5121: Uint8Array,
|
|
@@ -2307,7 +1131,6 @@
|
|
|
2307
1131
|
5125: Uint32Array,
|
|
2308
1132
|
5126: Float32Array
|
|
2309
1133
|
};
|
|
2310
|
-
|
|
2311
1134
|
const WEBGL_FILTERS = {
|
|
2312
1135
|
9728: three.NearestFilter,
|
|
2313
1136
|
9729: three.LinearFilter,
|
|
@@ -2316,13 +1139,11 @@
|
|
|
2316
1139
|
9986: three.NearestMipmapLinearFilter,
|
|
2317
1140
|
9987: three.LinearMipmapLinearFilter
|
|
2318
1141
|
};
|
|
2319
|
-
|
|
2320
1142
|
const WEBGL_WRAPPINGS = {
|
|
2321
1143
|
33071: three.ClampToEdgeWrapping,
|
|
2322
1144
|
33648: three.MirroredRepeatWrapping,
|
|
2323
1145
|
10497: three.RepeatWrapping
|
|
2324
1146
|
};
|
|
2325
|
-
|
|
2326
1147
|
const WEBGL_TYPE_SIZES = {
|
|
2327
1148
|
'SCALAR': 1,
|
|
2328
1149
|
'VEC2': 2,
|
|
@@ -2332,7 +1153,6 @@
|
|
|
2332
1153
|
'MAT3': 9,
|
|
2333
1154
|
'MAT4': 16
|
|
2334
1155
|
};
|
|
2335
|
-
|
|
2336
1156
|
const ATTRIBUTES = {
|
|
2337
1157
|
POSITION: 'position',
|
|
2338
1158
|
NORMAL: 'normal',
|
|
@@ -2345,38 +1165,24 @@
|
|
|
2345
1165
|
WEIGHTS_0: 'skinWeight',
|
|
2346
1166
|
JOINTS_0: 'skinIndex',
|
|
2347
1167
|
};
|
|
2348
|
-
|
|
2349
1168
|
const PATH_PROPERTIES = {
|
|
2350
1169
|
scale: 'scale',
|
|
2351
1170
|
translation: 'position',
|
|
2352
1171
|
rotation: 'quaternion',
|
|
2353
1172
|
weights: 'morphTargetInfluences'
|
|
2354
1173
|
};
|
|
2355
|
-
|
|
2356
1174
|
const INTERPOLATION = {
|
|
2357
|
-
CUBICSPLINE: undefined,
|
|
2358
|
-
// keyframe track will be initialized with a default interpolation type, then modified.
|
|
1175
|
+
CUBICSPLINE: undefined,
|
|
2359
1176
|
LINEAR: three.InterpolateLinear,
|
|
2360
1177
|
STEP: three.InterpolateDiscrete
|
|
2361
1178
|
};
|
|
2362
|
-
|
|
2363
1179
|
const ALPHA_MODES = {
|
|
2364
1180
|
OPAQUE: 'OPAQUE',
|
|
2365
1181
|
MASK: 'MASK',
|
|
2366
1182
|
BLEND: 'BLEND'
|
|
2367
1183
|
};
|
|
2368
|
-
|
|
2369
|
-
/**
|
|
2370
|
-
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material
|
|
2371
|
-
*
|
|
2372
|
-
* @private
|
|
2373
|
-
* @param {Object<string, Material>} cache
|
|
2374
|
-
* @return {Material}
|
|
2375
|
-
*/
|
|
2376
1184
|
function createDefaultMaterial( cache ) {
|
|
2377
|
-
|
|
2378
1185
|
if ( cache[ 'DefaultMaterial' ] === undefined ) {
|
|
2379
|
-
|
|
2380
1186
|
cache[ 'DefaultMaterial' ] = new three.MeshStandardMaterial( {
|
|
2381
1187
|
color: 0xFFFFFF,
|
|
2382
1188
|
emissive: 0x000000,
|
|
@@ -2386,399 +1192,207 @@
|
|
|
2386
1192
|
depthTest: true,
|
|
2387
1193
|
side: three.FrontSide
|
|
2388
1194
|
} );
|
|
2389
|
-
|
|
2390
1195
|
}
|
|
2391
|
-
|
|
2392
1196
|
return cache[ 'DefaultMaterial' ];
|
|
2393
|
-
|
|
2394
1197
|
}
|
|
2395
|
-
|
|
2396
1198
|
function addUnknownExtensionsToUserData( knownExtensions, object, objectDef ) {
|
|
2397
|
-
|
|
2398
|
-
// Add unknown glTF extensions to an object's userData.
|
|
2399
|
-
|
|
2400
1199
|
for ( const name in objectDef.extensions ) {
|
|
2401
|
-
|
|
2402
1200
|
if ( knownExtensions[ name ] === undefined ) {
|
|
2403
|
-
|
|
2404
1201
|
object.userData.gltfExtensions = object.userData.gltfExtensions || {};
|
|
2405
1202
|
object.userData.gltfExtensions[ name ] = objectDef.extensions[ name ];
|
|
2406
|
-
|
|
2407
1203
|
}
|
|
2408
|
-
|
|
2409
1204
|
}
|
|
2410
|
-
|
|
2411
1205
|
}
|
|
2412
|
-
|
|
2413
|
-
/**
|
|
2414
|
-
*
|
|
2415
|
-
* @private
|
|
2416
|
-
* @param {Object3D|Material|BufferGeometry|Object} object
|
|
2417
|
-
* @param {GLTF.definition} gltfDef
|
|
2418
|
-
*/
|
|
2419
1206
|
function assignExtrasToUserData( object, gltfDef ) {
|
|
2420
|
-
|
|
2421
1207
|
if ( gltfDef.extras !== undefined ) {
|
|
2422
|
-
|
|
2423
1208
|
if ( typeof gltfDef.extras === 'object' ) {
|
|
2424
|
-
|
|
2425
1209
|
Object.assign( object.userData, gltfDef.extras );
|
|
2426
|
-
|
|
2427
1210
|
} else {
|
|
2428
|
-
|
|
2429
1211
|
console.warn( 'THREE.GLTFLoader: Ignoring primitive type .extras, ' + gltfDef.extras );
|
|
2430
|
-
|
|
2431
1212
|
}
|
|
2432
|
-
|
|
2433
1213
|
}
|
|
2434
|
-
|
|
2435
1214
|
}
|
|
2436
|
-
|
|
2437
|
-
/**
|
|
2438
|
-
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
|
|
2439
|
-
*
|
|
2440
|
-
* @private
|
|
2441
|
-
* @param {BufferGeometry} geometry
|
|
2442
|
-
* @param {Array<GLTF.Target>} targets
|
|
2443
|
-
* @param {GLTFParser} parser
|
|
2444
|
-
* @return {Promise<BufferGeometry>}
|
|
2445
|
-
*/
|
|
2446
1215
|
function addMorphTargets( geometry, targets, parser ) {
|
|
2447
|
-
|
|
2448
1216
|
let hasMorphPosition = false;
|
|
2449
1217
|
let hasMorphNormal = false;
|
|
2450
1218
|
let hasMorphColor = false;
|
|
2451
|
-
|
|
2452
1219
|
for ( let i = 0, il = targets.length; i < il; i ++ ) {
|
|
2453
|
-
|
|
2454
1220
|
const target = targets[ i ];
|
|
2455
|
-
|
|
2456
1221
|
if ( target.POSITION !== undefined ) hasMorphPosition = true;
|
|
2457
1222
|
if ( target.NORMAL !== undefined ) hasMorphNormal = true;
|
|
2458
1223
|
if ( target.COLOR_0 !== undefined ) hasMorphColor = true;
|
|
2459
|
-
|
|
2460
1224
|
if ( hasMorphPosition && hasMorphNormal && hasMorphColor ) break;
|
|
2461
|
-
|
|
2462
1225
|
}
|
|
2463
|
-
|
|
2464
1226
|
if ( ! hasMorphPosition && ! hasMorphNormal && ! hasMorphColor ) return Promise.resolve( geometry );
|
|
2465
|
-
|
|
2466
1227
|
const pendingPositionAccessors = [];
|
|
2467
1228
|
const pendingNormalAccessors = [];
|
|
2468
1229
|
const pendingColorAccessors = [];
|
|
2469
|
-
|
|
2470
1230
|
for ( let i = 0, il = targets.length; i < il; i ++ ) {
|
|
2471
|
-
|
|
2472
1231
|
const target = targets[ i ];
|
|
2473
|
-
|
|
2474
1232
|
if ( hasMorphPosition ) {
|
|
2475
|
-
|
|
2476
1233
|
const pendingAccessor = target.POSITION !== undefined
|
|
2477
1234
|
? parser.getDependency( 'accessor', target.POSITION )
|
|
2478
1235
|
: geometry.attributes.position;
|
|
2479
|
-
|
|
2480
1236
|
pendingPositionAccessors.push( pendingAccessor );
|
|
2481
|
-
|
|
2482
1237
|
}
|
|
2483
|
-
|
|
2484
1238
|
if ( hasMorphNormal ) {
|
|
2485
|
-
|
|
2486
1239
|
const pendingAccessor = target.NORMAL !== undefined
|
|
2487
1240
|
? parser.getDependency( 'accessor', target.NORMAL )
|
|
2488
1241
|
: geometry.attributes.normal;
|
|
2489
|
-
|
|
2490
1242
|
pendingNormalAccessors.push( pendingAccessor );
|
|
2491
|
-
|
|
2492
1243
|
}
|
|
2493
|
-
|
|
2494
1244
|
if ( hasMorphColor ) {
|
|
2495
|
-
|
|
2496
1245
|
const pendingAccessor = target.COLOR_0 !== undefined
|
|
2497
1246
|
? parser.getDependency( 'accessor', target.COLOR_0 )
|
|
2498
1247
|
: geometry.attributes.color;
|
|
2499
|
-
|
|
2500
1248
|
pendingColorAccessors.push( pendingAccessor );
|
|
2501
|
-
|
|
2502
1249
|
}
|
|
2503
|
-
|
|
2504
1250
|
}
|
|
2505
|
-
|
|
2506
1251
|
return Promise.all( [
|
|
2507
1252
|
Promise.all( pendingPositionAccessors ),
|
|
2508
1253
|
Promise.all( pendingNormalAccessors ),
|
|
2509
1254
|
Promise.all( pendingColorAccessors )
|
|
2510
1255
|
] ).then( function ( accessors ) {
|
|
2511
|
-
|
|
2512
1256
|
const morphPositions = accessors[ 0 ];
|
|
2513
1257
|
const morphNormals = accessors[ 1 ];
|
|
2514
1258
|
const morphColors = accessors[ 2 ];
|
|
2515
|
-
|
|
2516
1259
|
if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
|
|
2517
1260
|
if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
|
|
2518
1261
|
if ( hasMorphColor ) geometry.morphAttributes.color = morphColors;
|
|
2519
1262
|
geometry.morphTargetsRelative = true;
|
|
2520
|
-
|
|
2521
1263
|
return geometry;
|
|
2522
|
-
|
|
2523
1264
|
} );
|
|
2524
|
-
|
|
2525
1265
|
}
|
|
2526
|
-
|
|
2527
|
-
/**
|
|
2528
|
-
*
|
|
2529
|
-
* @private
|
|
2530
|
-
* @param {Mesh} mesh
|
|
2531
|
-
* @param {GLTF.Mesh} meshDef
|
|
2532
|
-
*/
|
|
2533
1266
|
function updateMorphTargets( mesh, meshDef ) {
|
|
2534
|
-
|
|
2535
1267
|
mesh.updateMorphTargets();
|
|
2536
|
-
|
|
2537
1268
|
if ( meshDef.weights !== undefined ) {
|
|
2538
|
-
|
|
2539
1269
|
for ( let i = 0, il = meshDef.weights.length; i < il; i ++ ) {
|
|
2540
|
-
|
|
2541
1270
|
mesh.morphTargetInfluences[ i ] = meshDef.weights[ i ];
|
|
2542
|
-
|
|
2543
1271
|
}
|
|
2544
|
-
|
|
2545
1272
|
}
|
|
2546
|
-
|
|
2547
|
-
// .extras has user-defined data, so check that .extras.targetNames is an array.
|
|
2548
1273
|
if ( meshDef.extras && Array.isArray( meshDef.extras.targetNames ) ) {
|
|
2549
|
-
|
|
2550
1274
|
const targetNames = meshDef.extras.targetNames;
|
|
2551
|
-
|
|
2552
1275
|
if ( mesh.morphTargetInfluences.length === targetNames.length ) {
|
|
2553
|
-
|
|
2554
1276
|
mesh.morphTargetDictionary = {};
|
|
2555
|
-
|
|
2556
1277
|
for ( let i = 0, il = targetNames.length; i < il; i ++ ) {
|
|
2557
|
-
|
|
2558
1278
|
mesh.morphTargetDictionary[ targetNames[ i ] ] = i;
|
|
2559
|
-
|
|
2560
1279
|
}
|
|
2561
|
-
|
|
2562
1280
|
} else {
|
|
2563
|
-
|
|
2564
1281
|
console.warn( 'THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.' );
|
|
2565
|
-
|
|
2566
1282
|
}
|
|
2567
|
-
|
|
2568
1283
|
}
|
|
2569
|
-
|
|
2570
1284
|
}
|
|
2571
|
-
|
|
2572
1285
|
function createPrimitiveKey( primitiveDef ) {
|
|
2573
|
-
|
|
2574
1286
|
let geometryKey;
|
|
2575
|
-
|
|
2576
1287
|
const dracoExtension = primitiveDef.extensions && primitiveDef.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ];
|
|
2577
|
-
|
|
2578
1288
|
if ( dracoExtension ) {
|
|
2579
|
-
|
|
2580
1289
|
geometryKey = 'draco:' + dracoExtension.bufferView
|
|
2581
1290
|
+ ':' + dracoExtension.indices
|
|
2582
1291
|
+ ':' + createAttributesKey( dracoExtension.attributes );
|
|
2583
|
-
|
|
2584
1292
|
} else {
|
|
2585
|
-
|
|
2586
1293
|
geometryKey = primitiveDef.indices + ':' + createAttributesKey( primitiveDef.attributes ) + ':' + primitiveDef.mode;
|
|
2587
|
-
|
|
2588
1294
|
}
|
|
2589
|
-
|
|
2590
1295
|
if ( primitiveDef.targets !== undefined ) {
|
|
2591
|
-
|
|
2592
1296
|
for ( let i = 0, il = primitiveDef.targets.length; i < il; i ++ ) {
|
|
2593
|
-
|
|
2594
1297
|
geometryKey += ':' + createAttributesKey( primitiveDef.targets[ i ] );
|
|
2595
|
-
|
|
2596
1298
|
}
|
|
2597
|
-
|
|
2598
1299
|
}
|
|
2599
|
-
|
|
2600
1300
|
return geometryKey;
|
|
2601
|
-
|
|
2602
1301
|
}
|
|
2603
|
-
|
|
2604
1302
|
function createAttributesKey( attributes ) {
|
|
2605
|
-
|
|
2606
1303
|
let attributesKey = '';
|
|
2607
|
-
|
|
2608
1304
|
const keys = Object.keys( attributes ).sort();
|
|
2609
|
-
|
|
2610
1305
|
for ( let i = 0, il = keys.length; i < il; i ++ ) {
|
|
2611
|
-
|
|
2612
1306
|
attributesKey += keys[ i ] + ':' + attributes[ keys[ i ] ] + ';';
|
|
2613
|
-
|
|
2614
1307
|
}
|
|
2615
|
-
|
|
2616
1308
|
return attributesKey;
|
|
2617
|
-
|
|
2618
1309
|
}
|
|
2619
|
-
|
|
2620
1310
|
function getNormalizedComponentScale( constructor ) {
|
|
2621
|
-
|
|
2622
|
-
// Reference:
|
|
2623
|
-
// https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization#encoding-quantized-data
|
|
2624
|
-
|
|
2625
1311
|
switch ( constructor ) {
|
|
2626
|
-
|
|
2627
1312
|
case Int8Array:
|
|
2628
1313
|
return 1 / 127;
|
|
2629
|
-
|
|
2630
1314
|
case Uint8Array:
|
|
2631
1315
|
return 1 / 255;
|
|
2632
|
-
|
|
2633
1316
|
case Int16Array:
|
|
2634
1317
|
return 1 / 32767;
|
|
2635
|
-
|
|
2636
1318
|
case Uint16Array:
|
|
2637
1319
|
return 1 / 65535;
|
|
2638
|
-
|
|
2639
1320
|
default:
|
|
2640
1321
|
throw new Error( 'THREE.GLTFLoader: Unsupported normalized accessor component type.' );
|
|
2641
|
-
|
|
2642
1322
|
}
|
|
2643
|
-
|
|
2644
1323
|
}
|
|
2645
|
-
|
|
2646
1324
|
function getImageURIMimeType( uri ) {
|
|
2647
|
-
|
|
2648
1325
|
if ( uri.search( /\.jpe?g($|\?)/i ) > 0 || uri.search( /^data\:image\/jpeg/ ) === 0 ) return 'image/jpeg';
|
|
2649
1326
|
if ( uri.search( /\.webp($|\?)/i ) > 0 || uri.search( /^data\:image\/webp/ ) === 0 ) return 'image/webp';
|
|
2650
1327
|
if ( uri.search( /\.ktx2($|\?)/i ) > 0 || uri.search( /^data\:image\/ktx2/ ) === 0 ) return 'image/ktx2';
|
|
2651
|
-
|
|
2652
1328
|
return 'image/png';
|
|
2653
|
-
|
|
2654
1329
|
}
|
|
2655
|
-
|
|
2656
1330
|
const _identityMatrix = new three.Matrix4();
|
|
2657
|
-
|
|
2658
|
-
/* GLTF PARSER */
|
|
2659
|
-
|
|
2660
1331
|
class GLTFParser {
|
|
2661
|
-
|
|
2662
1332
|
constructor( json = {}, options = {} ) {
|
|
2663
|
-
|
|
2664
1333
|
this.json = json;
|
|
2665
1334
|
this.extensions = {};
|
|
2666
1335
|
this.plugins = {};
|
|
2667
1336
|
this.options = options;
|
|
2668
|
-
|
|
2669
|
-
// loader object cache
|
|
2670
1337
|
this.cache = new GLTFRegistry();
|
|
2671
|
-
|
|
2672
|
-
// associations between Three.js objects and glTF elements
|
|
2673
1338
|
this.associations = new Map();
|
|
2674
|
-
|
|
2675
|
-
// BufferGeometry caching
|
|
2676
1339
|
this.primitiveCache = {};
|
|
2677
|
-
|
|
2678
|
-
// Node cache
|
|
2679
1340
|
this.nodeCache = {};
|
|
2680
|
-
|
|
2681
|
-
// Object3D instance caches
|
|
2682
1341
|
this.meshCache = { refs: {}, uses: {} };
|
|
2683
1342
|
this.cameraCache = { refs: {}, uses: {} };
|
|
2684
1343
|
this.lightCache = { refs: {}, uses: {} };
|
|
2685
|
-
|
|
2686
1344
|
this.sourceCache = {};
|
|
2687
1345
|
this.textureCache = {};
|
|
2688
|
-
|
|
2689
|
-
// Track node names, to ensure no duplicates
|
|
2690
1346
|
this.nodeNamesUsed = {};
|
|
2691
|
-
|
|
2692
|
-
// Use an ImageBitmapLoader if imageBitmaps are supported. Moves much of the
|
|
2693
|
-
// expensive work of uploading a texture to the GPU off the main thread.
|
|
2694
|
-
|
|
2695
1347
|
let isSafari = false;
|
|
2696
1348
|
let safariVersion = -1;
|
|
2697
1349
|
let isFirefox = false;
|
|
2698
1350
|
let firefoxVersion = -1;
|
|
2699
|
-
|
|
2700
1351
|
if ( typeof navigator !== 'undefined' ) {
|
|
2701
|
-
|
|
2702
1352
|
const userAgent = navigator.userAgent;
|
|
2703
|
-
|
|
2704
1353
|
isSafari = /^((?!chrome|android).)*safari/i.test( userAgent ) === true;
|
|
2705
1354
|
const safariMatch = userAgent.match( /Version\/(\d+)/ );
|
|
2706
1355
|
safariVersion = isSafari && safariMatch ? parseInt( safariMatch[ 1 ], 10 ) : -1;
|
|
2707
|
-
|
|
2708
1356
|
isFirefox = userAgent.indexOf( 'Firefox' ) > -1;
|
|
2709
1357
|
firefoxVersion = isFirefox ? userAgent.match( /Firefox\/([0-9]+)\./ )[ 1 ] : -1;
|
|
2710
|
-
|
|
2711
1358
|
}
|
|
2712
|
-
|
|
2713
1359
|
if ( typeof createImageBitmap === 'undefined' || ( isSafari && safariVersion < 17 ) || ( isFirefox && firefoxVersion < 98 ) ) {
|
|
2714
|
-
|
|
2715
1360
|
this.textureLoader = new three.TextureLoader( this.options.manager );
|
|
2716
|
-
|
|
2717
1361
|
} else {
|
|
2718
|
-
|
|
2719
1362
|
this.textureLoader = new three.ImageBitmapLoader( this.options.manager );
|
|
2720
|
-
|
|
2721
1363
|
}
|
|
2722
|
-
|
|
2723
1364
|
this.textureLoader.setCrossOrigin( this.options.crossOrigin );
|
|
2724
1365
|
this.textureLoader.setRequestHeader( this.options.requestHeader );
|
|
2725
|
-
|
|
2726
1366
|
this.fileLoader = new three.FileLoader( this.options.manager );
|
|
2727
1367
|
this.fileLoader.setResponseType( 'arraybuffer' );
|
|
2728
|
-
|
|
2729
1368
|
if ( this.options.crossOrigin === 'use-credentials' ) {
|
|
2730
|
-
|
|
2731
1369
|
this.fileLoader.setWithCredentials( true );
|
|
2732
|
-
|
|
2733
1370
|
}
|
|
2734
|
-
|
|
2735
1371
|
}
|
|
2736
|
-
|
|
2737
1372
|
setExtensions( extensions ) {
|
|
2738
|
-
|
|
2739
1373
|
this.extensions = extensions;
|
|
2740
|
-
|
|
2741
1374
|
}
|
|
2742
|
-
|
|
2743
1375
|
setPlugins( plugins ) {
|
|
2744
|
-
|
|
2745
1376
|
this.plugins = plugins;
|
|
2746
|
-
|
|
2747
1377
|
}
|
|
2748
|
-
|
|
2749
1378
|
parse( onLoad, onError ) {
|
|
2750
|
-
|
|
2751
1379
|
const parser = this;
|
|
2752
1380
|
const json = this.json;
|
|
2753
1381
|
const extensions = this.extensions;
|
|
2754
|
-
|
|
2755
|
-
// Clear the loader cache
|
|
2756
1382
|
this.cache.removeAll();
|
|
2757
1383
|
this.nodeCache = {};
|
|
2758
|
-
|
|
2759
|
-
// Mark the special nodes/meshes in json for efficient parse
|
|
2760
1384
|
this._invokeAll( function ( ext ) {
|
|
2761
|
-
|
|
2762
1385
|
return ext._markDefs && ext._markDefs();
|
|
2763
|
-
|
|
2764
1386
|
} );
|
|
2765
|
-
|
|
2766
1387
|
Promise.all( this._invokeAll( function ( ext ) {
|
|
2767
|
-
|
|
2768
1388
|
return ext.beforeRoot && ext.beforeRoot();
|
|
2769
|
-
|
|
2770
1389
|
} ) ).then( function () {
|
|
2771
|
-
|
|
2772
1390
|
return Promise.all( [
|
|
2773
|
-
|
|
2774
1391
|
parser.getDependencies( 'scene' ),
|
|
2775
1392
|
parser.getDependencies( 'animation' ),
|
|
2776
1393
|
parser.getDependencies( 'camera' ),
|
|
2777
|
-
|
|
2778
1394
|
] );
|
|
2779
|
-
|
|
2780
1395
|
} ).then( function ( dependencies ) {
|
|
2781
|
-
|
|
2782
1396
|
const result = {
|
|
2783
1397
|
scene: dependencies[ 0 ][ json.scene || 0 ],
|
|
2784
1398
|
scenes: dependencies[ 0 ],
|
|
@@ -2788,1852 +1402,914 @@
|
|
|
2788
1402
|
parser: parser,
|
|
2789
1403
|
userData: {}
|
|
2790
1404
|
};
|
|
2791
|
-
|
|
2792
1405
|
addUnknownExtensionsToUserData( extensions, result, json );
|
|
2793
|
-
|
|
2794
1406
|
assignExtrasToUserData( result, json );
|
|
2795
|
-
|
|
2796
1407
|
return Promise.all( parser._invokeAll( function ( ext ) {
|
|
2797
|
-
|
|
2798
1408
|
return ext.afterRoot && ext.afterRoot( result );
|
|
2799
|
-
|
|
2800
1409
|
} ) ).then( function () {
|
|
2801
|
-
|
|
2802
1410
|
for ( const scene of result.scenes ) {
|
|
2803
|
-
|
|
2804
1411
|
scene.updateMatrixWorld();
|
|
2805
|
-
|
|
2806
1412
|
}
|
|
2807
|
-
|
|
2808
1413
|
onLoad( result );
|
|
2809
|
-
|
|
2810
1414
|
} );
|
|
2811
|
-
|
|
2812
1415
|
} ).catch( onError );
|
|
2813
|
-
|
|
2814
1416
|
}
|
|
2815
|
-
|
|
2816
|
-
/**
|
|
2817
|
-
* Marks the special nodes/meshes in json for efficient parse.
|
|
2818
|
-
*
|
|
2819
|
-
* @private
|
|
2820
|
-
*/
|
|
2821
1417
|
_markDefs() {
|
|
2822
|
-
|
|
2823
1418
|
const nodeDefs = this.json.nodes || [];
|
|
2824
1419
|
const skinDefs = this.json.skins || [];
|
|
2825
1420
|
const meshDefs = this.json.meshes || [];
|
|
2826
|
-
|
|
2827
|
-
// Nothing in the node definition indicates whether it is a Bone or an
|
|
2828
|
-
// Object3D. Use the skins' joint references to mark bones.
|
|
2829
1421
|
for ( let skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex ++ ) {
|
|
2830
|
-
|
|
2831
1422
|
const joints = skinDefs[ skinIndex ].joints;
|
|
2832
|
-
|
|
2833
1423
|
for ( let i = 0, il = joints.length; i < il; i ++ ) {
|
|
2834
|
-
|
|
2835
1424
|
nodeDefs[ joints[ i ] ].isBone = true;
|
|
2836
|
-
|
|
2837
1425
|
}
|
|
2838
|
-
|
|
2839
1426
|
}
|
|
2840
|
-
|
|
2841
|
-
// Iterate over all nodes, marking references to shared resources,
|
|
2842
|
-
// as well as skeleton joints.
|
|
2843
1427
|
for ( let nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex ++ ) {
|
|
2844
|
-
|
|
2845
1428
|
const nodeDef = nodeDefs[ nodeIndex ];
|
|
2846
|
-
|
|
2847
1429
|
if ( nodeDef.mesh !== undefined ) {
|
|
2848
|
-
|
|
2849
1430
|
this._addNodeRef( this.meshCache, nodeDef.mesh );
|
|
2850
|
-
|
|
2851
|
-
// Nothing in the mesh definition indicates whether it is
|
|
2852
|
-
// a SkinnedMesh or Mesh. Use the node's mesh reference
|
|
2853
|
-
// to mark SkinnedMesh if node has skin.
|
|
2854
1431
|
if ( nodeDef.skin !== undefined ) {
|
|
2855
|
-
|
|
2856
1432
|
meshDefs[ nodeDef.mesh ].isSkinnedMesh = true;
|
|
2857
|
-
|
|
2858
1433
|
}
|
|
2859
|
-
|
|
2860
1434
|
}
|
|
2861
|
-
|
|
2862
1435
|
if ( nodeDef.camera !== undefined ) {
|
|
2863
|
-
|
|
2864
1436
|
this._addNodeRef( this.cameraCache, nodeDef.camera );
|
|
2865
|
-
|
|
2866
1437
|
}
|
|
2867
|
-
|
|
2868
1438
|
}
|
|
2869
|
-
|
|
2870
1439
|
}
|
|
2871
|
-
|
|
2872
|
-
/**
|
|
2873
|
-
* Counts references to shared node / Object3D resources. These resources
|
|
2874
|
-
* can be reused, or "instantiated", at multiple nodes in the scene
|
|
2875
|
-
* hierarchy. Mesh, Camera, and Light instances are instantiated and must
|
|
2876
|
-
* be marked. Non-scenegraph resources (like Materials, Geometries, and
|
|
2877
|
-
* Textures) can be reused directly and are not marked here.
|
|
2878
|
-
*
|
|
2879
|
-
* Example: CesiumMilkTruck sample model reuses "Wheel" meshes.
|
|
2880
|
-
*
|
|
2881
|
-
* @private
|
|
2882
|
-
* @param {Object} cache
|
|
2883
|
-
* @param {Object3D} index
|
|
2884
|
-
*/
|
|
2885
1440
|
_addNodeRef( cache, index ) {
|
|
2886
|
-
|
|
2887
1441
|
if ( index === undefined ) return;
|
|
2888
|
-
|
|
2889
1442
|
if ( cache.refs[ index ] === undefined ) {
|
|
2890
|
-
|
|
2891
1443
|
cache.refs[ index ] = cache.uses[ index ] = 0;
|
|
2892
|
-
|
|
2893
1444
|
}
|
|
2894
|
-
|
|
2895
1445
|
cache.refs[ index ] ++;
|
|
2896
|
-
|
|
2897
1446
|
}
|
|
2898
|
-
|
|
2899
|
-
/**
|
|
2900
|
-
* Returns a reference to a shared resource, cloning it if necessary.
|
|
2901
|
-
*
|
|
2902
|
-
* @private
|
|
2903
|
-
* @param {Object} cache
|
|
2904
|
-
* @param {number} index
|
|
2905
|
-
* @param {Object} object
|
|
2906
|
-
* @return {Object}
|
|
2907
|
-
*/
|
|
2908
1447
|
_getNodeRef( cache, index, object ) {
|
|
2909
|
-
|
|
2910
1448
|
if ( cache.refs[ index ] <= 1 ) return object;
|
|
2911
|
-
|
|
2912
1449
|
const ref = object.clone();
|
|
2913
|
-
|
|
2914
|
-
// Propagates mappings to the cloned object, prevents mappings on the
|
|
2915
|
-
// original object from being lost.
|
|
2916
1450
|
const updateMappings = ( original, clone ) => {
|
|
2917
|
-
|
|
2918
1451
|
const mappings = this.associations.get( original );
|
|
2919
1452
|
if ( mappings != null ) {
|
|
2920
|
-
|
|
2921
1453
|
this.associations.set( clone, mappings );
|
|
2922
|
-
|
|
2923
1454
|
}
|
|
2924
|
-
|
|
2925
1455
|
for ( const [ i, child ] of original.children.entries() ) {
|
|
2926
|
-
|
|
2927
1456
|
updateMappings( child, clone.children[ i ] );
|
|
2928
|
-
|
|
2929
1457
|
}
|
|
2930
|
-
|
|
2931
1458
|
};
|
|
2932
|
-
|
|
2933
1459
|
updateMappings( object, ref );
|
|
2934
|
-
|
|
2935
1460
|
ref.name += '_instance_' + ( cache.uses[ index ] ++ );
|
|
2936
|
-
|
|
2937
1461
|
return ref;
|
|
2938
|
-
|
|
2939
1462
|
}
|
|
2940
|
-
|
|
2941
1463
|
_invokeOne( func ) {
|
|
2942
|
-
|
|
2943
1464
|
const extensions = Object.values( this.plugins );
|
|
2944
1465
|
extensions.push( this );
|
|
2945
|
-
|
|
2946
1466
|
for ( let i = 0; i < extensions.length; i ++ ) {
|
|
2947
|
-
|
|
2948
1467
|
const result = func( extensions[ i ] );
|
|
2949
|
-
|
|
2950
1468
|
if ( result ) return result;
|
|
2951
|
-
|
|
2952
1469
|
}
|
|
2953
|
-
|
|
2954
1470
|
return null;
|
|
2955
|
-
|
|
2956
1471
|
}
|
|
2957
|
-
|
|
2958
1472
|
_invokeAll( func ) {
|
|
2959
|
-
|
|
2960
1473
|
const extensions = Object.values( this.plugins );
|
|
2961
1474
|
extensions.unshift( this );
|
|
2962
|
-
|
|
2963
1475
|
const pending = [];
|
|
2964
|
-
|
|
2965
1476
|
for ( let i = 0; i < extensions.length; i ++ ) {
|
|
2966
|
-
|
|
2967
1477
|
const result = func( extensions[ i ] );
|
|
2968
|
-
|
|
2969
1478
|
if ( result ) pending.push( result );
|
|
2970
|
-
|
|
2971
1479
|
}
|
|
2972
|
-
|
|
2973
1480
|
return pending;
|
|
2974
|
-
|
|
2975
1481
|
}
|
|
2976
|
-
|
|
2977
|
-
/**
|
|
2978
|
-
* Requests the specified dependency asynchronously, with caching.
|
|
2979
|
-
*
|
|
2980
|
-
* @private
|
|
2981
|
-
* @param {string} type
|
|
2982
|
-
* @param {number} index
|
|
2983
|
-
* @return {Promise<Object3D|Material|THREE.Texture|AnimationClip|ArrayBuffer|Object>}
|
|
2984
|
-
*/
|
|
2985
1482
|
getDependency( type, index ) {
|
|
2986
|
-
|
|
2987
1483
|
const cacheKey = type + ':' + index;
|
|
2988
1484
|
let dependency = this.cache.get( cacheKey );
|
|
2989
|
-
|
|
2990
1485
|
if ( ! dependency ) {
|
|
2991
|
-
|
|
2992
1486
|
switch ( type ) {
|
|
2993
|
-
|
|
2994
1487
|
case 'scene':
|
|
2995
1488
|
dependency = this.loadScene( index );
|
|
2996
1489
|
break;
|
|
2997
|
-
|
|
2998
1490
|
case 'node':
|
|
2999
1491
|
dependency = this._invokeOne( function ( ext ) {
|
|
3000
|
-
|
|
3001
1492
|
return ext.loadNode && ext.loadNode( index );
|
|
3002
|
-
|
|
3003
1493
|
} );
|
|
3004
1494
|
break;
|
|
3005
|
-
|
|
3006
1495
|
case 'mesh':
|
|
3007
1496
|
dependency = this._invokeOne( function ( ext ) {
|
|
3008
|
-
|
|
3009
1497
|
return ext.loadMesh && ext.loadMesh( index );
|
|
3010
|
-
|
|
3011
1498
|
} );
|
|
3012
1499
|
break;
|
|
3013
|
-
|
|
3014
1500
|
case 'accessor':
|
|
3015
1501
|
dependency = this.loadAccessor( index );
|
|
3016
1502
|
break;
|
|
3017
|
-
|
|
3018
1503
|
case 'bufferView':
|
|
3019
1504
|
dependency = this._invokeOne( function ( ext ) {
|
|
3020
|
-
|
|
3021
1505
|
return ext.loadBufferView && ext.loadBufferView( index );
|
|
3022
|
-
|
|
3023
1506
|
} );
|
|
3024
1507
|
break;
|
|
3025
|
-
|
|
3026
1508
|
case 'buffer':
|
|
3027
1509
|
dependency = this.loadBuffer( index );
|
|
3028
1510
|
break;
|
|
3029
|
-
|
|
3030
1511
|
case 'material':
|
|
3031
1512
|
dependency = this._invokeOne( function ( ext ) {
|
|
3032
|
-
|
|
3033
1513
|
return ext.loadMaterial && ext.loadMaterial( index );
|
|
3034
|
-
|
|
3035
1514
|
} );
|
|
3036
1515
|
break;
|
|
3037
|
-
|
|
3038
1516
|
case 'texture':
|
|
3039
1517
|
dependency = this._invokeOne( function ( ext ) {
|
|
3040
|
-
|
|
3041
1518
|
return ext.loadTexture && ext.loadTexture( index );
|
|
3042
|
-
|
|
3043
1519
|
} );
|
|
3044
1520
|
break;
|
|
3045
|
-
|
|
3046
1521
|
case 'skin':
|
|
3047
1522
|
dependency = this.loadSkin( index );
|
|
3048
1523
|
break;
|
|
3049
|
-
|
|
3050
1524
|
case 'animation':
|
|
3051
1525
|
dependency = this._invokeOne( function ( ext ) {
|
|
3052
|
-
|
|
3053
1526
|
return ext.loadAnimation && ext.loadAnimation( index );
|
|
3054
|
-
|
|
3055
1527
|
} );
|
|
3056
1528
|
break;
|
|
3057
|
-
|
|
3058
1529
|
case 'camera':
|
|
3059
1530
|
dependency = this.loadCamera( index );
|
|
3060
1531
|
break;
|
|
3061
|
-
|
|
3062
1532
|
default:
|
|
3063
1533
|
dependency = this._invokeOne( function ( ext ) {
|
|
3064
|
-
|
|
3065
1534
|
return ext != this && ext.getDependency && ext.getDependency( type, index );
|
|
3066
|
-
|
|
3067
1535
|
} );
|
|
3068
|
-
|
|
3069
1536
|
if ( ! dependency ) {
|
|
3070
|
-
|
|
3071
1537
|
throw new Error( 'Unknown type: ' + type );
|
|
3072
|
-
|
|
3073
1538
|
}
|
|
3074
|
-
|
|
3075
1539
|
break;
|
|
3076
|
-
|
|
3077
1540
|
}
|
|
3078
|
-
|
|
3079
1541
|
this.cache.add( cacheKey, dependency );
|
|
3080
|
-
|
|
3081
1542
|
}
|
|
3082
|
-
|
|
3083
1543
|
return dependency;
|
|
3084
|
-
|
|
3085
1544
|
}
|
|
3086
|
-
|
|
3087
|
-
/**
|
|
3088
|
-
* Requests all dependencies of the specified type asynchronously, with caching.
|
|
3089
|
-
*
|
|
3090
|
-
* @private
|
|
3091
|
-
* @param {string} type
|
|
3092
|
-
* @return {Promise<Array<Object>>}
|
|
3093
|
-
*/
|
|
3094
1545
|
getDependencies( type ) {
|
|
3095
|
-
|
|
3096
1546
|
let dependencies = this.cache.get( type );
|
|
3097
|
-
|
|
3098
1547
|
if ( ! dependencies ) {
|
|
3099
|
-
|
|
3100
1548
|
const parser = this;
|
|
3101
1549
|
const defs = this.json[ type + ( type === 'mesh' ? 'es' : 's' ) ] || [];
|
|
3102
|
-
|
|
3103
1550
|
dependencies = Promise.all( defs.map( function ( def, index ) {
|
|
3104
|
-
|
|
3105
1551
|
return parser.getDependency( type, index );
|
|
3106
|
-
|
|
3107
1552
|
} ) );
|
|
3108
|
-
|
|
3109
1553
|
this.cache.add( type, dependencies );
|
|
3110
|
-
|
|
3111
1554
|
}
|
|
3112
|
-
|
|
3113
1555
|
return dependencies;
|
|
3114
|
-
|
|
3115
1556
|
}
|
|
3116
|
-
|
|
3117
|
-
/**
|
|
3118
|
-
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
|
|
3119
|
-
*
|
|
3120
|
-
* @private
|
|
3121
|
-
* @param {number} bufferIndex
|
|
3122
|
-
* @return {Promise<ArrayBuffer>}
|
|
3123
|
-
*/
|
|
3124
1557
|
loadBuffer( bufferIndex ) {
|
|
3125
|
-
|
|
3126
1558
|
const bufferDef = this.json.buffers[ bufferIndex ];
|
|
3127
1559
|
const loader = this.fileLoader;
|
|
3128
|
-
|
|
3129
1560
|
if ( bufferDef.type && bufferDef.type !== 'arraybuffer' ) {
|
|
3130
|
-
|
|
3131
1561
|
throw new Error( 'THREE.GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.' );
|
|
3132
|
-
|
|
3133
1562
|
}
|
|
3134
|
-
|
|
3135
|
-
// If present, GLB container is required to be the first buffer.
|
|
3136
1563
|
if ( bufferDef.uri === undefined && bufferIndex === 0 ) {
|
|
3137
|
-
|
|
3138
1564
|
return Promise.resolve( this.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body );
|
|
3139
|
-
|
|
3140
1565
|
}
|
|
3141
|
-
|
|
3142
1566
|
const options = this.options;
|
|
3143
|
-
|
|
3144
1567
|
return new Promise( function ( resolve, reject ) {
|
|
3145
|
-
|
|
3146
1568
|
loader.load( three.LoaderUtils.resolveURL( bufferDef.uri, options.path ), resolve, undefined, function () {
|
|
3147
|
-
|
|
3148
1569
|
reject( new Error( 'THREE.GLTFLoader: Failed to load buffer "' + bufferDef.uri + '".' ) );
|
|
3149
|
-
|
|
3150
1570
|
} );
|
|
3151
|
-
|
|
3152
1571
|
} );
|
|
3153
|
-
|
|
3154
1572
|
}
|
|
3155
|
-
|
|
3156
|
-
/**
|
|
3157
|
-
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
|
|
3158
|
-
*
|
|
3159
|
-
* @private
|
|
3160
|
-
* @param {number} bufferViewIndex
|
|
3161
|
-
* @return {Promise<ArrayBuffer>}
|
|
3162
|
-
*/
|
|
3163
1573
|
loadBufferView( bufferViewIndex ) {
|
|
3164
|
-
|
|
3165
1574
|
const bufferViewDef = this.json.bufferViews[ bufferViewIndex ];
|
|
3166
|
-
|
|
3167
1575
|
return this.getDependency( 'buffer', bufferViewDef.buffer ).then( function ( buffer ) {
|
|
3168
|
-
|
|
3169
1576
|
const byteLength = bufferViewDef.byteLength || 0;
|
|
3170
1577
|
const byteOffset = bufferViewDef.byteOffset || 0;
|
|
3171
1578
|
return buffer.slice( byteOffset, byteOffset + byteLength );
|
|
3172
|
-
|
|
3173
1579
|
} );
|
|
3174
|
-
|
|
3175
1580
|
}
|
|
3176
|
-
|
|
3177
|
-
/**
|
|
3178
|
-
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors
|
|
3179
|
-
*
|
|
3180
|
-
* @private
|
|
3181
|
-
* @param {number} accessorIndex
|
|
3182
|
-
* @return {Promise<BufferAttribute|InterleavedBufferAttribute>}
|
|
3183
|
-
*/
|
|
3184
1581
|
loadAccessor( accessorIndex ) {
|
|
3185
|
-
|
|
3186
1582
|
const parser = this;
|
|
3187
1583
|
const json = this.json;
|
|
3188
|
-
|
|
3189
1584
|
const accessorDef = this.json.accessors[ accessorIndex ];
|
|
3190
|
-
|
|
3191
1585
|
if ( accessorDef.bufferView === undefined && accessorDef.sparse === undefined ) {
|
|
3192
|
-
|
|
3193
1586
|
const itemSize = WEBGL_TYPE_SIZES[ accessorDef.type ];
|
|
3194
1587
|
const TypedArray = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
|
|
3195
1588
|
const normalized = accessorDef.normalized === true;
|
|
3196
|
-
|
|
3197
1589
|
const array = new TypedArray( accessorDef.count * itemSize );
|
|
3198
1590
|
return Promise.resolve( new three.BufferAttribute( array, itemSize, normalized ) );
|
|
3199
|
-
|
|
3200
1591
|
}
|
|
3201
|
-
|
|
3202
1592
|
const pendingBufferViews = [];
|
|
3203
|
-
|
|
3204
1593
|
if ( accessorDef.bufferView !== undefined ) {
|
|
3205
|
-
|
|
3206
1594
|
pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.bufferView ) );
|
|
3207
|
-
|
|
3208
1595
|
} else {
|
|
3209
|
-
|
|
3210
1596
|
pendingBufferViews.push( null );
|
|
3211
|
-
|
|
3212
1597
|
}
|
|
3213
|
-
|
|
3214
1598
|
if ( accessorDef.sparse !== undefined ) {
|
|
3215
|
-
|
|
3216
1599
|
pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.indices.bufferView ) );
|
|
3217
1600
|
pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.values.bufferView ) );
|
|
3218
|
-
|
|
3219
1601
|
}
|
|
3220
|
-
|
|
3221
1602
|
return Promise.all( pendingBufferViews ).then( function ( bufferViews ) {
|
|
3222
|
-
|
|
3223
1603
|
const bufferView = bufferViews[ 0 ];
|
|
3224
|
-
|
|
3225
1604
|
const itemSize = WEBGL_TYPE_SIZES[ accessorDef.type ];
|
|
3226
1605
|
const TypedArray = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
|
|
3227
|
-
|
|
3228
|
-
// For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
|
|
3229
1606
|
const elementBytes = TypedArray.BYTES_PER_ELEMENT;
|
|
3230
1607
|
const itemBytes = elementBytes * itemSize;
|
|
3231
1608
|
const byteOffset = accessorDef.byteOffset || 0;
|
|
3232
1609
|
const byteStride = accessorDef.bufferView !== undefined ? json.bufferViews[ accessorDef.bufferView ].byteStride : undefined;
|
|
3233
1610
|
const normalized = accessorDef.normalized === true;
|
|
3234
1611
|
let array, bufferAttribute;
|
|
3235
|
-
|
|
3236
|
-
// The buffer is not interleaved if the stride is the item size in bytes.
|
|
3237
1612
|
if ( byteStride && byteStride !== itemBytes ) {
|
|
3238
|
-
|
|
3239
|
-
// Each "slice" of the buffer, as defined by 'count' elements of 'byteStride' bytes, gets its own InterleavedBuffer
|
|
3240
|
-
// This makes sure that IBA.count reflects accessor.count properly
|
|
3241
1613
|
const ibSlice = Math.floor( byteOffset / byteStride );
|
|
3242
1614
|
const ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType + ':' + ibSlice + ':' + accessorDef.count;
|
|
3243
1615
|
let ib = parser.cache.get( ibCacheKey );
|
|
3244
|
-
|
|
3245
1616
|
if ( ! ib ) {
|
|
3246
|
-
|
|
3247
1617
|
array = new TypedArray( bufferView, ibSlice * byteStride, accessorDef.count * byteStride / elementBytes );
|
|
3248
|
-
|
|
3249
|
-
// Integer parameters to IB/IBA are in array elements, not bytes.
|
|
3250
1618
|
ib = new three.InterleavedBuffer( array, byteStride / elementBytes );
|
|
3251
|
-
|
|
3252
1619
|
parser.cache.add( ibCacheKey, ib );
|
|
3253
|
-
|
|
3254
1620
|
}
|
|
3255
|
-
|
|
3256
1621
|
bufferAttribute = new three.InterleavedBufferAttribute( ib, itemSize, ( byteOffset % byteStride ) / elementBytes, normalized );
|
|
3257
|
-
|
|
3258
1622
|
} else {
|
|
3259
|
-
|
|
3260
1623
|
if ( bufferView === null ) {
|
|
3261
|
-
|
|
3262
1624
|
array = new TypedArray( accessorDef.count * itemSize );
|
|
3263
|
-
|
|
3264
1625
|
} else {
|
|
3265
|
-
|
|
3266
1626
|
array = new TypedArray( bufferView, byteOffset, accessorDef.count * itemSize );
|
|
3267
|
-
|
|
3268
1627
|
}
|
|
3269
|
-
|
|
3270
1628
|
bufferAttribute = new three.BufferAttribute( array, itemSize, normalized );
|
|
3271
|
-
|
|
3272
1629
|
}
|
|
3273
|
-
|
|
3274
|
-
// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessors
|
|
3275
1630
|
if ( accessorDef.sparse !== undefined ) {
|
|
3276
|
-
|
|
3277
1631
|
const itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR;
|
|
3278
1632
|
const TypedArrayIndices = WEBGL_COMPONENT_TYPES[ accessorDef.sparse.indices.componentType ];
|
|
3279
|
-
|
|
3280
1633
|
const byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0;
|
|
3281
1634
|
const byteOffsetValues = accessorDef.sparse.values.byteOffset || 0;
|
|
3282
|
-
|
|
3283
1635
|
const sparseIndices = new TypedArrayIndices( bufferViews[ 1 ], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices );
|
|
3284
1636
|
const sparseValues = new TypedArray( bufferViews[ 2 ], byteOffsetValues, accessorDef.sparse.count * itemSize );
|
|
3285
|
-
|
|
3286
1637
|
if ( bufferView !== null ) {
|
|
3287
|
-
|
|
3288
|
-
// Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes.
|
|
3289
1638
|
bufferAttribute = new three.BufferAttribute( bufferAttribute.array.slice(), bufferAttribute.itemSize, bufferAttribute.normalized );
|
|
3290
|
-
|
|
3291
1639
|
}
|
|
3292
|
-
|
|
3293
|
-
// Ignore normalized since we copy from sparse
|
|
3294
1640
|
bufferAttribute.normalized = false;
|
|
3295
|
-
|
|
3296
1641
|
for ( let i = 0, il = sparseIndices.length; i < il; i ++ ) {
|
|
3297
|
-
|
|
3298
1642
|
const index = sparseIndices[ i ];
|
|
3299
|
-
|
|
3300
1643
|
bufferAttribute.setX( index, sparseValues[ i * itemSize ] );
|
|
3301
1644
|
if ( itemSize >= 2 ) bufferAttribute.setY( index, sparseValues[ i * itemSize + 1 ] );
|
|
3302
1645
|
if ( itemSize >= 3 ) bufferAttribute.setZ( index, sparseValues[ i * itemSize + 2 ] );
|
|
3303
1646
|
if ( itemSize >= 4 ) bufferAttribute.setW( index, sparseValues[ i * itemSize + 3 ] );
|
|
3304
1647
|
if ( itemSize >= 5 ) throw new Error( 'THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.' );
|
|
3305
|
-
|
|
3306
1648
|
}
|
|
3307
|
-
|
|
3308
1649
|
bufferAttribute.normalized = normalized;
|
|
3309
|
-
|
|
3310
1650
|
}
|
|
3311
|
-
|
|
3312
1651
|
return bufferAttribute;
|
|
3313
|
-
|
|
3314
1652
|
} );
|
|
3315
|
-
|
|
3316
1653
|
}
|
|
3317
|
-
|
|
3318
|
-
/**
|
|
3319
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures
|
|
3320
|
-
*
|
|
3321
|
-
* @private
|
|
3322
|
-
* @param {number} textureIndex
|
|
3323
|
-
* @return {Promise<THREE.Texture|null>}
|
|
3324
|
-
*/
|
|
3325
1654
|
loadTexture( textureIndex ) {
|
|
3326
|
-
|
|
3327
1655
|
const json = this.json;
|
|
3328
1656
|
const options = this.options;
|
|
3329
1657
|
const textureDef = json.textures[ textureIndex ];
|
|
3330
1658
|
const sourceIndex = textureDef.source;
|
|
3331
1659
|
const sourceDef = json.images[ sourceIndex ];
|
|
3332
|
-
|
|
3333
1660
|
let loader = this.textureLoader;
|
|
3334
|
-
|
|
3335
1661
|
if ( sourceDef.uri ) {
|
|
3336
|
-
|
|
3337
1662
|
const handler = options.manager.getHandler( sourceDef.uri );
|
|
3338
1663
|
if ( handler !== null ) loader = handler;
|
|
3339
|
-
|
|
3340
1664
|
}
|
|
3341
|
-
|
|
3342
1665
|
return this.loadTextureImage( textureIndex, sourceIndex, loader );
|
|
3343
|
-
|
|
3344
1666
|
}
|
|
3345
|
-
|
|
3346
1667
|
loadTextureImage( textureIndex, sourceIndex, loader ) {
|
|
3347
|
-
|
|
3348
1668
|
const parser = this;
|
|
3349
1669
|
const json = this.json;
|
|
3350
|
-
|
|
3351
1670
|
const textureDef = json.textures[ textureIndex ];
|
|
3352
1671
|
const sourceDef = json.images[ sourceIndex ];
|
|
3353
|
-
|
|
3354
1672
|
const cacheKey = ( sourceDef.uri || sourceDef.bufferView ) + ':' + textureDef.sampler;
|
|
3355
|
-
|
|
3356
1673
|
if ( this.textureCache[ cacheKey ] ) {
|
|
3357
|
-
|
|
3358
|
-
// See https://github.com/mrdoob/three.js/issues/21559.
|
|
3359
1674
|
return this.textureCache[ cacheKey ];
|
|
3360
|
-
|
|
3361
1675
|
}
|
|
3362
|
-
|
|
3363
1676
|
const promise = this.loadImageSource( sourceIndex, loader ).then( function ( texture ) {
|
|
3364
|
-
|
|
3365
1677
|
texture.flipY = false;
|
|
3366
|
-
|
|
3367
1678
|
texture.name = textureDef.name || sourceDef.name || '';
|
|
3368
|
-
|
|
3369
1679
|
if ( texture.name === '' && typeof sourceDef.uri === 'string' && sourceDef.uri.startsWith( 'data:image/' ) === false ) {
|
|
3370
|
-
|
|
3371
1680
|
texture.name = sourceDef.uri;
|
|
3372
|
-
|
|
3373
1681
|
}
|
|
3374
|
-
|
|
3375
1682
|
const samplers = json.samplers || {};
|
|
3376
1683
|
const sampler = samplers[ textureDef.sampler ] || {};
|
|
3377
|
-
|
|
3378
1684
|
texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || three.LinearFilter;
|
|
3379
1685
|
texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || three.LinearMipmapLinearFilter;
|
|
3380
1686
|
texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || three.RepeatWrapping;
|
|
3381
1687
|
texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || three.RepeatWrapping;
|
|
3382
1688
|
texture.generateMipmaps = ! texture.isCompressedTexture && texture.minFilter !== three.NearestFilter && texture.minFilter !== three.LinearFilter;
|
|
3383
|
-
|
|
3384
1689
|
parser.associations.set( texture, { textures: textureIndex } );
|
|
3385
|
-
|
|
3386
1690
|
return texture;
|
|
3387
|
-
|
|
3388
1691
|
} ).catch( function () {
|
|
3389
|
-
|
|
3390
1692
|
return null;
|
|
3391
|
-
|
|
3392
1693
|
} );
|
|
3393
|
-
|
|
3394
1694
|
this.textureCache[ cacheKey ] = promise;
|
|
3395
|
-
|
|
3396
1695
|
return promise;
|
|
3397
|
-
|
|
3398
1696
|
}
|
|
3399
|
-
|
|
3400
1697
|
loadImageSource( sourceIndex, loader ) {
|
|
3401
|
-
|
|
3402
1698
|
const parser = this;
|
|
3403
1699
|
const json = this.json;
|
|
3404
1700
|
const options = this.options;
|
|
3405
|
-
|
|
3406
1701
|
if ( this.sourceCache[ sourceIndex ] !== undefined ) {
|
|
3407
|
-
|
|
3408
1702
|
return this.sourceCache[ sourceIndex ].then( ( texture ) => texture.clone() );
|
|
3409
|
-
|
|
3410
1703
|
}
|
|
3411
|
-
|
|
3412
1704
|
const sourceDef = json.images[ sourceIndex ];
|
|
3413
|
-
|
|
3414
1705
|
const URL = self.URL || self.webkitURL;
|
|
3415
|
-
|
|
3416
1706
|
let sourceURI = sourceDef.uri || '';
|
|
3417
1707
|
let isObjectURL = false;
|
|
3418
|
-
|
|
3419
1708
|
if ( sourceDef.bufferView !== undefined ) {
|
|
3420
|
-
|
|
3421
|
-
// Load binary image data from bufferView, if provided.
|
|
3422
|
-
|
|
3423
1709
|
sourceURI = parser.getDependency( 'bufferView', sourceDef.bufferView ).then( function ( bufferView ) {
|
|
3424
|
-
|
|
3425
1710
|
isObjectURL = true;
|
|
3426
1711
|
const blob = new Blob( [ bufferView ], { type: sourceDef.mimeType } );
|
|
3427
1712
|
sourceURI = URL.createObjectURL( blob );
|
|
3428
1713
|
return sourceURI;
|
|
3429
|
-
|
|
3430
1714
|
} );
|
|
3431
|
-
|
|
3432
1715
|
} else if ( sourceDef.uri === undefined ) {
|
|
3433
|
-
|
|
3434
1716
|
throw new Error( 'THREE.GLTFLoader: Image ' + sourceIndex + ' is missing URI and bufferView' );
|
|
3435
|
-
|
|
3436
1717
|
}
|
|
3437
|
-
|
|
3438
1718
|
const promise = Promise.resolve( sourceURI ).then( function ( sourceURI ) {
|
|
3439
|
-
|
|
3440
1719
|
return new Promise( function ( resolve, reject ) {
|
|
3441
|
-
|
|
3442
1720
|
let onLoad = resolve;
|
|
3443
|
-
|
|
3444
1721
|
if ( loader.isImageBitmapLoader === true ) {
|
|
3445
|
-
|
|
3446
1722
|
onLoad = function ( imageBitmap ) {
|
|
3447
|
-
|
|
3448
1723
|
const texture = new three.Texture( imageBitmap );
|
|
3449
1724
|
texture.needsUpdate = true;
|
|
3450
|
-
|
|
3451
1725
|
resolve( texture );
|
|
3452
|
-
|
|
3453
1726
|
};
|
|
3454
|
-
|
|
3455
1727
|
}
|
|
3456
|
-
|
|
3457
1728
|
loader.load( three.LoaderUtils.resolveURL( sourceURI, options.path ), onLoad, undefined, reject );
|
|
3458
|
-
|
|
3459
1729
|
} );
|
|
3460
|
-
|
|
3461
1730
|
} ).then( function ( texture ) {
|
|
3462
|
-
|
|
3463
|
-
// Clean up resources and configure Texture.
|
|
3464
|
-
|
|
3465
1731
|
if ( isObjectURL === true ) {
|
|
3466
|
-
|
|
3467
1732
|
URL.revokeObjectURL( sourceURI );
|
|
3468
|
-
|
|
3469
1733
|
}
|
|
3470
|
-
|
|
3471
1734
|
assignExtrasToUserData( texture, sourceDef );
|
|
3472
|
-
|
|
3473
1735
|
texture.userData.mimeType = sourceDef.mimeType || getImageURIMimeType( sourceDef.uri );
|
|
3474
|
-
|
|
3475
1736
|
return texture;
|
|
3476
|
-
|
|
3477
1737
|
} ).catch( function ( error ) {
|
|
3478
|
-
|
|
3479
1738
|
console.error( 'THREE.GLTFLoader: Couldn\'t load texture', sourceURI );
|
|
3480
1739
|
throw error;
|
|
3481
|
-
|
|
3482
1740
|
} );
|
|
3483
|
-
|
|
3484
1741
|
this.sourceCache[ sourceIndex ] = promise;
|
|
3485
1742
|
return promise;
|
|
3486
|
-
|
|
3487
1743
|
}
|
|
3488
|
-
|
|
3489
|
-
/**
|
|
3490
|
-
* Asynchronously assigns a texture to the given material parameters.
|
|
3491
|
-
*
|
|
3492
|
-
* @private
|
|
3493
|
-
* @param {Object} materialParams
|
|
3494
|
-
* @param {string} mapName
|
|
3495
|
-
* @param {Object} mapDef
|
|
3496
|
-
* @param {string} [colorSpace]
|
|
3497
|
-
* @return {Promise<Texture>}
|
|
3498
|
-
*/
|
|
3499
1744
|
assignTexture( materialParams, mapName, mapDef, colorSpace ) {
|
|
3500
|
-
|
|
3501
1745
|
const parser = this;
|
|
3502
|
-
|
|
3503
1746
|
return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) {
|
|
3504
|
-
|
|
3505
1747
|
if ( ! texture ) return null;
|
|
3506
|
-
|
|
3507
1748
|
if ( mapDef.texCoord !== undefined && mapDef.texCoord > 0 ) {
|
|
3508
|
-
|
|
3509
1749
|
texture = texture.clone();
|
|
3510
1750
|
texture.channel = mapDef.texCoord;
|
|
3511
|
-
|
|
3512
1751
|
}
|
|
3513
|
-
|
|
3514
1752
|
if ( parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] ) {
|
|
3515
|
-
|
|
3516
1753
|
const transform = mapDef.extensions !== undefined ? mapDef.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] : undefined;
|
|
3517
|
-
|
|
3518
1754
|
if ( transform ) {
|
|
3519
|
-
|
|
3520
1755
|
const gltfReference = parser.associations.get( texture );
|
|
3521
1756
|
texture = parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ].extendTexture( texture, transform );
|
|
3522
1757
|
parser.associations.set( texture, gltfReference );
|
|
3523
|
-
|
|
3524
1758
|
}
|
|
3525
|
-
|
|
3526
1759
|
}
|
|
3527
|
-
|
|
3528
1760
|
if ( colorSpace !== undefined ) {
|
|
3529
|
-
|
|
3530
1761
|
texture.colorSpace = colorSpace;
|
|
3531
|
-
|
|
3532
1762
|
}
|
|
3533
|
-
|
|
3534
1763
|
materialParams[ mapName ] = texture;
|
|
3535
|
-
|
|
3536
1764
|
return texture;
|
|
3537
|
-
|
|
3538
1765
|
} );
|
|
3539
|
-
|
|
3540
1766
|
}
|
|
3541
|
-
|
|
3542
|
-
/**
|
|
3543
|
-
* Assigns final material to a Mesh, Line, or Points instance. The instance
|
|
3544
|
-
* already has a material (generated from the glTF material options alone)
|
|
3545
|
-
* but reuse of the same glTF material may require multiple threejs materials
|
|
3546
|
-
* to accommodate different primitive types, defines, etc. New materials will
|
|
3547
|
-
* be created if necessary, and reused from a cache.
|
|
3548
|
-
*
|
|
3549
|
-
* @private
|
|
3550
|
-
* @param {Object3D} mesh Mesh, Line, or Points instance.
|
|
3551
|
-
*/
|
|
3552
1767
|
assignFinalMaterial( mesh ) {
|
|
3553
|
-
|
|
3554
1768
|
const geometry = mesh.geometry;
|
|
3555
1769
|
let material = mesh.material;
|
|
3556
|
-
|
|
3557
1770
|
const useDerivativeTangents = geometry.attributes.tangent === undefined;
|
|
3558
1771
|
const useVertexColors = geometry.attributes.color !== undefined;
|
|
3559
1772
|
const useFlatShading = geometry.attributes.normal === undefined;
|
|
3560
|
-
|
|
3561
1773
|
if ( mesh.isPoints ) {
|
|
3562
|
-
|
|
3563
1774
|
const cacheKey = 'PointsMaterial:' + material.uuid;
|
|
3564
|
-
|
|
3565
1775
|
let pointsMaterial = this.cache.get( cacheKey );
|
|
3566
|
-
|
|
3567
1776
|
if ( ! pointsMaterial ) {
|
|
3568
|
-
|
|
3569
1777
|
pointsMaterial = new three.PointsMaterial();
|
|
3570
1778
|
three.Material.prototype.copy.call( pointsMaterial, material );
|
|
3571
1779
|
pointsMaterial.color.copy( material.color );
|
|
3572
1780
|
pointsMaterial.map = material.map;
|
|
3573
|
-
pointsMaterial.sizeAttenuation = false;
|
|
3574
|
-
|
|
1781
|
+
pointsMaterial.sizeAttenuation = false;
|
|
3575
1782
|
this.cache.add( cacheKey, pointsMaterial );
|
|
3576
|
-
|
|
3577
1783
|
}
|
|
3578
|
-
|
|
3579
1784
|
material = pointsMaterial;
|
|
3580
|
-
|
|
3581
1785
|
} else if ( mesh.isLine ) {
|
|
3582
|
-
|
|
3583
1786
|
const cacheKey = 'LineBasicMaterial:' + material.uuid;
|
|
3584
|
-
|
|
3585
1787
|
let lineMaterial = this.cache.get( cacheKey );
|
|
3586
|
-
|
|
3587
1788
|
if ( ! lineMaterial ) {
|
|
3588
|
-
|
|
3589
1789
|
lineMaterial = new three.LineBasicMaterial();
|
|
3590
1790
|
three.Material.prototype.copy.call( lineMaterial, material );
|
|
3591
1791
|
lineMaterial.color.copy( material.color );
|
|
3592
1792
|
lineMaterial.map = material.map;
|
|
3593
|
-
|
|
3594
1793
|
this.cache.add( cacheKey, lineMaterial );
|
|
3595
|
-
|
|
3596
1794
|
}
|
|
3597
|
-
|
|
3598
1795
|
material = lineMaterial;
|
|
3599
|
-
|
|
3600
1796
|
}
|
|
3601
|
-
|
|
3602
|
-
// Clone the material if it will be modified
|
|
3603
1797
|
if ( useDerivativeTangents || useVertexColors || useFlatShading ) {
|
|
3604
|
-
|
|
3605
1798
|
let cacheKey = 'ClonedMaterial:' + material.uuid + ':';
|
|
3606
|
-
|
|
3607
1799
|
if ( useDerivativeTangents ) cacheKey += 'derivative-tangents:';
|
|
3608
1800
|
if ( useVertexColors ) cacheKey += 'vertex-colors:';
|
|
3609
1801
|
if ( useFlatShading ) cacheKey += 'flat-shading:';
|
|
3610
|
-
|
|
3611
1802
|
let cachedMaterial = this.cache.get( cacheKey );
|
|
3612
|
-
|
|
3613
1803
|
if ( ! cachedMaterial ) {
|
|
3614
|
-
|
|
3615
1804
|
cachedMaterial = material.clone();
|
|
3616
|
-
|
|
3617
1805
|
if ( useVertexColors ) cachedMaterial.vertexColors = true;
|
|
3618
1806
|
if ( useFlatShading ) cachedMaterial.flatShading = true;
|
|
3619
|
-
|
|
3620
1807
|
if ( useDerivativeTangents ) {
|
|
3621
|
-
|
|
3622
|
-
// https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995
|
|
3623
1808
|
if ( cachedMaterial.normalScale ) cachedMaterial.normalScale.y *= -1;
|
|
3624
1809
|
if ( cachedMaterial.clearcoatNormalScale ) cachedMaterial.clearcoatNormalScale.y *= -1;
|
|
3625
|
-
|
|
3626
1810
|
}
|
|
3627
|
-
|
|
3628
1811
|
this.cache.add( cacheKey, cachedMaterial );
|
|
3629
|
-
|
|
3630
1812
|
this.associations.set( cachedMaterial, this.associations.get( material ) );
|
|
3631
|
-
|
|
3632
1813
|
}
|
|
3633
|
-
|
|
3634
1814
|
material = cachedMaterial;
|
|
3635
|
-
|
|
3636
1815
|
}
|
|
3637
|
-
|
|
3638
1816
|
mesh.material = material;
|
|
3639
|
-
|
|
3640
1817
|
}
|
|
3641
|
-
|
|
3642
|
-
getMaterialType( /* materialIndex */ ) {
|
|
3643
|
-
|
|
1818
|
+
getMaterialType( ) {
|
|
3644
1819
|
return three.MeshStandardMaterial;
|
|
3645
|
-
|
|
3646
1820
|
}
|
|
3647
|
-
|
|
3648
|
-
/**
|
|
3649
|
-
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials
|
|
3650
|
-
*
|
|
3651
|
-
* @private
|
|
3652
|
-
* @param {number} materialIndex
|
|
3653
|
-
* @return {Promise<Material>}
|
|
3654
|
-
*/
|
|
3655
1821
|
loadMaterial( materialIndex ) {
|
|
3656
|
-
|
|
3657
1822
|
const parser = this;
|
|
3658
1823
|
const json = this.json;
|
|
3659
1824
|
const extensions = this.extensions;
|
|
3660
1825
|
const materialDef = json.materials[ materialIndex ];
|
|
3661
|
-
|
|
3662
1826
|
let materialType;
|
|
3663
1827
|
const materialParams = {};
|
|
3664
1828
|
const materialExtensions = materialDef.extensions || {};
|
|
3665
|
-
|
|
3666
1829
|
const pending = [];
|
|
3667
|
-
|
|
3668
1830
|
if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ] ) {
|
|
3669
|
-
|
|
3670
1831
|
const kmuExtension = extensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ];
|
|
3671
1832
|
materialType = kmuExtension.getMaterialType();
|
|
3672
1833
|
pending.push( kmuExtension.extendParams( materialParams, materialDef, parser ) );
|
|
3673
|
-
|
|
3674
1834
|
} else {
|
|
3675
|
-
|
|
3676
|
-
// Specification:
|
|
3677
|
-
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
|
|
3678
|
-
|
|
3679
1835
|
const metallicRoughness = materialDef.pbrMetallicRoughness || {};
|
|
3680
|
-
|
|
3681
1836
|
materialParams.color = new three.Color( 1.0, 1.0, 1.0 );
|
|
3682
1837
|
materialParams.opacity = 1.0;
|
|
3683
|
-
|
|
3684
1838
|
if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
|
|
3685
|
-
|
|
3686
1839
|
const array = metallicRoughness.baseColorFactor;
|
|
3687
|
-
|
|
3688
1840
|
materialParams.color.setRGB( array[ 0 ], array[ 1 ], array[ 2 ], three.LinearSRGBColorSpace );
|
|
3689
1841
|
materialParams.opacity = array[ 3 ];
|
|
3690
|
-
|
|
3691
1842
|
}
|
|
3692
|
-
|
|
3693
1843
|
if ( metallicRoughness.baseColorTexture !== undefined ) {
|
|
3694
|
-
|
|
3695
1844
|
pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture, three.SRGBColorSpace ) );
|
|
3696
|
-
|
|
3697
1845
|
}
|
|
3698
|
-
|
|
3699
1846
|
materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0;
|
|
3700
1847
|
materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0;
|
|
3701
|
-
|
|
3702
1848
|
if ( metallicRoughness.metallicRoughnessTexture !== undefined ) {
|
|
3703
|
-
|
|
3704
1849
|
pending.push( parser.assignTexture( materialParams, 'metalnessMap', metallicRoughness.metallicRoughnessTexture ) );
|
|
3705
1850
|
pending.push( parser.assignTexture( materialParams, 'roughnessMap', metallicRoughness.metallicRoughnessTexture ) );
|
|
3706
|
-
|
|
3707
1851
|
}
|
|
3708
|
-
|
|
3709
1852
|
materialType = this._invokeOne( function ( ext ) {
|
|
3710
|
-
|
|
3711
1853
|
return ext.getMaterialType && ext.getMaterialType( materialIndex );
|
|
3712
|
-
|
|
3713
1854
|
} );
|
|
3714
|
-
|
|
3715
1855
|
pending.push( Promise.all( this._invokeAll( function ( ext ) {
|
|
3716
|
-
|
|
3717
1856
|
return ext.extendMaterialParams && ext.extendMaterialParams( materialIndex, materialParams );
|
|
3718
|
-
|
|
3719
1857
|
} ) ) );
|
|
3720
|
-
|
|
3721
1858
|
}
|
|
3722
|
-
|
|
3723
1859
|
if ( materialDef.doubleSided === true ) {
|
|
3724
|
-
|
|
3725
1860
|
materialParams.side = three.DoubleSide;
|
|
3726
|
-
|
|
3727
1861
|
}
|
|
3728
|
-
|
|
3729
1862
|
const alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE;
|
|
3730
|
-
|
|
3731
1863
|
if ( alphaMode === ALPHA_MODES.BLEND ) {
|
|
3732
|
-
|
|
3733
1864
|
materialParams.transparent = true;
|
|
3734
|
-
|
|
3735
|
-
// See: https://github.com/mrdoob/three.js/issues/17706
|
|
3736
1865
|
materialParams.depthWrite = false;
|
|
3737
|
-
|
|
3738
1866
|
} else {
|
|
3739
|
-
|
|
3740
1867
|
materialParams.transparent = false;
|
|
3741
|
-
|
|
3742
1868
|
if ( alphaMode === ALPHA_MODES.MASK ) {
|
|
3743
|
-
|
|
3744
1869
|
materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5;
|
|
3745
|
-
|
|
3746
1870
|
}
|
|
3747
|
-
|
|
3748
1871
|
}
|
|
3749
|
-
|
|
3750
1872
|
if ( materialDef.normalTexture !== undefined && materialType !== three.MeshBasicMaterial ) {
|
|
3751
|
-
|
|
3752
1873
|
pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture ) );
|
|
3753
|
-
|
|
3754
1874
|
materialParams.normalScale = new three.Vector2( 1, 1 );
|
|
3755
|
-
|
|
3756
1875
|
if ( materialDef.normalTexture.scale !== undefined ) {
|
|
3757
|
-
|
|
3758
1876
|
const scale = materialDef.normalTexture.scale;
|
|
3759
|
-
|
|
3760
1877
|
materialParams.normalScale.set( scale, scale );
|
|
3761
|
-
|
|
3762
1878
|
}
|
|
3763
|
-
|
|
3764
1879
|
}
|
|
3765
|
-
|
|
3766
1880
|
if ( materialDef.occlusionTexture !== undefined && materialType !== three.MeshBasicMaterial ) {
|
|
3767
|
-
|
|
3768
1881
|
pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture ) );
|
|
3769
|
-
|
|
3770
1882
|
if ( materialDef.occlusionTexture.strength !== undefined ) {
|
|
3771
|
-
|
|
3772
1883
|
materialParams.aoMapIntensity = materialDef.occlusionTexture.strength;
|
|
3773
|
-
|
|
3774
1884
|
}
|
|
3775
|
-
|
|
3776
1885
|
}
|
|
3777
|
-
|
|
3778
1886
|
if ( materialDef.emissiveFactor !== undefined && materialType !== three.MeshBasicMaterial ) {
|
|
3779
|
-
|
|
3780
1887
|
const emissiveFactor = materialDef.emissiveFactor;
|
|
3781
1888
|
materialParams.emissive = new three.Color().setRGB( emissiveFactor[ 0 ], emissiveFactor[ 1 ], emissiveFactor[ 2 ], three.LinearSRGBColorSpace );
|
|
3782
|
-
|
|
3783
1889
|
}
|
|
3784
|
-
|
|
3785
1890
|
if ( materialDef.emissiveTexture !== undefined && materialType !== three.MeshBasicMaterial ) {
|
|
3786
|
-
|
|
3787
1891
|
pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture, three.SRGBColorSpace ) );
|
|
3788
|
-
|
|
3789
1892
|
}
|
|
3790
|
-
|
|
3791
1893
|
return Promise.all( pending ).then( function () {
|
|
3792
|
-
|
|
3793
1894
|
const material = new materialType( materialParams );
|
|
3794
|
-
|
|
3795
1895
|
if ( materialDef.name ) material.name = materialDef.name;
|
|
3796
|
-
|
|
3797
1896
|
assignExtrasToUserData( material, materialDef );
|
|
3798
|
-
|
|
3799
1897
|
parser.associations.set( material, { materials: materialIndex } );
|
|
3800
|
-
|
|
3801
1898
|
if ( materialDef.extensions ) addUnknownExtensionsToUserData( extensions, material, materialDef );
|
|
3802
|
-
|
|
3803
1899
|
return material;
|
|
3804
|
-
|
|
3805
1900
|
} );
|
|
3806
|
-
|
|
3807
1901
|
}
|
|
3808
|
-
|
|
3809
|
-
/**
|
|
3810
|
-
* When Object3D instances are targeted by animation, they need unique names.
|
|
3811
|
-
*
|
|
3812
|
-
* @private
|
|
3813
|
-
* @param {string} originalName
|
|
3814
|
-
* @return {string}
|
|
3815
|
-
*/
|
|
3816
1902
|
createUniqueName( originalName ) {
|
|
3817
|
-
|
|
3818
1903
|
const sanitizedName = three.PropertyBinding.sanitizeNodeName( originalName || '' );
|
|
3819
|
-
|
|
3820
1904
|
if ( sanitizedName in this.nodeNamesUsed ) {
|
|
3821
|
-
|
|
3822
1905
|
return sanitizedName + '_' + ( ++ this.nodeNamesUsed[ sanitizedName ] );
|
|
3823
|
-
|
|
3824
1906
|
} else {
|
|
3825
|
-
|
|
3826
1907
|
this.nodeNamesUsed[ sanitizedName ] = 0;
|
|
3827
|
-
|
|
3828
1908
|
return sanitizedName;
|
|
3829
|
-
|
|
3830
1909
|
}
|
|
3831
|
-
|
|
3832
1910
|
}
|
|
3833
|
-
|
|
3834
|
-
/**
|
|
3835
|
-
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry
|
|
3836
|
-
*
|
|
3837
|
-
* Creates BufferGeometries from primitives.
|
|
3838
|
-
*
|
|
3839
|
-
* @private
|
|
3840
|
-
* @param {Array<GLTF.Primitive>} primitives
|
|
3841
|
-
* @return {Promise<Array<BufferGeometry>>}
|
|
3842
|
-
*/
|
|
3843
1911
|
loadGeometries( primitives ) {
|
|
3844
|
-
|
|
3845
1912
|
const parser = this;
|
|
3846
1913
|
const extensions = this.extensions;
|
|
3847
1914
|
const cache = this.primitiveCache;
|
|
3848
|
-
|
|
3849
1915
|
function createDracoPrimitive( primitive ) {
|
|
3850
|
-
|
|
3851
1916
|
return extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ]
|
|
3852
1917
|
.decodePrimitive( primitive, parser )
|
|
3853
1918
|
.then( function ( geometry ) {
|
|
3854
|
-
|
|
3855
1919
|
return addPrimitiveAttributes( geometry, primitive, parser );
|
|
3856
|
-
|
|
3857
1920
|
} );
|
|
3858
|
-
|
|
3859
1921
|
}
|
|
3860
|
-
|
|
3861
1922
|
const pending = [];
|
|
3862
|
-
|
|
3863
1923
|
for ( let i = 0, il = primitives.length; i < il; i ++ ) {
|
|
3864
|
-
|
|
3865
1924
|
const primitive = primitives[ i ];
|
|
3866
1925
|
const cacheKey = createPrimitiveKey( primitive );
|
|
3867
|
-
|
|
3868
|
-
// See if we've already created this geometry
|
|
3869
1926
|
const cached = cache[ cacheKey ];
|
|
3870
|
-
|
|
3871
1927
|
if ( cached ) {
|
|
3872
|
-
|
|
3873
|
-
// Use the cached geometry if it exists
|
|
3874
1928
|
pending.push( cached.promise );
|
|
3875
|
-
|
|
3876
1929
|
} else {
|
|
3877
|
-
|
|
3878
1930
|
let geometryPromise;
|
|
3879
|
-
|
|
3880
1931
|
if ( primitive.extensions && primitive.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] ) {
|
|
3881
|
-
|
|
3882
|
-
// Use DRACO geometry if available
|
|
3883
1932
|
geometryPromise = createDracoPrimitive( primitive );
|
|
3884
|
-
|
|
3885
1933
|
} else {
|
|
3886
|
-
|
|
3887
|
-
// Otherwise create a new geometry
|
|
3888
1934
|
geometryPromise = addPrimitiveAttributes( new three.BufferGeometry(), primitive, parser );
|
|
3889
|
-
|
|
3890
1935
|
}
|
|
3891
|
-
|
|
3892
|
-
// Cache this geometry
|
|
3893
1936
|
cache[ cacheKey ] = { primitive: primitive, promise: geometryPromise };
|
|
3894
|
-
|
|
3895
1937
|
pending.push( geometryPromise );
|
|
3896
|
-
|
|
3897
1938
|
}
|
|
3898
|
-
|
|
3899
1939
|
}
|
|
3900
|
-
|
|
3901
1940
|
return Promise.all( pending );
|
|
3902
|
-
|
|
3903
1941
|
}
|
|
3904
|
-
|
|
3905
|
-
/**
|
|
3906
|
-
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes
|
|
3907
|
-
*
|
|
3908
|
-
* @private
|
|
3909
|
-
* @param {number} meshIndex
|
|
3910
|
-
* @return {Promise<Group|Mesh|SkinnedMesh|Line|Points>}
|
|
3911
|
-
*/
|
|
3912
1942
|
loadMesh( meshIndex ) {
|
|
3913
|
-
|
|
3914
1943
|
const parser = this;
|
|
3915
1944
|
const json = this.json;
|
|
3916
1945
|
const extensions = this.extensions;
|
|
3917
|
-
|
|
3918
1946
|
const meshDef = json.meshes[ meshIndex ];
|
|
3919
1947
|
const primitives = meshDef.primitives;
|
|
3920
|
-
|
|
3921
1948
|
const pending = [];
|
|
3922
|
-
|
|
3923
1949
|
for ( let i = 0, il = primitives.length; i < il; i ++ ) {
|
|
3924
|
-
|
|
3925
1950
|
const material = primitives[ i ].material === undefined
|
|
3926
1951
|
? createDefaultMaterial( this.cache )
|
|
3927
1952
|
: this.getDependency( 'material', primitives[ i ].material );
|
|
3928
|
-
|
|
3929
1953
|
pending.push( material );
|
|
3930
|
-
|
|
3931
1954
|
}
|
|
3932
|
-
|
|
3933
1955
|
pending.push( parser.loadGeometries( primitives ) );
|
|
3934
|
-
|
|
3935
1956
|
return Promise.all( pending ).then( function ( results ) {
|
|
3936
|
-
|
|
3937
1957
|
const materials = results.slice( 0, results.length - 1 );
|
|
3938
1958
|
const geometries = results[ results.length - 1 ];
|
|
3939
|
-
|
|
3940
1959
|
const meshes = [];
|
|
3941
|
-
|
|
3942
1960
|
for ( let i = 0, il = geometries.length; i < il; i ++ ) {
|
|
3943
|
-
|
|
3944
1961
|
const geometry = geometries[ i ];
|
|
3945
1962
|
const primitive = primitives[ i ];
|
|
3946
|
-
|
|
3947
|
-
// 1. create Mesh
|
|
3948
|
-
|
|
3949
1963
|
let mesh;
|
|
3950
|
-
|
|
3951
1964
|
const material = materials[ i ];
|
|
3952
|
-
|
|
3953
1965
|
if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
|
|
3954
1966
|
primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
|
|
3955
1967
|
primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
|
|
3956
1968
|
primitive.mode === undefined ) {
|
|
3957
|
-
|
|
3958
|
-
// .isSkinnedMesh isn't in glTF spec. See ._markDefs()
|
|
3959
1969
|
mesh = meshDef.isSkinnedMesh === true
|
|
3960
1970
|
? new three.SkinnedMesh( geometry, material )
|
|
3961
1971
|
: new three.Mesh( geometry, material );
|
|
3962
|
-
|
|
3963
1972
|
if ( mesh.isSkinnedMesh === true ) {
|
|
3964
|
-
|
|
3965
|
-
// normalize skin weights to fix malformed assets (see #15319)
|
|
3966
1973
|
mesh.normalizeSkinWeights();
|
|
3967
|
-
|
|
3968
1974
|
}
|
|
3969
|
-
|
|
3970
1975
|
if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
|
|
3971
|
-
|
|
3972
1976
|
mesh.geometry = toTrianglesDrawMode( mesh.geometry, three.TriangleStripDrawMode );
|
|
3973
|
-
|
|
3974
1977
|
} else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
|
|
3975
|
-
|
|
3976
1978
|
mesh.geometry = toTrianglesDrawMode( mesh.geometry, three.TriangleFanDrawMode );
|
|
3977
|
-
|
|
3978
1979
|
}
|
|
3979
|
-
|
|
3980
1980
|
} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
|
|
3981
|
-
|
|
3982
1981
|
mesh = new three.LineSegments( geometry, material );
|
|
3983
|
-
|
|
3984
1982
|
} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
|
|
3985
|
-
|
|
3986
1983
|
mesh = new three.Line( geometry, material );
|
|
3987
|
-
|
|
3988
1984
|
} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
|
|
3989
|
-
|
|
3990
1985
|
mesh = new three.LineLoop( geometry, material );
|
|
3991
|
-
|
|
3992
1986
|
} else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
|
|
3993
|
-
|
|
3994
1987
|
mesh = new three.Points( geometry, material );
|
|
3995
|
-
|
|
3996
1988
|
} else {
|
|
3997
|
-
|
|
3998
1989
|
throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
|
|
3999
|
-
|
|
4000
1990
|
}
|
|
4001
|
-
|
|
4002
1991
|
if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) {
|
|
4003
|
-
|
|
4004
1992
|
updateMorphTargets( mesh, meshDef );
|
|
4005
|
-
|
|
4006
1993
|
}
|
|
4007
|
-
|
|
4008
1994
|
mesh.name = parser.createUniqueName( meshDef.name || ( 'mesh_' + meshIndex ) );
|
|
4009
|
-
|
|
4010
1995
|
assignExtrasToUserData( mesh, meshDef );
|
|
4011
|
-
|
|
4012
1996
|
if ( primitive.extensions ) addUnknownExtensionsToUserData( extensions, mesh, primitive );
|
|
4013
|
-
|
|
4014
1997
|
parser.assignFinalMaterial( mesh );
|
|
4015
|
-
|
|
4016
1998
|
meshes.push( mesh );
|
|
4017
|
-
|
|
4018
1999
|
}
|
|
4019
|
-
|
|
4020
2000
|
for ( let i = 0, il = meshes.length; i < il; i ++ ) {
|
|
4021
|
-
|
|
4022
2001
|
parser.associations.set( meshes[ i ], {
|
|
4023
2002
|
meshes: meshIndex,
|
|
4024
2003
|
primitives: i
|
|
4025
2004
|
} );
|
|
4026
|
-
|
|
4027
2005
|
}
|
|
4028
|
-
|
|
4029
2006
|
if ( meshes.length === 1 ) {
|
|
4030
|
-
|
|
4031
2007
|
if ( meshDef.extensions ) addUnknownExtensionsToUserData( extensions, meshes[ 0 ], meshDef );
|
|
4032
|
-
|
|
4033
2008
|
return meshes[ 0 ];
|
|
4034
|
-
|
|
4035
2009
|
}
|
|
4036
|
-
|
|
4037
2010
|
const group = new three.Group();
|
|
4038
|
-
|
|
4039
2011
|
if ( meshDef.extensions ) addUnknownExtensionsToUserData( extensions, group, meshDef );
|
|
4040
|
-
|
|
4041
2012
|
parser.associations.set( group, { meshes: meshIndex } );
|
|
4042
|
-
|
|
4043
2013
|
for ( let i = 0, il = meshes.length; i < il; i ++ ) {
|
|
4044
|
-
|
|
4045
2014
|
group.add( meshes[ i ] );
|
|
4046
|
-
|
|
4047
2015
|
}
|
|
4048
|
-
|
|
4049
2016
|
return group;
|
|
4050
|
-
|
|
4051
2017
|
} );
|
|
4052
|
-
|
|
4053
2018
|
}
|
|
4054
|
-
|
|
4055
|
-
/**
|
|
4056
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras
|
|
4057
|
-
*
|
|
4058
|
-
* @private
|
|
4059
|
-
* @param {number} cameraIndex
|
|
4060
|
-
* @return {Promise<THREE.Camera>}
|
|
4061
|
-
*/
|
|
4062
2019
|
loadCamera( cameraIndex ) {
|
|
4063
|
-
|
|
4064
2020
|
let camera;
|
|
4065
2021
|
const cameraDef = this.json.cameras[ cameraIndex ];
|
|
4066
2022
|
const params = cameraDef[ cameraDef.type ];
|
|
4067
|
-
|
|
4068
2023
|
if ( ! params ) {
|
|
4069
|
-
|
|
4070
2024
|
console.warn( 'THREE.GLTFLoader: Missing camera parameters.' );
|
|
4071
2025
|
return;
|
|
4072
|
-
|
|
4073
2026
|
}
|
|
4074
|
-
|
|
4075
2027
|
if ( cameraDef.type === 'perspective' ) {
|
|
4076
|
-
|
|
4077
2028
|
camera = new three.PerspectiveCamera( three.MathUtils.radToDeg( params.yfov ), params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6 );
|
|
4078
|
-
|
|
4079
2029
|
} else if ( cameraDef.type === 'orthographic' ) {
|
|
4080
|
-
|
|
4081
2030
|
camera = new three.OrthographicCamera( - params.xmag, params.xmag, params.ymag, - params.ymag, params.znear, params.zfar );
|
|
4082
|
-
|
|
4083
2031
|
}
|
|
4084
|
-
|
|
4085
2032
|
if ( cameraDef.name ) camera.name = this.createUniqueName( cameraDef.name );
|
|
4086
|
-
|
|
4087
2033
|
assignExtrasToUserData( camera, cameraDef );
|
|
4088
|
-
|
|
4089
2034
|
return Promise.resolve( camera );
|
|
4090
|
-
|
|
4091
2035
|
}
|
|
4092
|
-
|
|
4093
|
-
/**
|
|
4094
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins
|
|
4095
|
-
*
|
|
4096
|
-
* @private
|
|
4097
|
-
* @param {number} skinIndex
|
|
4098
|
-
* @return {Promise<Skeleton>}
|
|
4099
|
-
*/
|
|
4100
2036
|
loadSkin( skinIndex ) {
|
|
4101
|
-
|
|
4102
2037
|
const skinDef = this.json.skins[ skinIndex ];
|
|
4103
|
-
|
|
4104
2038
|
const pending = [];
|
|
4105
|
-
|
|
4106
2039
|
for ( let i = 0, il = skinDef.joints.length; i < il; i ++ ) {
|
|
4107
|
-
|
|
4108
2040
|
pending.push( this._loadNodeShallow( skinDef.joints[ i ] ) );
|
|
4109
|
-
|
|
4110
2041
|
}
|
|
4111
|
-
|
|
4112
2042
|
if ( skinDef.inverseBindMatrices !== undefined ) {
|
|
4113
|
-
|
|
4114
2043
|
pending.push( this.getDependency( 'accessor', skinDef.inverseBindMatrices ) );
|
|
4115
|
-
|
|
4116
2044
|
} else {
|
|
4117
|
-
|
|
4118
2045
|
pending.push( null );
|
|
4119
|
-
|
|
4120
2046
|
}
|
|
4121
|
-
|
|
4122
2047
|
return Promise.all( pending ).then( function ( results ) {
|
|
4123
|
-
|
|
4124
2048
|
const inverseBindMatrices = results.pop();
|
|
4125
2049
|
const jointNodes = results;
|
|
4126
|
-
|
|
4127
|
-
// Note that bones (joint nodes) may or may not be in the
|
|
4128
|
-
// scene graph at this time.
|
|
4129
|
-
|
|
4130
2050
|
const bones = [];
|
|
4131
2051
|
const boneInverses = [];
|
|
4132
|
-
|
|
4133
2052
|
for ( let i = 0, il = jointNodes.length; i < il; i ++ ) {
|
|
4134
|
-
|
|
4135
2053
|
const jointNode = jointNodes[ i ];
|
|
4136
|
-
|
|
4137
2054
|
if ( jointNode ) {
|
|
4138
|
-
|
|
4139
2055
|
bones.push( jointNode );
|
|
4140
|
-
|
|
4141
2056
|
const mat = new three.Matrix4();
|
|
4142
|
-
|
|
4143
2057
|
if ( inverseBindMatrices !== null ) {
|
|
4144
|
-
|
|
4145
2058
|
mat.fromArray( inverseBindMatrices.array, i * 16 );
|
|
4146
|
-
|
|
4147
2059
|
}
|
|
4148
|
-
|
|
4149
2060
|
boneInverses.push( mat );
|
|
4150
|
-
|
|
4151
2061
|
} else {
|
|
4152
|
-
|
|
4153
2062
|
console.warn( 'THREE.GLTFLoader: Joint "%s" could not be found.', skinDef.joints[ i ] );
|
|
4154
|
-
|
|
4155
2063
|
}
|
|
4156
|
-
|
|
4157
2064
|
}
|
|
4158
|
-
|
|
4159
2065
|
return new three.Skeleton( bones, boneInverses );
|
|
4160
|
-
|
|
4161
2066
|
} );
|
|
4162
|
-
|
|
4163
2067
|
}
|
|
4164
|
-
|
|
4165
|
-
/**
|
|
4166
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations
|
|
4167
|
-
*
|
|
4168
|
-
* @private
|
|
4169
|
-
* @param {number} animationIndex
|
|
4170
|
-
* @return {Promise<AnimationClip>}
|
|
4171
|
-
*/
|
|
4172
2068
|
loadAnimation( animationIndex ) {
|
|
4173
|
-
|
|
4174
2069
|
const json = this.json;
|
|
4175
2070
|
const parser = this;
|
|
4176
|
-
|
|
4177
2071
|
const animationDef = json.animations[ animationIndex ];
|
|
4178
2072
|
const animationName = animationDef.name ? animationDef.name : 'animation_' + animationIndex;
|
|
4179
|
-
|
|
4180
2073
|
const pendingNodes = [];
|
|
4181
2074
|
const pendingInputAccessors = [];
|
|
4182
2075
|
const pendingOutputAccessors = [];
|
|
4183
2076
|
const pendingSamplers = [];
|
|
4184
2077
|
const pendingTargets = [];
|
|
4185
|
-
|
|
4186
2078
|
for ( let i = 0, il = animationDef.channels.length; i < il; i ++ ) {
|
|
4187
|
-
|
|
4188
2079
|
const channel = animationDef.channels[ i ];
|
|
4189
2080
|
const sampler = animationDef.samplers[ channel.sampler ];
|
|
4190
2081
|
const target = channel.target;
|
|
4191
2082
|
const name = target.node;
|
|
4192
2083
|
const input = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.input ] : sampler.input;
|
|
4193
2084
|
const output = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.output ] : sampler.output;
|
|
4194
|
-
|
|
4195
2085
|
if ( target.node === undefined ) continue;
|
|
4196
|
-
|
|
4197
2086
|
pendingNodes.push( this.getDependency( 'node', name ) );
|
|
4198
2087
|
pendingInputAccessors.push( this.getDependency( 'accessor', input ) );
|
|
4199
2088
|
pendingOutputAccessors.push( this.getDependency( 'accessor', output ) );
|
|
4200
2089
|
pendingSamplers.push( sampler );
|
|
4201
2090
|
pendingTargets.push( target );
|
|
4202
|
-
|
|
4203
2091
|
}
|
|
4204
|
-
|
|
4205
2092
|
return Promise.all( [
|
|
4206
|
-
|
|
4207
2093
|
Promise.all( pendingNodes ),
|
|
4208
2094
|
Promise.all( pendingInputAccessors ),
|
|
4209
2095
|
Promise.all( pendingOutputAccessors ),
|
|
4210
2096
|
Promise.all( pendingSamplers ),
|
|
4211
2097
|
Promise.all( pendingTargets )
|
|
4212
|
-
|
|
4213
2098
|
] ).then( function ( dependencies ) {
|
|
4214
|
-
|
|
4215
2099
|
const nodes = dependencies[ 0 ];
|
|
4216
2100
|
const inputAccessors = dependencies[ 1 ];
|
|
4217
2101
|
const outputAccessors = dependencies[ 2 ];
|
|
4218
2102
|
const samplers = dependencies[ 3 ];
|
|
4219
2103
|
const targets = dependencies[ 4 ];
|
|
4220
|
-
|
|
4221
2104
|
const tracks = [];
|
|
4222
|
-
|
|
4223
2105
|
for ( let i = 0, il = nodes.length; i < il; i ++ ) {
|
|
4224
|
-
|
|
4225
2106
|
const node = nodes[ i ];
|
|
4226
2107
|
const inputAccessor = inputAccessors[ i ];
|
|
4227
2108
|
const outputAccessor = outputAccessors[ i ];
|
|
4228
2109
|
const sampler = samplers[ i ];
|
|
4229
2110
|
const target = targets[ i ];
|
|
4230
|
-
|
|
4231
2111
|
if ( node === undefined ) continue;
|
|
4232
|
-
|
|
4233
2112
|
if ( node.updateMatrix ) {
|
|
4234
|
-
|
|
4235
2113
|
node.updateMatrix();
|
|
4236
|
-
|
|
4237
2114
|
}
|
|
4238
|
-
|
|
4239
2115
|
const createdTracks = parser._createAnimationTracks( node, inputAccessor, outputAccessor, sampler, target );
|
|
4240
|
-
|
|
4241
2116
|
if ( createdTracks ) {
|
|
4242
|
-
|
|
4243
2117
|
for ( let k = 0; k < createdTracks.length; k ++ ) {
|
|
4244
|
-
|
|
4245
2118
|
tracks.push( createdTracks[ k ] );
|
|
4246
|
-
|
|
4247
2119
|
}
|
|
4248
|
-
|
|
4249
2120
|
}
|
|
4250
|
-
|
|
4251
2121
|
}
|
|
4252
|
-
|
|
4253
2122
|
return new three.AnimationClip( animationName, undefined, tracks );
|
|
4254
|
-
|
|
4255
2123
|
} );
|
|
4256
|
-
|
|
4257
2124
|
}
|
|
4258
|
-
|
|
4259
2125
|
createNodeMesh( nodeIndex ) {
|
|
4260
|
-
|
|
4261
2126
|
const json = this.json;
|
|
4262
2127
|
const parser = this;
|
|
4263
2128
|
const nodeDef = json.nodes[ nodeIndex ];
|
|
4264
|
-
|
|
4265
2129
|
if ( nodeDef.mesh === undefined ) return null;
|
|
4266
|
-
|
|
4267
2130
|
return parser.getDependency( 'mesh', nodeDef.mesh ).then( function ( mesh ) {
|
|
4268
|
-
|
|
4269
2131
|
const node = parser._getNodeRef( parser.meshCache, nodeDef.mesh, mesh );
|
|
4270
|
-
|
|
4271
|
-
// if weights are provided on the node, override weights on the mesh.
|
|
4272
2132
|
if ( nodeDef.weights !== undefined ) {
|
|
4273
|
-
|
|
4274
2133
|
node.traverse( function ( o ) {
|
|
4275
|
-
|
|
4276
2134
|
if ( ! o.isMesh ) return;
|
|
4277
|
-
|
|
4278
2135
|
for ( let i = 0, il = nodeDef.weights.length; i < il; i ++ ) {
|
|
4279
|
-
|
|
4280
2136
|
o.morphTargetInfluences[ i ] = nodeDef.weights[ i ];
|
|
4281
|
-
|
|
4282
2137
|
}
|
|
4283
|
-
|
|
4284
2138
|
} );
|
|
4285
|
-
|
|
4286
2139
|
}
|
|
4287
|
-
|
|
4288
2140
|
return node;
|
|
4289
|
-
|
|
4290
2141
|
} );
|
|
4291
|
-
|
|
4292
2142
|
}
|
|
4293
|
-
|
|
4294
|
-
/**
|
|
4295
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy
|
|
4296
|
-
*
|
|
4297
|
-
* @private
|
|
4298
|
-
* @param {number} nodeIndex
|
|
4299
|
-
* @return {Promise<Object3D>}
|
|
4300
|
-
*/
|
|
4301
2143
|
loadNode( nodeIndex ) {
|
|
4302
|
-
|
|
4303
2144
|
const json = this.json;
|
|
4304
2145
|
const parser = this;
|
|
4305
|
-
|
|
4306
2146
|
const nodeDef = json.nodes[ nodeIndex ];
|
|
4307
|
-
|
|
4308
2147
|
const nodePending = parser._loadNodeShallow( nodeIndex );
|
|
4309
|
-
|
|
4310
2148
|
const childPending = [];
|
|
4311
2149
|
const childrenDef = nodeDef.children || [];
|
|
4312
|
-
|
|
4313
2150
|
for ( let i = 0, il = childrenDef.length; i < il; i ++ ) {
|
|
4314
|
-
|
|
4315
2151
|
childPending.push( parser.getDependency( 'node', childrenDef[ i ] ) );
|
|
4316
|
-
|
|
4317
2152
|
}
|
|
4318
|
-
|
|
4319
2153
|
const skeletonPending = nodeDef.skin === undefined
|
|
4320
2154
|
? Promise.resolve( null )
|
|
4321
2155
|
: parser.getDependency( 'skin', nodeDef.skin );
|
|
4322
|
-
|
|
4323
2156
|
return Promise.all( [
|
|
4324
2157
|
nodePending,
|
|
4325
2158
|
Promise.all( childPending ),
|
|
4326
2159
|
skeletonPending
|
|
4327
2160
|
] ).then( function ( results ) {
|
|
4328
|
-
|
|
4329
2161
|
const node = results[ 0 ];
|
|
4330
2162
|
const children = results[ 1 ];
|
|
4331
2163
|
const skeleton = results[ 2 ];
|
|
4332
|
-
|
|
4333
2164
|
if ( skeleton !== null ) {
|
|
4334
|
-
|
|
4335
|
-
// This full traverse should be fine because
|
|
4336
|
-
// child glTF nodes have not been added to this node yet.
|
|
4337
2165
|
node.traverse( function ( mesh ) {
|
|
4338
|
-
|
|
4339
2166
|
if ( ! mesh.isSkinnedMesh ) return;
|
|
4340
|
-
|
|
4341
2167
|
mesh.bind( skeleton, _identityMatrix );
|
|
4342
|
-
|
|
4343
2168
|
} );
|
|
4344
|
-
|
|
4345
2169
|
}
|
|
4346
|
-
|
|
4347
2170
|
for ( let i = 0, il = children.length; i < il; i ++ ) {
|
|
4348
|
-
|
|
4349
2171
|
node.add( children[ i ] );
|
|
4350
|
-
|
|
4351
2172
|
}
|
|
4352
|
-
|
|
4353
2173
|
return node;
|
|
4354
|
-
|
|
4355
2174
|
} );
|
|
4356
|
-
|
|
4357
2175
|
}
|
|
4358
|
-
|
|
4359
|
-
// ._loadNodeShallow() parses a single node.
|
|
4360
|
-
// skin and child nodes are created and added in .loadNode() (no '_' prefix).
|
|
4361
2176
|
_loadNodeShallow( nodeIndex ) {
|
|
4362
|
-
|
|
4363
2177
|
const json = this.json;
|
|
4364
2178
|
const extensions = this.extensions;
|
|
4365
2179
|
const parser = this;
|
|
4366
|
-
|
|
4367
|
-
// This method is called from .loadNode() and .loadSkin().
|
|
4368
|
-
// Cache a node to avoid duplication.
|
|
4369
|
-
|
|
4370
2180
|
if ( this.nodeCache[ nodeIndex ] !== undefined ) {
|
|
4371
|
-
|
|
4372
2181
|
return this.nodeCache[ nodeIndex ];
|
|
4373
|
-
|
|
4374
2182
|
}
|
|
4375
|
-
|
|
4376
2183
|
const nodeDef = json.nodes[ nodeIndex ];
|
|
4377
|
-
|
|
4378
|
-
// reserve node's name before its dependencies, so the root has the intended name.
|
|
4379
2184
|
const nodeName = nodeDef.name ? parser.createUniqueName( nodeDef.name ) : '';
|
|
4380
|
-
|
|
4381
2185
|
const pending = [];
|
|
4382
|
-
|
|
4383
2186
|
const meshPromise = parser._invokeOne( function ( ext ) {
|
|
4384
|
-
|
|
4385
2187
|
return ext.createNodeMesh && ext.createNodeMesh( nodeIndex );
|
|
4386
|
-
|
|
4387
2188
|
} );
|
|
4388
|
-
|
|
4389
2189
|
if ( meshPromise ) {
|
|
4390
|
-
|
|
4391
2190
|
pending.push( meshPromise );
|
|
4392
|
-
|
|
4393
2191
|
}
|
|
4394
|
-
|
|
4395
2192
|
if ( nodeDef.camera !== undefined ) {
|
|
4396
|
-
|
|
4397
2193
|
pending.push( parser.getDependency( 'camera', nodeDef.camera ).then( function ( camera ) {
|
|
4398
|
-
|
|
4399
2194
|
return parser._getNodeRef( parser.cameraCache, nodeDef.camera, camera );
|
|
4400
|
-
|
|
4401
2195
|
} ) );
|
|
4402
|
-
|
|
4403
2196
|
}
|
|
4404
|
-
|
|
4405
2197
|
parser._invokeAll( function ( ext ) {
|
|
4406
|
-
|
|
4407
2198
|
return ext.createNodeAttachment && ext.createNodeAttachment( nodeIndex );
|
|
4408
|
-
|
|
4409
2199
|
} ).forEach( function ( promise ) {
|
|
4410
|
-
|
|
4411
2200
|
pending.push( promise );
|
|
4412
|
-
|
|
4413
2201
|
} );
|
|
4414
|
-
|
|
4415
2202
|
this.nodeCache[ nodeIndex ] = Promise.all( pending ).then( function ( objects ) {
|
|
4416
|
-
|
|
4417
2203
|
let node;
|
|
4418
|
-
|
|
4419
|
-
// .isBone isn't in glTF spec. See ._markDefs
|
|
4420
2204
|
if ( nodeDef.isBone === true ) {
|
|
4421
|
-
|
|
4422
2205
|
node = new three.Bone();
|
|
4423
|
-
|
|
4424
2206
|
} else if ( objects.length > 1 ) {
|
|
4425
|
-
|
|
4426
2207
|
node = new three.Group();
|
|
4427
|
-
|
|
4428
2208
|
} else if ( objects.length === 1 ) {
|
|
4429
|
-
|
|
4430
2209
|
node = objects[ 0 ];
|
|
4431
|
-
|
|
4432
2210
|
} else {
|
|
4433
|
-
|
|
4434
2211
|
node = new three.Object3D();
|
|
4435
|
-
|
|
4436
2212
|
}
|
|
4437
|
-
|
|
4438
2213
|
if ( node !== objects[ 0 ] ) {
|
|
4439
|
-
|
|
4440
2214
|
for ( let i = 0, il = objects.length; i < il; i ++ ) {
|
|
4441
|
-
|
|
4442
2215
|
node.add( objects[ i ] );
|
|
4443
|
-
|
|
4444
2216
|
}
|
|
4445
|
-
|
|
4446
2217
|
}
|
|
4447
|
-
|
|
4448
2218
|
if ( nodeDef.name ) {
|
|
4449
|
-
|
|
4450
2219
|
node.userData.name = nodeDef.name;
|
|
4451
2220
|
node.name = nodeName;
|
|
4452
|
-
|
|
4453
2221
|
}
|
|
4454
|
-
|
|
4455
2222
|
assignExtrasToUserData( node, nodeDef );
|
|
4456
|
-
|
|
4457
2223
|
if ( nodeDef.extensions ) addUnknownExtensionsToUserData( extensions, node, nodeDef );
|
|
4458
|
-
|
|
4459
2224
|
if ( nodeDef.matrix !== undefined ) {
|
|
4460
|
-
|
|
4461
2225
|
const matrix = new three.Matrix4();
|
|
4462
2226
|
matrix.fromArray( nodeDef.matrix );
|
|
4463
2227
|
node.applyMatrix4( matrix );
|
|
4464
|
-
|
|
4465
2228
|
} else {
|
|
4466
|
-
|
|
4467
2229
|
if ( nodeDef.translation !== undefined ) {
|
|
4468
|
-
|
|
4469
2230
|
node.position.fromArray( nodeDef.translation );
|
|
4470
|
-
|
|
4471
2231
|
}
|
|
4472
|
-
|
|
4473
2232
|
if ( nodeDef.rotation !== undefined ) {
|
|
4474
|
-
|
|
4475
2233
|
node.quaternion.fromArray( nodeDef.rotation );
|
|
4476
|
-
|
|
4477
2234
|
}
|
|
4478
|
-
|
|
4479
2235
|
if ( nodeDef.scale !== undefined ) {
|
|
4480
|
-
|
|
4481
2236
|
node.scale.fromArray( nodeDef.scale );
|
|
4482
|
-
|
|
4483
2237
|
}
|
|
4484
|
-
|
|
4485
2238
|
}
|
|
4486
|
-
|
|
4487
2239
|
if ( ! parser.associations.has( node ) ) {
|
|
4488
|
-
|
|
4489
2240
|
parser.associations.set( node, {} );
|
|
4490
|
-
|
|
4491
2241
|
} else if ( nodeDef.mesh !== undefined && parser.meshCache.refs[ nodeDef.mesh ] > 1 ) {
|
|
4492
|
-
|
|
4493
2242
|
const mapping = parser.associations.get( node );
|
|
4494
2243
|
parser.associations.set( node, { ...mapping } );
|
|
4495
|
-
|
|
4496
2244
|
}
|
|
4497
|
-
|
|
4498
2245
|
parser.associations.get( node ).nodes = nodeIndex;
|
|
4499
|
-
|
|
4500
2246
|
return node;
|
|
4501
|
-
|
|
4502
2247
|
} );
|
|
4503
|
-
|
|
4504
2248
|
return this.nodeCache[ nodeIndex ];
|
|
4505
|
-
|
|
4506
2249
|
}
|
|
4507
|
-
|
|
4508
|
-
/**
|
|
4509
|
-
* Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes
|
|
4510
|
-
*
|
|
4511
|
-
* @private
|
|
4512
|
-
* @param {number} sceneIndex
|
|
4513
|
-
* @return {Promise<Group>}
|
|
4514
|
-
*/
|
|
4515
2250
|
loadScene( sceneIndex ) {
|
|
4516
|
-
|
|
4517
2251
|
const extensions = this.extensions;
|
|
4518
2252
|
const sceneDef = this.json.scenes[ sceneIndex ];
|
|
4519
2253
|
const parser = this;
|
|
4520
|
-
|
|
4521
|
-
// Loader returns Group, not Scene.
|
|
4522
|
-
// See: https://github.com/mrdoob/three.js/issues/18342#issuecomment-578981172
|
|
4523
2254
|
const scene = new three.Group();
|
|
4524
2255
|
if ( sceneDef.name ) scene.name = parser.createUniqueName( sceneDef.name );
|
|
4525
|
-
|
|
4526
2256
|
assignExtrasToUserData( scene, sceneDef );
|
|
4527
|
-
|
|
4528
2257
|
if ( sceneDef.extensions ) addUnknownExtensionsToUserData( extensions, scene, sceneDef );
|
|
4529
|
-
|
|
4530
2258
|
const nodeIds = sceneDef.nodes || [];
|
|
4531
|
-
|
|
4532
2259
|
const pending = [];
|
|
4533
|
-
|
|
4534
2260
|
for ( let i = 0, il = nodeIds.length; i < il; i ++ ) {
|
|
4535
|
-
|
|
4536
2261
|
pending.push( parser.getDependency( 'node', nodeIds[ i ] ) );
|
|
4537
|
-
|
|
4538
2262
|
}
|
|
4539
|
-
|
|
4540
2263
|
return Promise.all( pending ).then( function ( nodes ) {
|
|
4541
|
-
|
|
4542
2264
|
for ( let i = 0, il = nodes.length; i < il; i ++ ) {
|
|
4543
|
-
|
|
4544
2265
|
scene.add( nodes[ i ] );
|
|
4545
|
-
|
|
4546
2266
|
}
|
|
4547
|
-
|
|
4548
|
-
// Removes dangling associations, associations that reference a node that
|
|
4549
|
-
// didn't make it into the scene.
|
|
4550
2267
|
const reduceAssociations = ( node ) => {
|
|
4551
|
-
|
|
4552
2268
|
const reducedAssociations = new Map();
|
|
4553
|
-
|
|
4554
2269
|
for ( const [ key, value ] of parser.associations ) {
|
|
4555
|
-
|
|
4556
2270
|
if ( key instanceof three.Material || key instanceof three.Texture ) {
|
|
4557
|
-
|
|
4558
2271
|
reducedAssociations.set( key, value );
|
|
4559
|
-
|
|
4560
2272
|
}
|
|
4561
|
-
|
|
4562
2273
|
}
|
|
4563
|
-
|
|
4564
2274
|
node.traverse( ( node ) => {
|
|
4565
|
-
|
|
4566
2275
|
const mappings = parser.associations.get( node );
|
|
4567
|
-
|
|
4568
2276
|
if ( mappings != null ) {
|
|
4569
|
-
|
|
4570
2277
|
reducedAssociations.set( node, mappings );
|
|
4571
|
-
|
|
4572
2278
|
}
|
|
4573
|
-
|
|
4574
2279
|
} );
|
|
4575
|
-
|
|
4576
2280
|
return reducedAssociations;
|
|
4577
|
-
|
|
4578
2281
|
};
|
|
4579
|
-
|
|
4580
2282
|
parser.associations = reduceAssociations( scene );
|
|
4581
|
-
|
|
4582
2283
|
return scene;
|
|
4583
|
-
|
|
4584
2284
|
} );
|
|
4585
|
-
|
|
4586
2285
|
}
|
|
4587
|
-
|
|
4588
2286
|
_createAnimationTracks( node, inputAccessor, outputAccessor, sampler, target ) {
|
|
4589
|
-
|
|
4590
2287
|
const tracks = [];
|
|
4591
|
-
|
|
4592
2288
|
const targetName = node.name ? node.name : node.uuid;
|
|
4593
2289
|
const targetNames = [];
|
|
4594
|
-
|
|
4595
2290
|
if ( PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.weights ) {
|
|
4596
|
-
|
|
4597
2291
|
node.traverse( function ( object ) {
|
|
4598
|
-
|
|
4599
2292
|
if ( object.morphTargetInfluences ) {
|
|
4600
|
-
|
|
4601
2293
|
targetNames.push( object.name ? object.name : object.uuid );
|
|
4602
|
-
|
|
4603
2294
|
}
|
|
4604
|
-
|
|
4605
2295
|
} );
|
|
4606
|
-
|
|
4607
2296
|
} else {
|
|
4608
|
-
|
|
4609
2297
|
targetNames.push( targetName );
|
|
4610
|
-
|
|
4611
2298
|
}
|
|
4612
|
-
|
|
4613
2299
|
let TypedKeyframeTrack;
|
|
4614
|
-
|
|
4615
2300
|
switch ( PATH_PROPERTIES[ target.path ] ) {
|
|
4616
|
-
|
|
4617
2301
|
case PATH_PROPERTIES.weights:
|
|
4618
|
-
|
|
4619
2302
|
TypedKeyframeTrack = three.NumberKeyframeTrack;
|
|
4620
2303
|
break;
|
|
4621
|
-
|
|
4622
2304
|
case PATH_PROPERTIES.rotation:
|
|
4623
|
-
|
|
4624
2305
|
TypedKeyframeTrack = three.QuaternionKeyframeTrack;
|
|
4625
2306
|
break;
|
|
4626
|
-
|
|
4627
2307
|
case PATH_PROPERTIES.translation:
|
|
4628
2308
|
case PATH_PROPERTIES.scale:
|
|
4629
|
-
|
|
4630
2309
|
TypedKeyframeTrack = three.VectorKeyframeTrack;
|
|
4631
2310
|
break;
|
|
4632
|
-
|
|
4633
2311
|
default:
|
|
4634
|
-
|
|
4635
2312
|
switch ( outputAccessor.itemSize ) {
|
|
4636
|
-
|
|
4637
2313
|
case 1:
|
|
4638
2314
|
TypedKeyframeTrack = three.NumberKeyframeTrack;
|
|
4639
2315
|
break;
|
|
@@ -4642,293 +2318,133 @@
|
|
|
4642
2318
|
default:
|
|
4643
2319
|
TypedKeyframeTrack = three.VectorKeyframeTrack;
|
|
4644
2320
|
break;
|
|
4645
|
-
|
|
4646
2321
|
}
|
|
4647
|
-
|
|
4648
2322
|
break;
|
|
4649
|
-
|
|
4650
2323
|
}
|
|
4651
|
-
|
|
4652
2324
|
const interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : three.InterpolateLinear;
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
2325
|
const outputArray = this._getArrayFromAccessor( outputAccessor );
|
|
4656
|
-
|
|
4657
2326
|
for ( let j = 0, jl = targetNames.length; j < jl; j ++ ) {
|
|
4658
|
-
|
|
4659
2327
|
const track = new TypedKeyframeTrack(
|
|
4660
2328
|
targetNames[ j ] + '.' + PATH_PROPERTIES[ target.path ],
|
|
4661
2329
|
inputAccessor.array,
|
|
4662
2330
|
outputArray,
|
|
4663
2331
|
interpolation
|
|
4664
2332
|
);
|
|
4665
|
-
|
|
4666
|
-
// Override interpolation with custom factory method.
|
|
4667
2333
|
if ( sampler.interpolation === 'CUBICSPLINE' ) {
|
|
4668
|
-
|
|
4669
2334
|
this._createCubicSplineTrackInterpolant( track );
|
|
4670
|
-
|
|
4671
2335
|
}
|
|
4672
|
-
|
|
4673
2336
|
tracks.push( track );
|
|
4674
|
-
|
|
4675
2337
|
}
|
|
4676
|
-
|
|
4677
2338
|
return tracks;
|
|
4678
|
-
|
|
4679
2339
|
}
|
|
4680
|
-
|
|
4681
2340
|
_getArrayFromAccessor( accessor ) {
|
|
4682
|
-
|
|
4683
2341
|
let outputArray = accessor.array;
|
|
4684
|
-
|
|
4685
2342
|
if ( accessor.normalized ) {
|
|
4686
|
-
|
|
4687
2343
|
const scale = getNormalizedComponentScale( outputArray.constructor );
|
|
4688
2344
|
const scaled = new Float32Array( outputArray.length );
|
|
4689
|
-
|
|
4690
2345
|
for ( let j = 0, jl = outputArray.length; j < jl; j ++ ) {
|
|
4691
|
-
|
|
4692
2346
|
scaled[ j ] = outputArray[ j ] * scale;
|
|
4693
|
-
|
|
4694
2347
|
}
|
|
4695
|
-
|
|
4696
2348
|
outputArray = scaled;
|
|
4697
|
-
|
|
4698
2349
|
}
|
|
4699
|
-
|
|
4700
2350
|
return outputArray;
|
|
4701
|
-
|
|
4702
2351
|
}
|
|
4703
|
-
|
|
4704
2352
|
_createCubicSplineTrackInterpolant( track ) {
|
|
4705
|
-
|
|
4706
2353
|
track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline( result ) {
|
|
4707
|
-
|
|
4708
|
-
// A CUBICSPLINE keyframe in glTF has three output values for each input value,
|
|
4709
|
-
// representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize()
|
|
4710
|
-
// must be divided by three to get the interpolant's sampleSize argument.
|
|
4711
|
-
|
|
4712
2354
|
const interpolantType = ( this instanceof three.QuaternionKeyframeTrack ) ? GLTFCubicSplineQuaternionInterpolant : GLTFCubicSplineInterpolant;
|
|
4713
|
-
|
|
4714
2355
|
return new interpolantType( this.times, this.values, this.getValueSize() / 3, result );
|
|
4715
|
-
|
|
4716
2356
|
};
|
|
4717
|
-
|
|
4718
|
-
// Mark as CUBICSPLINE. `track.getInterpolation()` doesn't support custom interpolants.
|
|
4719
2357
|
track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true;
|
|
4720
|
-
|
|
4721
2358
|
}
|
|
4722
|
-
|
|
4723
2359
|
}
|
|
4724
|
-
|
|
4725
|
-
/**
|
|
4726
|
-
*
|
|
4727
|
-
* @private
|
|
4728
|
-
* @param {BufferGeometry} geometry
|
|
4729
|
-
* @param {GLTF.Primitive} primitiveDef
|
|
4730
|
-
* @param {GLTFParser} parser
|
|
4731
|
-
*/
|
|
4732
2360
|
function computeBounds( geometry, primitiveDef, parser ) {
|
|
4733
|
-
|
|
4734
2361
|
const attributes = primitiveDef.attributes;
|
|
4735
|
-
|
|
4736
2362
|
const box = new three.Box3();
|
|
4737
|
-
|
|
4738
2363
|
if ( attributes.POSITION !== undefined ) {
|
|
4739
|
-
|
|
4740
2364
|
const accessor = parser.json.accessors[ attributes.POSITION ];
|
|
4741
|
-
|
|
4742
2365
|
const min = accessor.min;
|
|
4743
2366
|
const max = accessor.max;
|
|
4744
|
-
|
|
4745
|
-
// glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.
|
|
4746
|
-
|
|
4747
2367
|
if ( min !== undefined && max !== undefined ) {
|
|
4748
|
-
|
|
4749
2368
|
box.set(
|
|
4750
2369
|
new three.Vector3( min[ 0 ], min[ 1 ], min[ 2 ] ),
|
|
4751
2370
|
new three.Vector3( max[ 0 ], max[ 1 ], max[ 2 ] )
|
|
4752
2371
|
);
|
|
4753
|
-
|
|
4754
2372
|
if ( accessor.normalized ) {
|
|
4755
|
-
|
|
4756
2373
|
const boxScale = getNormalizedComponentScale( WEBGL_COMPONENT_TYPES[ accessor.componentType ] );
|
|
4757
2374
|
box.min.multiplyScalar( boxScale );
|
|
4758
2375
|
box.max.multiplyScalar( boxScale );
|
|
4759
|
-
|
|
4760
2376
|
}
|
|
4761
|
-
|
|
4762
2377
|
} else {
|
|
4763
|
-
|
|
4764
2378
|
console.warn( 'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.' );
|
|
4765
|
-
|
|
4766
2379
|
return;
|
|
4767
|
-
|
|
4768
2380
|
}
|
|
4769
|
-
|
|
4770
2381
|
} else {
|
|
4771
|
-
|
|
4772
2382
|
return;
|
|
4773
|
-
|
|
4774
2383
|
}
|
|
4775
|
-
|
|
4776
2384
|
const targets = primitiveDef.targets;
|
|
4777
|
-
|
|
4778
2385
|
if ( targets !== undefined ) {
|
|
4779
|
-
|
|
4780
2386
|
const maxDisplacement = new three.Vector3();
|
|
4781
2387
|
const vector = new three.Vector3();
|
|
4782
|
-
|
|
4783
2388
|
for ( let i = 0, il = targets.length; i < il; i ++ ) {
|
|
4784
|
-
|
|
4785
2389
|
const target = targets[ i ];
|
|
4786
|
-
|
|
4787
2390
|
if ( target.POSITION !== undefined ) {
|
|
4788
|
-
|
|
4789
2391
|
const accessor = parser.json.accessors[ target.POSITION ];
|
|
4790
2392
|
const min = accessor.min;
|
|
4791
2393
|
const max = accessor.max;
|
|
4792
|
-
|
|
4793
|
-
// glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.
|
|
4794
|
-
|
|
4795
2394
|
if ( min !== undefined && max !== undefined ) {
|
|
4796
|
-
|
|
4797
|
-
// we need to get max of absolute components because target weight is [-1,1]
|
|
4798
2395
|
vector.setX( Math.max( Math.abs( min[ 0 ] ), Math.abs( max[ 0 ] ) ) );
|
|
4799
2396
|
vector.setY( Math.max( Math.abs( min[ 1 ] ), Math.abs( max[ 1 ] ) ) );
|
|
4800
2397
|
vector.setZ( Math.max( Math.abs( min[ 2 ] ), Math.abs( max[ 2 ] ) ) );
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
2398
|
if ( accessor.normalized ) {
|
|
4804
|
-
|
|
4805
2399
|
const boxScale = getNormalizedComponentScale( WEBGL_COMPONENT_TYPES[ accessor.componentType ] );
|
|
4806
2400
|
vector.multiplyScalar( boxScale );
|
|
4807
|
-
|
|
4808
2401
|
}
|
|
4809
|
-
|
|
4810
|
-
// Note: this assumes that the sum of all weights is at most 1. This isn't quite correct - it's more conservative
|
|
4811
|
-
// to assume that each target can have a max weight of 1. However, for some use cases - notably, when morph targets
|
|
4812
|
-
// are used to implement key-frame animations and as such only two are active at a time - this results in very large
|
|
4813
|
-
// boxes. So for now we make a box that's sometimes a touch too small but is hopefully mostly of reasonable size.
|
|
4814
2402
|
maxDisplacement.max( vector );
|
|
4815
|
-
|
|
4816
2403
|
} else {
|
|
4817
|
-
|
|
4818
2404
|
console.warn( 'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.' );
|
|
4819
|
-
|
|
4820
2405
|
}
|
|
4821
|
-
|
|
4822
2406
|
}
|
|
4823
|
-
|
|
4824
2407
|
}
|
|
4825
|
-
|
|
4826
|
-
// As per comment above this box isn't conservative, but has a reasonable size for a very large number of morph targets.
|
|
4827
2408
|
box.expandByVector( maxDisplacement );
|
|
4828
|
-
|
|
4829
2409
|
}
|
|
4830
|
-
|
|
4831
2410
|
geometry.boundingBox = box;
|
|
4832
|
-
|
|
4833
2411
|
const sphere = new three.Sphere();
|
|
4834
|
-
|
|
4835
2412
|
box.getCenter( sphere.center );
|
|
4836
2413
|
sphere.radius = box.min.distanceTo( box.max ) / 2;
|
|
4837
|
-
|
|
4838
2414
|
geometry.boundingSphere = sphere;
|
|
4839
|
-
|
|
4840
2415
|
}
|
|
4841
|
-
|
|
4842
|
-
/**
|
|
4843
|
-
*
|
|
4844
|
-
* @private
|
|
4845
|
-
* @param {BufferGeometry} geometry
|
|
4846
|
-
* @param {GLTF.Primitive} primitiveDef
|
|
4847
|
-
* @param {GLTFParser} parser
|
|
4848
|
-
* @return {Promise<BufferGeometry>}
|
|
4849
|
-
*/
|
|
4850
2416
|
function addPrimitiveAttributes( geometry, primitiveDef, parser ) {
|
|
4851
|
-
|
|
4852
2417
|
const attributes = primitiveDef.attributes;
|
|
4853
|
-
|
|
4854
2418
|
const pending = [];
|
|
4855
|
-
|
|
4856
2419
|
function assignAttributeAccessor( accessorIndex, attributeName ) {
|
|
4857
|
-
|
|
4858
2420
|
return parser.getDependency( 'accessor', accessorIndex )
|
|
4859
2421
|
.then( function ( accessor ) {
|
|
4860
|
-
|
|
4861
2422
|
geometry.setAttribute( attributeName, accessor );
|
|
4862
|
-
|
|
4863
2423
|
} );
|
|
4864
|
-
|
|
4865
2424
|
}
|
|
4866
|
-
|
|
4867
2425
|
for ( const gltfAttributeName in attributes ) {
|
|
4868
|
-
|
|
4869
2426
|
const threeAttributeName = ATTRIBUTES[ gltfAttributeName ] || gltfAttributeName.toLowerCase();
|
|
4870
|
-
|
|
4871
|
-
// Skip attributes already provided by e.g. Draco extension.
|
|
4872
2427
|
if ( threeAttributeName in geometry.attributes ) continue;
|
|
4873
|
-
|
|
4874
2428
|
pending.push( assignAttributeAccessor( attributes[ gltfAttributeName ], threeAttributeName ) );
|
|
4875
|
-
|
|
4876
2429
|
}
|
|
4877
|
-
|
|
4878
2430
|
if ( primitiveDef.indices !== undefined && ! geometry.index ) {
|
|
4879
|
-
|
|
4880
2431
|
const accessor = parser.getDependency( 'accessor', primitiveDef.indices ).then( function ( accessor ) {
|
|
4881
|
-
|
|
4882
2432
|
geometry.setIndex( accessor );
|
|
4883
|
-
|
|
4884
2433
|
} );
|
|
4885
|
-
|
|
4886
2434
|
pending.push( accessor );
|
|
4887
|
-
|
|
4888
2435
|
}
|
|
4889
|
-
|
|
4890
2436
|
if ( three.ColorManagement.workingColorSpace !== three.LinearSRGBColorSpace && 'COLOR_0' in attributes ) {
|
|
4891
|
-
|
|
4892
2437
|
console.warn( `THREE.GLTFLoader: Converting vertex colors from "srgb-linear" to "${three.ColorManagement.workingColorSpace}" not supported.` );
|
|
4893
|
-
|
|
4894
2438
|
}
|
|
4895
|
-
|
|
4896
2439
|
assignExtrasToUserData( geometry, primitiveDef );
|
|
4897
|
-
|
|
4898
2440
|
computeBounds( geometry, primitiveDef, parser );
|
|
4899
|
-
|
|
4900
2441
|
return Promise.all( pending ).then( function () {
|
|
4901
|
-
|
|
4902
2442
|
return primitiveDef.targets !== undefined
|
|
4903
2443
|
? addMorphTargets( geometry, primitiveDef.targets, parser )
|
|
4904
2444
|
: geometry;
|
|
4905
|
-
|
|
4906
2445
|
} );
|
|
4907
|
-
|
|
4908
2446
|
}
|
|
4909
2447
|
|
|
4910
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
4911
|
-
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
|
|
4912
|
-
// All rights reserved.
|
|
4913
|
-
//
|
|
4914
|
-
// This software and its documentation and related materials are owned by
|
|
4915
|
-
// the Alliance. The software may only be incorporated into application
|
|
4916
|
-
// programs owned by members of the Alliance, subject to a signed
|
|
4917
|
-
// Membership Agreement and Supplemental Software License Agreement with the
|
|
4918
|
-
// Alliance. The structure and organization of this software are the valuable
|
|
4919
|
-
// trade secrets of the Alliance and its suppliers. The software is also
|
|
4920
|
-
// protected by copyright law and international treaty provisions. Application
|
|
4921
|
-
// programs incorporating this software must include the following statement
|
|
4922
|
-
// with their copyright notices:
|
|
4923
|
-
//
|
|
4924
|
-
// This application incorporates Open Design Alliance software pursuant to a
|
|
4925
|
-
// license agreement with Open Design Alliance.
|
|
4926
|
-
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
|
|
4927
|
-
// All rights reserved.
|
|
4928
|
-
//
|
|
4929
|
-
// By use of this software, its documentation or related materials, you
|
|
4930
|
-
// acknowledge and accept the above terms.
|
|
4931
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
4932
2448
|
class GLTFCloudLoader extends viewerThree.Loader {
|
|
4933
2449
|
constructor(viewer) {
|
|
4934
2450
|
super();
|