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.
- package/index.cjs.js +1 -1
- package/loaders/GLTFLoader.cjs.js +1 -1
- package/loaders/GLTFLoader.js +372 -415
- package/loaders/VRMLoader.cjs.js +1 -1
- package/package.json +1 -1
- package/webxr/OculusHandModel.cjs.js +1 -1
- package/webxr/XRControllerModelFactory.cjs.js +1 -1
- package/webxr/XRHandMeshModel.cjs.js +1 -1
- package/webxr/XRHandModelFactory.cjs.js +1 -1
package/loaders/GLTFLoader.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Loader, LoaderUtils, FileLoader, Color, SpotLight, PointLight, DirectionalLight, MeshBasicMaterial, sRGBEncoding, MeshPhysicalMaterial, Vector2,
|
|
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
|
|
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
|
-
|
|
135
|
-
} else {
|
|
136
|
-
const magic =
|
|
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
|
-
|
|
154
|
+
json = JSON.parse(extensions[EXTENSIONS.KHR_BINARY_GLTF].content);
|
|
147
155
|
} else {
|
|
148
|
-
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
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
|
|
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
|
-
|
|
1447
|
-
|
|
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 = {}; //
|
|
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
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
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();
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2221
|
-
|
|
2222
|
-
if (mapDef.texCoord !== undefined && mapDef.texCoord
|
|
2223
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
2554
|
-
//
|
|
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<
|
|
2644
|
+
* @return {Promise<Skeleton>}
|
|
2641
2645
|
*/
|
|
2642
2646
|
|
|
2643
2647
|
|
|
2644
2648
|
loadSkin(skinIndex) {
|
|
2645
2649
|
const skinDef = this.json.skins[skinIndex];
|
|
2646
|
-
const
|
|
2647
|
-
|
|
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
|
|
2651
|
-
|
|
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
|
|
2655
|
-
|
|
2656
|
-
|
|
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
|
-
|
|
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];
|
|
2839
|
+
const nodeDef = json.nodes[nodeIndex];
|
|
2809
2840
|
|
|
2810
|
-
const
|
|
2811
|
-
return function () {
|
|
2812
|
-
const pending = [];
|
|
2841
|
+
const nodePending = parser._loadNodeShallow(nodeIndex);
|
|
2813
2842
|
|
|
2814
|
-
|
|
2815
|
-
|
|
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 (
|
|
2819
|
-
|
|
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
|
-
|
|
2823
|
-
|
|
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
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
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
|
-
|
|
2835
|
-
|
|
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(
|
|
2985
|
+
pending.push(parser.getDependency('node', nodeIds[i]));
|
|
2911
2986
|
}
|
|
2912
2987
|
|
|
2913
|
-
return Promise.all(pending).then(function () {
|
|
2914
|
-
|
|
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 };
|