three-stdlib 2.21.9 → 2.21.11

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.
@@ -1,4 +1,5 @@
1
- import { Loader, LoaderUtils, FileLoader, Color, SpotLight, PointLight, DirectionalLight, MeshBasicMaterial, sRGBEncoding, MeshPhysicalMaterial, Vector2, TangentSpaceNormalMap, Quaternion, TextureLoader, ImageBitmapLoader, InterleavedBuffer, InterleavedBufferAttribute, BufferAttribute, LinearFilter, LinearMipmapLinearFilter, RepeatWrapping, PointsMaterial, Material, LineBasicMaterial, MeshStandardMaterial, DoubleSide, PropertyBinding, BufferGeometry, SkinnedMesh, Mesh, LineSegments, Line, LineLoop, Points, Group, PerspectiveCamera, MathUtils, OrthographicCamera, InterpolateLinear, AnimationClip, Bone, Object3D, Matrix4, Skeleton, TriangleFanDrawMode, NearestFilter, NearestMipmapNearestFilter, LinearMipmapNearestFilter, NearestMipmapLinearFilter, ClampToEdgeWrapping, MirroredRepeatWrapping, InterpolateDiscrete, FrontSide, Texture, TriangleStripDrawMode, VectorKeyframeTrack, QuaternionKeyframeTrack, NumberKeyframeTrack, Box3, Vector3, Sphere, Interpolant } from 'three';
1
+ import { Loader, LoaderUtils, FileLoader, Color, SpotLight, PointLight, DirectionalLight, MeshBasicMaterial, sRGBEncoding, MeshPhysicalMaterial, Vector2, Matrix4, Vector3, Quaternion, InstancedMesh, Object3D, REVISION, TextureLoader, ImageBitmapLoader, BufferAttribute, InterleavedBuffer, InterleavedBufferAttribute, LinearFilter, LinearMipmapLinearFilter, RepeatWrapping, PointsMaterial, Material, LineBasicMaterial, MeshStandardMaterial, DoubleSide, PropertyBinding, BufferGeometry, SkinnedMesh, Mesh, TriangleStripDrawMode, TriangleFanDrawMode, LineSegments, Line, LineLoop, Points, Group, PerspectiveCamera, MathUtils, OrthographicCamera, Skeleton, InterpolateLinear, AnimationClip, Bone, NearestFilter, NearestMipmapNearestFilter, LinearMipmapNearestFilter, NearestMipmapLinearFilter, ClampToEdgeWrapping, MirroredRepeatWrapping, InterpolateDiscrete, FrontSide, Texture, VectorKeyframeTrack, QuaternionKeyframeTrack, NumberKeyframeTrack, Box3, Sphere, Interpolant } from 'three';
2
+ import { toTrianglesDrawMode } from '../utils/BufferGeometryUtils.js';
2
3
 
3
4
  class GLTFLoader extends Loader {
4
5
  constructor(manager) {
@@ -16,6 +17,9 @@ class GLTFLoader extends Loader {
16
17
  this.register(function (parser) {
17
18
  return new GLTFTextureWebPExtension(parser);
18
19
  });
20
+ this.register(function (parser) {
21
+ return new GLTFTextureAVIFExtension(parser);
22
+ });
19
23
  this.register(function (parser) {
20
24
  return new GLTFMaterialsSheenExtension(parser);
21
25
  });
@@ -43,6 +47,9 @@ class GLTFLoader extends Loader {
43
47
  this.register(function (parser) {
44
48
  return new GLTFMeshoptCompression(parser);
45
49
  });
50
+ this.register(function (parser) {
51
+ return new GLTFMeshGpuInstancing(parser);
52
+ });
46
53
  }
47
54
 
48
55
  load(url, onLoad, onProgress, onError) {
@@ -126,14 +133,15 @@ class GLTFLoader extends Loader {
126
133
  }
127
134
 
128
135
  parse(data, path, onLoad, onError) {
129
- let content;
136
+ let json;
130
137
  const extensions = {};
131
138
  const plugins = {};
139
+ const textDecoder = new TextDecoder();
132
140
 
133
141
  if (typeof data === 'string') {
134
- content = data;
135
- } else {
136
- const magic = LoaderUtils.decodeText(new Uint8Array(data, 0, 4));
142
+ json = JSON.parse(data);
143
+ } else if (data instanceof ArrayBuffer) {
144
+ const magic = textDecoder.decode(new Uint8Array(data, 0, 4));
137
145
 
138
146
  if (magic === BINARY_EXTENSION_HEADER_MAGIC) {
139
147
  try {
@@ -143,14 +151,14 @@ class GLTFLoader extends Loader {
143
151
  return;
144
152
  }
145
153
 
146
- content = extensions[EXTENSIONS.KHR_BINARY_GLTF].content;
154
+ json = JSON.parse(extensions[EXTENSIONS.KHR_BINARY_GLTF].content);
147
155
  } else {
148
- content = LoaderUtils.decodeText(new Uint8Array(data));
156
+ json = JSON.parse(textDecoder.decode(data));
149
157
  }
158
+ } else {
159
+ json = data;
150
160
  }
151
161
 
152
- const json = JSON.parse(content);
153
-
154
162
  if (json.asset === undefined || json.asset.version[0] < 2) {
155
163
  if (onError) onError(new Error('THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported.'));
156
164
  return;
@@ -186,10 +194,6 @@ class GLTFLoader extends Loader {
186
194
  extensions[extensionName] = new GLTFMaterialsUnlitExtension();
187
195
  break;
188
196
 
189
- case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
190
- extensions[extensionName] = new GLTFMaterialsPbrSpecularGlossinessExtension();
191
- break;
192
-
193
197
  case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
194
198
  extensions[extensionName] = new GLTFDracoMeshCompressionExtension(json, this.dracoLoader);
195
199
  break;
@@ -257,7 +261,6 @@ const EXTENSIONS = {
257
261
  KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',
258
262
  KHR_MATERIALS_CLEARCOAT: 'KHR_materials_clearcoat',
259
263
  KHR_MATERIALS_IOR: 'KHR_materials_ior',
260
- KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
261
264
  KHR_MATERIALS_SHEEN: 'KHR_materials_sheen',
262
265
  KHR_MATERIALS_SPECULAR: 'KHR_materials_specular',
263
266
  KHR_MATERIALS_TRANSMISSION: 'KHR_materials_transmission',
@@ -269,7 +272,9 @@ const EXTENSIONS = {
269
272
  KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization',
270
273
  KHR_MATERIALS_EMISSIVE_STRENGTH: 'KHR_materials_emissive_strength',
271
274
  EXT_TEXTURE_WEBP: 'EXT_texture_webp',
272
- EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression'
275
+ EXT_TEXTURE_AVIF: 'EXT_texture_avif',
276
+ EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression',
277
+ EXT_MESH_GPU_INSTANCING: 'EXT_mesh_gpu_instancing'
273
278
  };
274
279
  /**
275
280
  * Punctual Lights Extension
@@ -348,6 +353,7 @@ class GLTFLightsExtension {
348
353
 
349
354
  lightNode.position.set(0, 0, 0);
350
355
  lightNode.decay = 2;
356
+ assignExtrasToUserData(lightNode, lightDef);
351
357
  if (lightDef.intensity !== undefined) lightNode.intensity = lightDef.intensity;
352
358
  lightNode.name = parser.createUniqueName(lightDef.name || 'light_' + lightIndex);
353
359
  dependency = Promise.resolve(lightNode);
@@ -355,6 +361,11 @@ class GLTFLightsExtension {
355
361
  return dependency;
356
362
  }
357
363
 
364
+ getDependency(type, index) {
365
+ if (type !== 'light') return;
366
+ return this._loadLight(index);
367
+ }
368
+
358
369
  createNodeAttachment(nodeIndex) {
359
370
  const self = this;
360
371
  const parser = this.parser;
@@ -883,6 +894,68 @@ class GLTFTextureWebPExtension {
883
894
  return this.isSupported;
884
895
  }
885
896
 
897
+ }
898
+ /**
899
+ * AVIF Texture Extension
900
+ *
901
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_texture_avif
902
+ */
903
+
904
+
905
+ class GLTFTextureAVIFExtension {
906
+ constructor(parser) {
907
+ this.parser = parser;
908
+ this.name = EXTENSIONS.EXT_TEXTURE_AVIF;
909
+ this.isSupported = null;
910
+ }
911
+
912
+ loadTexture(textureIndex) {
913
+ const name = this.name;
914
+ const parser = this.parser;
915
+ const json = parser.json;
916
+ const textureDef = json.textures[textureIndex];
917
+
918
+ if (!textureDef.extensions || !textureDef.extensions[name]) {
919
+ return null;
920
+ }
921
+
922
+ const extension = textureDef.extensions[name];
923
+ const source = json.images[extension.source];
924
+ let loader = parser.textureLoader;
925
+
926
+ if (source.uri) {
927
+ const handler = parser.options.manager.getHandler(source.uri);
928
+ if (handler !== null) loader = handler;
929
+ }
930
+
931
+ return this.detectSupport().then(function (isSupported) {
932
+ if (isSupported) return parser.loadTextureImage(textureIndex, extension.source, loader);
933
+
934
+ if (json.extensionsRequired && json.extensionsRequired.indexOf(name) >= 0) {
935
+ throw new Error('THREE.GLTFLoader: AVIF required by asset but unsupported.');
936
+ } // Fall back to PNG or JPEG.
937
+
938
+
939
+ return parser.loadTexture(textureIndex);
940
+ });
941
+ }
942
+
943
+ detectSupport() {
944
+ if (!this.isSupported) {
945
+ this.isSupported = new Promise(function (resolve) {
946
+ const image = new Image(); // Lossy test image.
947
+
948
+ image.src = 'data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAABcAAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAEAAAABAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQAMAAAAABNjb2xybmNseAACAAIABoAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAAB9tZGF0EgAKCBgABogQEDQgMgkQAAAAB8dSLfI=';
949
+
950
+ image.onload = image.onerror = function () {
951
+ resolve(image.height === 1);
952
+ };
953
+ });
954
+ }
955
+
956
+ return this.isSupported;
957
+ }
958
+
886
959
  }
887
960
  /**
888
961
  * meshopt BufferView Compression Extension
@@ -940,6 +1013,109 @@ class GLTFMeshoptCompression {
940
1013
  }
941
1014
  }
942
1015
 
1016
+ }
1017
+ /**
1018
+ * GPU Instancing Extension
1019
+ *
1020
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_mesh_gpu_instancing
1021
+ *
1022
+ */
1023
+
1024
+
1025
+ class GLTFMeshGpuInstancing {
1026
+ constructor(parser) {
1027
+ this.name = EXTENSIONS.EXT_MESH_GPU_INSTANCING;
1028
+ this.parser = parser;
1029
+ }
1030
+
1031
+ createNodeMesh(nodeIndex) {
1032
+ const json = this.parser.json;
1033
+ const nodeDef = json.nodes[nodeIndex];
1034
+
1035
+ if (!nodeDef.extensions || !nodeDef.extensions[this.name] || nodeDef.mesh === undefined) {
1036
+ return null;
1037
+ }
1038
+
1039
+ const meshDef = json.meshes[nodeDef.mesh]; // No Points or Lines + Instancing support yet
1040
+
1041
+ for (const primitive of meshDef.primitives) {
1042
+ if (primitive.mode !== WEBGL_CONSTANTS.TRIANGLES && primitive.mode !== WEBGL_CONSTANTS.TRIANGLE_STRIP && primitive.mode !== WEBGL_CONSTANTS.TRIANGLE_FAN && primitive.mode !== undefined) {
1043
+ return null;
1044
+ }
1045
+ }
1046
+
1047
+ const extensionDef = nodeDef.extensions[this.name];
1048
+ const attributesDef = extensionDef.attributes; // @TODO: Can we support InstancedMesh + SkinnedMesh?
1049
+
1050
+ const pending = [];
1051
+ const attributes = {};
1052
+
1053
+ for (const key in attributesDef) {
1054
+ pending.push(this.parser.getDependency('accessor', attributesDef[key]).then(accessor => {
1055
+ attributes[key] = accessor;
1056
+ return attributes[key];
1057
+ }));
1058
+ }
1059
+
1060
+ if (pending.length < 1) {
1061
+ return null;
1062
+ }
1063
+
1064
+ pending.push(this.parser.createNodeMesh(nodeIndex));
1065
+ return Promise.all(pending).then(results => {
1066
+ const nodeObject = results.pop();
1067
+ const meshes = nodeObject.isGroup ? nodeObject.children : [nodeObject];
1068
+ const count = results[0].count; // All attribute counts should be same
1069
+
1070
+ const instancedMeshes = [];
1071
+
1072
+ for (const mesh of meshes) {
1073
+ // Temporal variables
1074
+ const m = new Matrix4();
1075
+ const p = new Vector3();
1076
+ const q = new Quaternion();
1077
+ const s = new Vector3(1, 1, 1);
1078
+ const instancedMesh = new InstancedMesh(mesh.geometry, mesh.material, count);
1079
+
1080
+ for (let i = 0; i < count; i++) {
1081
+ if (attributes.TRANSLATION) {
1082
+ p.fromBufferAttribute(attributes.TRANSLATION, i);
1083
+ }
1084
+
1085
+ if (attributes.ROTATION) {
1086
+ q.fromBufferAttribute(attributes.ROTATION, i);
1087
+ }
1088
+
1089
+ if (attributes.SCALE) {
1090
+ s.fromBufferAttribute(attributes.SCALE, i);
1091
+ }
1092
+
1093
+ instancedMesh.setMatrixAt(i, m.compose(p, q, s));
1094
+ } // Add instance attributes to the geometry, excluding TRS.
1095
+
1096
+
1097
+ for (const attributeName in attributes) {
1098
+ if (attributeName !== 'TRANSLATION' && attributeName !== 'ROTATION' && attributeName !== 'SCALE') {
1099
+ mesh.geometry.setAttribute(attributeName, attributes[attributeName]);
1100
+ }
1101
+ } // Just in case
1102
+
1103
+
1104
+ Object3D.prototype.copy.call(instancedMesh, mesh);
1105
+ this.parser.assignFinalMaterial(instancedMesh);
1106
+ instancedMeshes.push(instancedMesh);
1107
+ }
1108
+
1109
+ if (nodeObject.isGroup) {
1110
+ nodeObject.clear();
1111
+ nodeObject.add(...instancedMeshes);
1112
+ return nodeObject;
1113
+ }
1114
+
1115
+ return instancedMeshes[0];
1116
+ });
1117
+ }
1118
+
943
1119
  }
944
1120
  /* BINARY EXTENSION */
945
1121
 
@@ -957,8 +1133,9 @@ class GLTFBinaryExtension {
957
1133
  this.content = null;
958
1134
  this.body = null;
959
1135
  const headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH);
1136
+ const textDecoder = new TextDecoder();
960
1137
  this.header = {
961
- magic: LoaderUtils.decodeText(new Uint8Array(data.slice(0, 4))),
1138
+ magic: textDecoder.decode(new Uint8Array(data.slice(0, 4))),
962
1139
  version: headerView.getUint32(4, true),
963
1140
  length: headerView.getUint32(8, true)
964
1141
  };
@@ -981,7 +1158,7 @@ class GLTFBinaryExtension {
981
1158
 
982
1159
  if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) {
983
1160
  const contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength);
984
- this.content = LoaderUtils.decodeText(contentArray);
1161
+ this.content = textDecoder.decode(contentArray);
985
1162
  } else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) {
986
1163
  const byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
987
1164
  this.body = data.slice(byteOffset, byteOffset + chunkLength);
@@ -1070,17 +1247,17 @@ class GLTFTextureTransformExtension {
1070
1247
  }
1071
1248
 
1072
1249
  extendTexture(texture, transform) {
1073
- if (transform.texCoord !== undefined) {
1074
- console.warn('THREE.GLTFLoader: Custom UV sets in "' + this.name + '" extension not yet supported.');
1075
- }
1076
-
1077
- if (transform.offset === undefined && transform.rotation === undefined && transform.scale === undefined) {
1250
+ if ((transform.texCoord === undefined || transform.texCoord === texture.channel) && transform.offset === undefined && transform.rotation === undefined && transform.scale === undefined) {
1078
1251
  // See https://github.com/mrdoob/three.js/issues/21819.
1079
1252
  return texture;
1080
1253
  }
1081
1254
 
1082
1255
  texture = texture.clone();
1083
1256
 
1257
+ if (transform.texCoord !== undefined) {
1258
+ texture.channel = transform.texCoord;
1259
+ }
1260
+
1084
1261
  if (transform.offset !== undefined) {
1085
1262
  texture.offset.fromArray(transform.offset);
1086
1263
  }
@@ -1097,198 +1274,6 @@ class GLTFTextureTransformExtension {
1097
1274
  return texture;
1098
1275
  }
1099
1276
 
1100
- }
1101
- /**
1102
- * Specular-Glossiness Extension
1103
- *
1104
- * Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Archived/KHR_materials_pbrSpecularGlossiness
1105
- */
1106
-
1107
- /**
1108
- * A sub class of StandardMaterial with some of the functionality
1109
- * changed via the `onBeforeCompile` callback
1110
- * @pailhead
1111
- */
1112
-
1113
-
1114
- class GLTFMeshStandardSGMaterial extends MeshStandardMaterial {
1115
- constructor(params) {
1116
- super();
1117
- this.isGLTFSpecularGlossinessMaterial = true; //various chunks that need replacing
1118
-
1119
- const specularMapParsFragmentChunk = ['#ifdef USE_SPECULARMAP', ' uniform sampler2D specularMap;', '#endif'].join('\n');
1120
- const glossinessMapParsFragmentChunk = ['#ifdef USE_GLOSSINESSMAP', ' uniform sampler2D glossinessMap;', '#endif'].join('\n');
1121
- const specularMapFragmentChunk = ['vec3 specularFactor = specular;', '#ifdef USE_SPECULARMAP', ' vec4 texelSpecular = texture2D( specularMap, vUv );', ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture', ' specularFactor *= texelSpecular.rgb;', '#endif'].join('\n');
1122
- const glossinessMapFragmentChunk = ['float glossinessFactor = glossiness;', '#ifdef USE_GLOSSINESSMAP', ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );', ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture', ' glossinessFactor *= texelGlossiness.a;', '#endif'].join('\n');
1123
- const lightPhysicalFragmentChunk = ['PhysicalMaterial material;', 'material.diffuseColor = diffuseColor.rgb * ( 1. - max( specularFactor.r, max( specularFactor.g, specularFactor.b ) ) );', 'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );', 'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );', 'material.roughness = max( 1.0 - glossinessFactor, 0.0525 ); // 0.0525 corresponds to the base mip of a 256 cubemap.', 'material.roughness += geometryRoughness;', 'material.roughness = min( material.roughness, 1.0 );', 'material.specularColor = specularFactor;'].join('\n');
1124
- const uniforms = {
1125
- specular: {
1126
- value: new Color().setHex(0xffffff)
1127
- },
1128
- glossiness: {
1129
- value: 1
1130
- },
1131
- specularMap: {
1132
- value: null
1133
- },
1134
- glossinessMap: {
1135
- value: null
1136
- }
1137
- };
1138
- this._extraUniforms = uniforms;
1139
-
1140
- this.onBeforeCompile = function (shader) {
1141
- for (const uniformName in uniforms) {
1142
- shader.uniforms[uniformName] = uniforms[uniformName];
1143
- }
1144
-
1145
- shader.fragmentShader = shader.fragmentShader.replace('uniform float roughness;', 'uniform vec3 specular;').replace('uniform float metalness;', 'uniform float glossiness;').replace('#include <roughnessmap_pars_fragment>', specularMapParsFragmentChunk).replace('#include <metalnessmap_pars_fragment>', glossinessMapParsFragmentChunk).replace('#include <roughnessmap_fragment>', specularMapFragmentChunk).replace('#include <metalnessmap_fragment>', glossinessMapFragmentChunk).replace('#include <lights_physical_fragment>', lightPhysicalFragmentChunk);
1146
- };
1147
-
1148
- Object.defineProperties(this, {
1149
- specular: {
1150
- get: function () {
1151
- return uniforms.specular.value;
1152
- },
1153
- set: function (v) {
1154
- uniforms.specular.value = v;
1155
- }
1156
- },
1157
- specularMap: {
1158
- get: function () {
1159
- return uniforms.specularMap.value;
1160
- },
1161
- set: function (v) {
1162
- uniforms.specularMap.value = v;
1163
-
1164
- if (v) {
1165
- this.defines.USE_SPECULARMAP = ''; // USE_UV is set by the renderer for specular maps
1166
- } else {
1167
- delete this.defines.USE_SPECULARMAP;
1168
- }
1169
- }
1170
- },
1171
- glossiness: {
1172
- get: function () {
1173
- return uniforms.glossiness.value;
1174
- },
1175
- set: function (v) {
1176
- uniforms.glossiness.value = v;
1177
- }
1178
- },
1179
- glossinessMap: {
1180
- get: function () {
1181
- return uniforms.glossinessMap.value;
1182
- },
1183
- set: function (v) {
1184
- uniforms.glossinessMap.value = v;
1185
-
1186
- if (v) {
1187
- this.defines.USE_GLOSSINESSMAP = '';
1188
- this.defines.USE_UV = '';
1189
- } else {
1190
- delete this.defines.USE_GLOSSINESSMAP;
1191
- delete this.defines.USE_UV;
1192
- }
1193
- }
1194
- }
1195
- });
1196
- delete this.metalness;
1197
- delete this.roughness;
1198
- delete this.metalnessMap;
1199
- delete this.roughnessMap;
1200
- this.setValues(params);
1201
- }
1202
-
1203
- copy(source) {
1204
- super.copy(source);
1205
- this.specularMap = source.specularMap;
1206
- this.specular.copy(source.specular);
1207
- this.glossinessMap = source.glossinessMap;
1208
- this.glossiness = source.glossiness;
1209
- delete this.metalness;
1210
- delete this.roughness;
1211
- delete this.metalnessMap;
1212
- delete this.roughnessMap;
1213
- return this;
1214
- }
1215
-
1216
- }
1217
-
1218
- class GLTFMaterialsPbrSpecularGlossinessExtension {
1219
- constructor() {
1220
- this.name = EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS;
1221
- this.specularGlossinessParams = ['color', 'map', 'lightMap', 'lightMapIntensity', 'aoMap', 'aoMapIntensity', 'emissive', 'emissiveIntensity', 'emissiveMap', 'bumpMap', 'bumpScale', 'normalMap', 'normalMapType', 'displacementMap', 'displacementScale', 'displacementBias', 'specularMap', 'specular', 'glossinessMap', 'glossiness', 'alphaMap', 'envMap', 'envMapIntensity', 'refractionRatio'];
1222
- }
1223
-
1224
- getMaterialType() {
1225
- return GLTFMeshStandardSGMaterial;
1226
- }
1227
-
1228
- extendParams(materialParams, materialDef, parser) {
1229
- const pbrSpecularGlossiness = materialDef.extensions[this.name];
1230
- materialParams.color = new Color(1.0, 1.0, 1.0);
1231
- materialParams.opacity = 1.0;
1232
- const pending = [];
1233
-
1234
- if (Array.isArray(pbrSpecularGlossiness.diffuseFactor)) {
1235
- const array = pbrSpecularGlossiness.diffuseFactor;
1236
- materialParams.color.fromArray(array);
1237
- materialParams.opacity = array[3];
1238
- }
1239
-
1240
- if (pbrSpecularGlossiness.diffuseTexture !== undefined) {
1241
- pending.push(parser.assignTexture(materialParams, 'map', pbrSpecularGlossiness.diffuseTexture, sRGBEncoding));
1242
- }
1243
-
1244
- materialParams.emissive = new Color(0.0, 0.0, 0.0);
1245
- materialParams.glossiness = pbrSpecularGlossiness.glossinessFactor !== undefined ? pbrSpecularGlossiness.glossinessFactor : 1.0;
1246
- materialParams.specular = new Color(1.0, 1.0, 1.0);
1247
-
1248
- if (Array.isArray(pbrSpecularGlossiness.specularFactor)) {
1249
- materialParams.specular.fromArray(pbrSpecularGlossiness.specularFactor);
1250
- }
1251
-
1252
- if (pbrSpecularGlossiness.specularGlossinessTexture !== undefined) {
1253
- const specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture;
1254
- pending.push(parser.assignTexture(materialParams, 'glossinessMap', specGlossMapDef));
1255
- pending.push(parser.assignTexture(materialParams, 'specularMap', specGlossMapDef, sRGBEncoding));
1256
- }
1257
-
1258
- return Promise.all(pending);
1259
- }
1260
-
1261
- createMaterial(materialParams) {
1262
- const material = new GLTFMeshStandardSGMaterial(materialParams);
1263
- material.fog = true;
1264
- material.color = materialParams.color;
1265
- material.map = materialParams.map === undefined ? null : materialParams.map;
1266
- material.lightMap = null;
1267
- material.lightMapIntensity = 1.0;
1268
- material.aoMap = materialParams.aoMap === undefined ? null : materialParams.aoMap;
1269
- material.aoMapIntensity = 1.0;
1270
- material.emissive = materialParams.emissive;
1271
- material.emissiveIntensity = materialParams.emissiveIntensity === undefined ? 1.0 : materialParams.emissiveIntensity;
1272
- material.emissiveMap = materialParams.emissiveMap === undefined ? null : materialParams.emissiveMap;
1273
- material.bumpMap = materialParams.bumpMap === undefined ? null : materialParams.bumpMap;
1274
- material.bumpScale = 1;
1275
- material.normalMap = materialParams.normalMap === undefined ? null : materialParams.normalMap;
1276
- material.normalMapType = TangentSpaceNormalMap;
1277
- if (materialParams.normalScale) material.normalScale = materialParams.normalScale;
1278
- material.displacementMap = null;
1279
- material.displacementScale = 1;
1280
- material.displacementBias = 0;
1281
- material.specularMap = materialParams.specularMap === undefined ? null : materialParams.specularMap;
1282
- material.specular = materialParams.specular;
1283
- material.glossinessMap = materialParams.glossinessMap === undefined ? null : materialParams.glossinessMap;
1284
- material.glossiness = materialParams.glossiness;
1285
- material.alphaMap = null;
1286
- material.envMap = materialParams.envMap === undefined ? null : materialParams.envMap;
1287
- material.envMapIntensity = 1.0;
1288
- material.refractionRatio = 0.98;
1289
- return material;
1290
- }
1291
-
1292
1277
  }
1293
1278
  /**
1294
1279
  * Mesh Quantization Extension
@@ -1443,8 +1428,18 @@ const ATTRIBUTES = {
1443
1428
  POSITION: 'position',
1444
1429
  NORMAL: 'normal',
1445
1430
  TANGENT: 'tangent',
1446
- TEXCOORD_0: 'uv',
1447
- TEXCOORD_1: 'uv2',
1431
+ // uv => uv1, 4 uv channels
1432
+ // https://github.com/mrdoob/three.js/pull/25943
1433
+ // https://github.com/mrdoob/three.js/pull/25788
1434
+ ...(REVISION.replace(/\D+/g, '') >= 152 ? {
1435
+ TEXCOORD_0: 'uv',
1436
+ TEXCOORD_1: 'uv1',
1437
+ TEXCOORD_2: 'uv2',
1438
+ TEXCOORD_3: 'uv3'
1439
+ } : {
1440
+ TEXCOORD_0: 'uv',
1441
+ TEXCOORD_1: 'uv2'
1442
+ }),
1448
1443
  COLOR_0: 'color',
1449
1444
  WEIGHTS_0: 'skinWeight',
1450
1445
  JOINTS_0: 'skinIndex'
@@ -1650,13 +1645,13 @@ function getImageURIMimeType(uri) {
1650
1645
  if (uri.search(/\.webp($|\?)/i) > 0 || uri.search(/^data\:image\/webp/) === 0) return 'image/webp';
1651
1646
  return 'image/png';
1652
1647
  }
1648
+
1649
+ const _identityMatrix = new Matrix4();
1653
1650
  /* GLTF PARSER */
1654
1651
 
1655
1652
 
1656
1653
  class GLTFParser {
1657
1654
  constructor(json = {}, options = {}) {
1658
- var _navigator$userAgent, _navigator$userAgent2;
1659
-
1660
1655
  this.json = json;
1661
1656
  this.extensions = {};
1662
1657
  this.plugins = {};
@@ -1666,7 +1661,9 @@ class GLTFParser {
1666
1661
 
1667
1662
  this.associations = new Map(); // BufferGeometry caching
1668
1663
 
1669
- this.primitiveCache = {}; // Object3D instance caches
1664
+ this.primitiveCache = {}; // Node cache
1665
+
1666
+ this.nodeCache = {}; // Object3D instance caches
1670
1667
 
1671
1668
  this.meshCache = {
1672
1669
  refs: {},
@@ -1686,9 +1683,15 @@ class GLTFParser {
1686
1683
  this.nodeNamesUsed = {}; // Use an ImageBitmapLoader if imageBitmaps are supported. Moves much of the
1687
1684
  // expensive work of uploading a texture to the GPU off the main thread.
1688
1685
 
1689
- const isSafari = typeof navigator !== 'undefined' && /^((?!chrome|android).)*safari/i.test(navigator.userAgent) === true;
1690
- const isFirefox = typeof navigator !== 'undefined' && ((_navigator$userAgent = navigator.userAgent) === null || _navigator$userAgent === void 0 ? void 0 : _navigator$userAgent.indexOf('Firefox')) > -1;
1691
- const firefoxVersion = typeof navigator !== 'undefined' && isFirefox ? (_navigator$userAgent2 = navigator.userAgent) === null || _navigator$userAgent2 === void 0 ? void 0 : _navigator$userAgent2.match(/Firefox\/([0-9]+)\./)[1] : -1;
1686
+ let isSafari = false;
1687
+ let isFirefox = false;
1688
+ let firefoxVersion = -1;
1689
+
1690
+ if (typeof navigator !== 'undefined') {
1691
+ isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent) === true;
1692
+ isFirefox = navigator.userAgent.indexOf('Firefox') > -1;
1693
+ firefoxVersion = isFirefox ? navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1] : -1;
1694
+ }
1692
1695
 
1693
1696
  if (typeof createImageBitmap === 'undefined' || isSafari || isFirefox && firefoxVersion < 98) {
1694
1697
  this.textureLoader = new TextureLoader(this.options.manager);
@@ -1719,7 +1722,8 @@ class GLTFParser {
1719
1722
  const json = this.json;
1720
1723
  const extensions = this.extensions; // Clear the loader cache
1721
1724
 
1722
- this.cache.removeAll(); // Mark the special nodes/meshes in json for efficient parse
1725
+ this.cache.removeAll();
1726
+ this.nodeCache = {}; // Mark the special nodes/meshes in json for efficient parse
1723
1727
 
1724
1728
  this._invokeAll(function (ext) {
1725
1729
  return ext._markDefs && ext._markDefs();
@@ -1876,7 +1880,9 @@ class GLTFParser {
1876
1880
  break;
1877
1881
 
1878
1882
  case 'node':
1879
- dependency = this.loadNode(index);
1883
+ dependency = this._invokeOne(function (ext) {
1884
+ return ext.loadNode && ext.loadNode(index);
1885
+ });
1880
1886
  break;
1881
1887
 
1882
1888
  case 'mesh':
@@ -1926,7 +1932,15 @@ class GLTFParser {
1926
1932
  break;
1927
1933
 
1928
1934
  default:
1929
- throw new Error('Unknown type: ' + type);
1935
+ dependency = this._invokeOne(function (ext) {
1936
+ return ext != this && ext.getDependency && ext.getDependency(type, index);
1937
+ });
1938
+
1939
+ if (!dependency) {
1940
+ throw new Error('Unknown type: ' + type);
1941
+ }
1942
+
1943
+ break;
1930
1944
  }
1931
1945
 
1932
1946
  this.cache.add(cacheKey, dependency);
@@ -2010,10 +2024,11 @@ class GLTFParser {
2010
2024
  const accessorDef = this.json.accessors[accessorIndex];
2011
2025
 
2012
2026
  if (accessorDef.bufferView === undefined && accessorDef.sparse === undefined) {
2013
- // Ignore empty accessors, which may be used to declare runtime
2014
- // information about attributes coming from another source (e.g. Draco
2015
- // compression extension).
2016
- return Promise.resolve(null);
2027
+ const itemSize = WEBGL_TYPE_SIZES[accessorDef.type];
2028
+ const TypedArray = WEBGL_COMPONENT_TYPES[accessorDef.componentType];
2029
+ const normalized = accessorDef.normalized === true;
2030
+ const array = new TypedArray(accessorDef.count * itemSize);
2031
+ return Promise.resolve(new BufferAttribute(array, itemSize, normalized));
2017
2032
  }
2018
2033
 
2019
2034
  const pendingBufferViews = [];
@@ -2096,7 +2111,7 @@ class GLTFParser {
2096
2111
  /**
2097
2112
  * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures
2098
2113
  * @param {number} textureIndex
2099
- * @return {Promise<THREE.Texture>}
2114
+ * @return {Promise<THREE.Texture|null>}
2100
2115
  */
2101
2116
 
2102
2117
 
@@ -2130,7 +2145,12 @@ class GLTFParser {
2130
2145
 
2131
2146
  const promise = this.loadImageSource(sourceIndex, loader).then(function (texture) {
2132
2147
  texture.flipY = false;
2133
- if (textureDef.name) texture.name = textureDef.name;
2148
+ texture.name = textureDef.name || sourceDef.name || '';
2149
+
2150
+ if (texture.name === '' && typeof sourceDef.uri === 'string' && sourceDef.uri.startsWith('data:image/') === false) {
2151
+ texture.name = sourceDef.uri;
2152
+ }
2153
+
2134
2154
  const samplers = json.samplers || {};
2135
2155
  const sampler = samplers[textureDef.sampler] || {};
2136
2156
  texture.magFilter = WEBGL_FILTERS[sampler.magFilter] || LinearFilter;
@@ -2217,10 +2237,11 @@ class GLTFParser {
2217
2237
  assignTexture(materialParams, mapName, mapDef, encoding) {
2218
2238
  const parser = this;
2219
2239
  return this.getDependency('texture', mapDef.index).then(function (texture) {
2220
- // Materials sample aoMap from UV set 1 and other maps from UV set 0 - this can't be configured
2221
- // However, we will copy UV set 0 to UV set 1 on demand for aoMap
2222
- if (mapDef.texCoord !== undefined && mapDef.texCoord != 0 && !(mapName === 'aoMap' && mapDef.texCoord == 1)) {
2223
- console.warn('THREE.GLTFLoader: Custom UV set ' + mapDef.texCoord + ' for texture ' + mapName + ' not yet supported.');
2240
+ if (!texture) return null;
2241
+
2242
+ if (mapDef.texCoord !== undefined && mapDef.texCoord > 0) {
2243
+ texture = texture.clone();
2244
+ texture.channel = mapDef.texCoord;
2224
2245
  }
2225
2246
 
2226
2247
  if (parser.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM]) {
@@ -2281,6 +2302,7 @@ class GLTFParser {
2281
2302
  lineMaterial = new LineBasicMaterial();
2282
2303
  Material.prototype.copy.call(lineMaterial, material);
2283
2304
  lineMaterial.color.copy(material.color);
2305
+ lineMaterial.map = material.map;
2284
2306
  this.cache.add(cacheKey, lineMaterial);
2285
2307
  }
2286
2308
 
@@ -2290,7 +2312,6 @@ class GLTFParser {
2290
2312
 
2291
2313
  if (useDerivativeTangents || useVertexColors || useFlatShading) {
2292
2314
  let cacheKey = 'ClonedMaterial:' + material.uuid + ':';
2293
- if (material.isGLTFSpecularGlossinessMaterial) cacheKey += 'specular-glossiness:';
2294
2315
  if (useDerivativeTangents) cacheKey += 'derivative-tangents:';
2295
2316
  if (useVertexColors) cacheKey += 'vertex-colors:';
2296
2317
  if (useFlatShading) cacheKey += 'flat-shading:';
@@ -2312,11 +2333,6 @@ class GLTFParser {
2312
2333
  }
2313
2334
 
2314
2335
  material = cachedMaterial;
2315
- } // workarounds for mesh and geometry
2316
-
2317
-
2318
- if (material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined) {
2319
- geometry.setAttribute('uv2', geometry.attributes.uv);
2320
2336
  }
2321
2337
 
2322
2338
  mesh.material = material;
@@ -2342,11 +2358,7 @@ class GLTFParser {
2342
2358
  const materialExtensions = materialDef.extensions || {};
2343
2359
  const pending = [];
2344
2360
 
2345
- if (materialExtensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS]) {
2346
- const sgExtension = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS];
2347
- materialType = sgExtension.getMaterialType();
2348
- pending.push(sgExtension.extendParams(materialParams, materialDef, parser));
2349
- } else if (materialExtensions[EXTENSIONS.KHR_MATERIALS_UNLIT]) {
2361
+ if (materialExtensions[EXTENSIONS.KHR_MATERIALS_UNLIT]) {
2350
2362
  const kmuExtension = extensions[EXTENSIONS.KHR_MATERIALS_UNLIT];
2351
2363
  materialType = kmuExtension.getMaterialType();
2352
2364
  pending.push(kmuExtension.extendParams(materialParams, materialDef, parser));
@@ -2428,14 +2440,7 @@ class GLTFParser {
2428
2440
  }
2429
2441
 
2430
2442
  return Promise.all(pending).then(function () {
2431
- let material;
2432
-
2433
- if (materialType === GLTFMeshStandardSGMaterial) {
2434
- material = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].createMaterial(materialParams);
2435
- } else {
2436
- material = new materialType(materialParams);
2437
- }
2438
-
2443
+ const material = new materialType(materialParams);
2439
2444
  if (materialDef.name) material.name = materialDef.name;
2440
2445
  assignExtrasToUserData(material, materialDef);
2441
2446
  parser.associations.set(material, {
@@ -2550,9 +2555,8 @@ class GLTFParser {
2550
2555
  // .isSkinnedMesh isn't in glTF spec. See ._markDefs()
2551
2556
  mesh = meshDef.isSkinnedMesh === true ? new SkinnedMesh(geometry, material) : new Mesh(geometry, material);
2552
2557
 
2553
- if (mesh.isSkinnedMesh === true && !mesh.geometry.attributes.skinWeight.normalized) {
2554
- // we normalize floating point skin weight array to fix malformed assets (see #15319)
2555
- // it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs
2558
+ if (mesh.isSkinnedMesh === true) {
2559
+ // normalize skin weights to fix malformed assets (see #15319)
2556
2560
  mesh.normalizeSkinWeights();
2557
2561
  }
2558
2562
 
@@ -2637,23 +2641,50 @@ class GLTFParser {
2637
2641
  /**
2638
2642
  * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins
2639
2643
  * @param {number} skinIndex
2640
- * @return {Promise<Object>}
2644
+ * @return {Promise<Skeleton>}
2641
2645
  */
2642
2646
 
2643
2647
 
2644
2648
  loadSkin(skinIndex) {
2645
2649
  const skinDef = this.json.skins[skinIndex];
2646
- const skinEntry = {
2647
- joints: skinDef.joints
2648
- };
2650
+ const pending = [];
2651
+
2652
+ for (let i = 0, il = skinDef.joints.length; i < il; i++) {
2653
+ pending.push(this._loadNodeShallow(skinDef.joints[i]));
2654
+ }
2649
2655
 
2650
- if (skinDef.inverseBindMatrices === undefined) {
2651
- return Promise.resolve(skinEntry);
2656
+ if (skinDef.inverseBindMatrices !== undefined) {
2657
+ pending.push(this.getDependency('accessor', skinDef.inverseBindMatrices));
2658
+ } else {
2659
+ pending.push(null);
2652
2660
  }
2653
2661
 
2654
- return this.getDependency('accessor', skinDef.inverseBindMatrices).then(function (accessor) {
2655
- skinEntry.inverseBindMatrices = accessor;
2656
- return skinEntry;
2662
+ return Promise.all(pending).then(function (results) {
2663
+ const inverseBindMatrices = results.pop();
2664
+ const jointNodes = results; // Note that bones (joint nodes) may or may not be in the
2665
+ // scene graph at this time.
2666
+
2667
+ const bones = [];
2668
+ const boneInverses = [];
2669
+
2670
+ for (let i = 0, il = jointNodes.length; i < il; i++) {
2671
+ const jointNode = jointNodes[i];
2672
+
2673
+ if (jointNode) {
2674
+ bones.push(jointNode);
2675
+ const mat = new Matrix4();
2676
+
2677
+ if (inverseBindMatrices !== null) {
2678
+ mat.fromArray(inverseBindMatrices.array, i * 16);
2679
+ }
2680
+
2681
+ boneInverses.push(mat);
2682
+ } else {
2683
+ console.warn('THREE.GLTFLoader: Joint "%s" could not be found.', skinDef.joints[i]);
2684
+ }
2685
+ }
2686
+
2687
+ return new Skeleton(bones, boneInverses);
2657
2688
  });
2658
2689
  }
2659
2690
  /**
@@ -2666,6 +2697,7 @@ class GLTFParser {
2666
2697
  loadAnimation(animationIndex) {
2667
2698
  const json = this.json;
2668
2699
  const animationDef = json.animations[animationIndex];
2700
+ const animationName = animationDef.name ? animationDef.name : 'animation_' + animationIndex;
2669
2701
  const pendingNodes = [];
2670
2702
  const pendingInputAccessors = [];
2671
2703
  const pendingOutputAccessors = [];
@@ -2679,6 +2711,7 @@ class GLTFParser {
2679
2711
  const name = target.node;
2680
2712
  const input = animationDef.parameters !== undefined ? animationDef.parameters[sampler.input] : sampler.input;
2681
2713
  const output = animationDef.parameters !== undefined ? animationDef.parameters[sampler.output] : sampler.output;
2714
+ if (target.node === undefined) continue;
2682
2715
  pendingNodes.push(this.getDependency('node', name));
2683
2716
  pendingInputAccessors.push(this.getDependency('accessor', input));
2684
2717
  pendingOutputAccessors.push(this.getDependency('accessor', output));
@@ -2767,8 +2800,7 @@ class GLTFParser {
2767
2800
  }
2768
2801
  }
2769
2802
 
2770
- const name = animationDef.name ? animationDef.name : 'animation_' + animationIndex;
2771
- return new AnimationClip(name, undefined, tracks);
2803
+ return new AnimationClip(animationName, undefined, tracks);
2772
2804
  });
2773
2805
  }
2774
2806
 
@@ -2803,36 +2835,79 @@ class GLTFParser {
2803
2835
 
2804
2836
  loadNode(nodeIndex) {
2805
2837
  const json = this.json;
2806
- const extensions = this.extensions;
2807
2838
  const parser = this;
2808
- const nodeDef = json.nodes[nodeIndex]; // reserve node's name before its dependencies, so the root has the intended name.
2839
+ const nodeDef = json.nodes[nodeIndex];
2809
2840
 
2810
- const nodeName = nodeDef.name ? parser.createUniqueName(nodeDef.name) : '';
2811
- return function () {
2812
- const pending = [];
2841
+ const nodePending = parser._loadNodeShallow(nodeIndex);
2813
2842
 
2814
- const meshPromise = parser._invokeOne(function (ext) {
2815
- return ext.createNodeMesh && ext.createNodeMesh(nodeIndex);
2816
- });
2843
+ const childPending = [];
2844
+ const childrenDef = nodeDef.children || [];
2845
+
2846
+ for (let i = 0, il = childrenDef.length; i < il; i++) {
2847
+ childPending.push(parser.getDependency('node', childrenDef[i]));
2848
+ }
2849
+
2850
+ const skeletonPending = nodeDef.skin === undefined ? Promise.resolve(null) : parser.getDependency('skin', nodeDef.skin);
2851
+ return Promise.all([nodePending, Promise.all(childPending), skeletonPending]).then(function (results) {
2852
+ const node = results[0];
2853
+ const children = results[1];
2854
+ const skeleton = results[2];
2817
2855
 
2818
- if (meshPromise) {
2819
- pending.push(meshPromise);
2856
+ if (skeleton !== null) {
2857
+ // This full traverse should be fine because
2858
+ // child glTF nodes have not been added to this node yet.
2859
+ node.traverse(function (mesh) {
2860
+ if (!mesh.isSkinnedMesh) return;
2861
+ mesh.bind(skeleton, _identityMatrix);
2862
+ });
2820
2863
  }
2821
2864
 
2822
- if (nodeDef.camera !== undefined) {
2823
- pending.push(parser.getDependency('camera', nodeDef.camera).then(function (camera) {
2824
- return parser._getNodeRef(parser.cameraCache, nodeDef.camera, camera);
2825
- }));
2865
+ for (let i = 0, il = children.length; i < il; i++) {
2866
+ node.add(children[i]);
2826
2867
  }
2827
2868
 
2828
- parser._invokeAll(function (ext) {
2829
- return ext.createNodeAttachment && ext.createNodeAttachment(nodeIndex);
2830
- }).forEach(function (promise) {
2831
- pending.push(promise);
2832
- });
2869
+ return node;
2870
+ });
2871
+ } // ._loadNodeShallow() parses a single node.
2872
+ // skin and child nodes are created and added in .loadNode() (no '_' prefix).
2873
+
2874
+
2875
+ _loadNodeShallow(nodeIndex) {
2876
+ const json = this.json;
2877
+ const extensions = this.extensions;
2878
+ const parser = this; // This method is called from .loadNode() and .loadSkin().
2879
+ // Cache a node to avoid duplication.
2880
+
2881
+ if (this.nodeCache[nodeIndex] !== undefined) {
2882
+ return this.nodeCache[nodeIndex];
2883
+ }
2884
+
2885
+ const nodeDef = json.nodes[nodeIndex]; // reserve node's name before its dependencies, so the root has the intended name.
2886
+
2887
+ const nodeName = nodeDef.name ? parser.createUniqueName(nodeDef.name) : '';
2888
+ const pending = [];
2889
+
2890
+ const meshPromise = parser._invokeOne(function (ext) {
2891
+ return ext.createNodeMesh && ext.createNodeMesh(nodeIndex);
2892
+ });
2893
+
2894
+ if (meshPromise) {
2895
+ pending.push(meshPromise);
2896
+ }
2897
+
2898
+ if (nodeDef.camera !== undefined) {
2899
+ pending.push(parser.getDependency('camera', nodeDef.camera).then(function (camera) {
2900
+ return parser._getNodeRef(parser.cameraCache, nodeDef.camera, camera);
2901
+ }));
2902
+ }
2833
2903
 
2834
- return Promise.all(pending);
2835
- }().then(function (objects) {
2904
+ parser._invokeAll(function (ext) {
2905
+ return ext.createNodeAttachment && ext.createNodeAttachment(nodeIndex);
2906
+ }).forEach(function (promise) {
2907
+ pending.push(promise);
2908
+ });
2909
+
2910
+ this.nodeCache[nodeIndex] = Promise.all(pending).then(function (objects) {
2836
2911
  let node; // .isBone isn't in glTF spec. See ._markDefs
2837
2912
 
2838
2913
  if (nodeDef.isBone === true) {
@@ -2884,6 +2959,7 @@ class GLTFParser {
2884
2959
  parser.associations.get(node).nodes = nodeIndex;
2885
2960
  return node;
2886
2961
  });
2962
+ return this.nodeCache[nodeIndex];
2887
2963
  }
2888
2964
  /**
2889
2965
  * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes
@@ -2893,7 +2969,6 @@ class GLTFParser {
2893
2969
 
2894
2970
 
2895
2971
  loadScene(sceneIndex) {
2896
- const json = this.json;
2897
2972
  const extensions = this.extensions;
2898
2973
  const sceneDef = this.json.scenes[sceneIndex];
2899
2974
  const parser = this; // Loader returns Group, not Scene.
@@ -2907,12 +2982,16 @@ class GLTFParser {
2907
2982
  const pending = [];
2908
2983
 
2909
2984
  for (let i = 0, il = nodeIds.length; i < il; i++) {
2910
- pending.push(buildNodeHierarchy(nodeIds[i], scene, json, parser));
2985
+ pending.push(parser.getDependency('node', nodeIds[i]));
2911
2986
  }
2912
2987
 
2913
- return Promise.all(pending).then(function () {
2914
- // Removes dangling associations, associations that reference a node that
2988
+ return Promise.all(pending).then(function (nodes) {
2989
+ for (let i = 0, il = nodes.length; i < il; i++) {
2990
+ scene.add(nodes[i]);
2991
+ } // Removes dangling associations, associations that reference a node that
2915
2992
  // didn't make it into the scene.
2993
+
2994
+
2916
2995
  const reduceAssociations = node => {
2917
2996
  const reducedAssociations = new Map();
2918
2997
 
@@ -2938,66 +3017,6 @@ class GLTFParser {
2938
3017
  }
2939
3018
 
2940
3019
  }
2941
-
2942
- function buildNodeHierarchy(nodeId, parentObject, json, parser) {
2943
- const nodeDef = json.nodes[nodeId];
2944
- return parser.getDependency('node', nodeId).then(function (node) {
2945
- if (nodeDef.skin === undefined) return node; // build skeleton here as well
2946
-
2947
- let skinEntry;
2948
- return parser.getDependency('skin', nodeDef.skin).then(function (skin) {
2949
- skinEntry = skin;
2950
- const pendingJoints = [];
2951
-
2952
- for (let i = 0, il = skinEntry.joints.length; i < il; i++) {
2953
- pendingJoints.push(parser.getDependency('node', skinEntry.joints[i]));
2954
- }
2955
-
2956
- return Promise.all(pendingJoints);
2957
- }).then(function (jointNodes) {
2958
- node.traverse(function (mesh) {
2959
- if (!mesh.isMesh) return;
2960
- const bones = [];
2961
- const boneInverses = [];
2962
-
2963
- for (let j = 0, jl = jointNodes.length; j < jl; j++) {
2964
- const jointNode = jointNodes[j];
2965
-
2966
- if (jointNode) {
2967
- bones.push(jointNode);
2968
- const mat = new Matrix4();
2969
-
2970
- if (skinEntry.inverseBindMatrices !== undefined) {
2971
- mat.fromArray(skinEntry.inverseBindMatrices.array, j * 16);
2972
- }
2973
-
2974
- boneInverses.push(mat);
2975
- } else {
2976
- console.warn('THREE.GLTFLoader: Joint "%s" could not be found.', skinEntry.joints[j]);
2977
- }
2978
- }
2979
-
2980
- mesh.bind(new Skeleton(bones, boneInverses), mesh.matrixWorld);
2981
- });
2982
- return node;
2983
- });
2984
- }).then(function (node) {
2985
- // build node hierachy
2986
- parentObject.add(node);
2987
- const pending = [];
2988
-
2989
- if (nodeDef.children) {
2990
- const children = nodeDef.children;
2991
-
2992
- for (let i = 0, il = children.length; i < il; i++) {
2993
- const child = children[i];
2994
- pending.push(buildNodeHierarchy(child, node, json, parser));
2995
- }
2996
- }
2997
-
2998
- return Promise.all(pending);
2999
- });
3000
- }
3001
3020
  /**
3002
3021
  * @param {BufferGeometry} geometry
3003
3022
  * @param {GLTF.Primitive} primitiveDef
@@ -3114,67 +3133,5 @@ function addPrimitiveAttributes(geometry, primitiveDef, parser) {
3114
3133
  return primitiveDef.targets !== undefined ? addMorphTargets(geometry, primitiveDef.targets, parser) : geometry;
3115
3134
  });
3116
3135
  }
3117
- /**
3118
- * @param {BufferGeometry} geometry
3119
- * @param {Number} drawMode
3120
- * @return {BufferGeometry}
3121
- */
3122
-
3123
-
3124
- function toTrianglesDrawMode(geometry, drawMode) {
3125
- let index = geometry.getIndex(); // generate index if not present
3126
-
3127
- if (index === null) {
3128
- const indices = [];
3129
- const position = geometry.getAttribute('position');
3130
-
3131
- if (position !== undefined) {
3132
- for (let i = 0; i < position.count; i++) {
3133
- indices.push(i);
3134
- }
3135
-
3136
- geometry.setIndex(indices);
3137
- index = geometry.getIndex();
3138
- } else {
3139
- console.error('THREE.GLTFLoader.toTrianglesDrawMode(): Undefined position attribute. Processing not possible.');
3140
- return geometry;
3141
- }
3142
- } //
3143
-
3144
-
3145
- const numberOfTriangles = index.count - 2;
3146
- const newIndices = [];
3147
-
3148
- if (drawMode === TriangleFanDrawMode) {
3149
- // gl.TRIANGLE_FAN
3150
- for (let i = 1; i <= numberOfTriangles; i++) {
3151
- newIndices.push(index.getX(0));
3152
- newIndices.push(index.getX(i));
3153
- newIndices.push(index.getX(i + 1));
3154
- }
3155
- } else {
3156
- // gl.TRIANGLE_STRIP
3157
- for (let i = 0; i < numberOfTriangles; i++) {
3158
- if (i % 2 === 0) {
3159
- newIndices.push(index.getX(i));
3160
- newIndices.push(index.getX(i + 1));
3161
- newIndices.push(index.getX(i + 2));
3162
- } else {
3163
- newIndices.push(index.getX(i + 2));
3164
- newIndices.push(index.getX(i + 1));
3165
- newIndices.push(index.getX(i));
3166
- }
3167
- }
3168
- }
3169
-
3170
- if (newIndices.length / 3 !== numberOfTriangles) {
3171
- console.error('THREE.GLTFLoader.toTrianglesDrawMode(): Unable to generate correct amount of triangles.');
3172
- } // build final geometry
3173
-
3174
-
3175
- const newGeometry = geometry.clone();
3176
- newGeometry.setIndex(newIndices);
3177
- return newGeometry;
3178
- }
3179
3136
 
3180
3137
  export { GLTFLoader };