@babylonjs/loaders 9.26.0 → 9.26.2
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/FBX/fbxConstraintBehavior.d.ts +188 -0
- package/FBX/fbxConstraintBehavior.js +532 -0
- package/FBX/fbxConstraintBehavior.js.map +1 -0
- package/FBX/fbxFileLoader.pure.d.ts +175 -6
- package/FBX/fbxFileLoader.pure.js +1521 -286
- package/FBX/fbxFileLoader.pure.js.map +1 -1
- package/FBX/index.d.ts +4 -1
- package/FBX/index.js +1 -0
- package/FBX/index.js.map +1 -1
- package/FBX/interpreter/animation.d.ts +73 -33
- package/FBX/interpreter/animation.js +620 -223
- package/FBX/interpreter/animation.js.map +1 -1
- package/FBX/interpreter/animationCurve.d.ts +91 -0
- package/FBX/interpreter/animationCurve.js +623 -0
- package/FBX/interpreter/animationCurve.js.map +1 -0
- package/FBX/interpreter/blendShapes.js +9 -18
- package/FBX/interpreter/blendShapes.js.map +1 -1
- package/FBX/interpreter/connections.d.ts +1 -1
- package/FBX/interpreter/connections.js +173 -34
- package/FBX/interpreter/connections.js.map +1 -1
- package/FBX/interpreter/constraints.d.ts +68 -0
- package/FBX/interpreter/constraints.js +143 -0
- package/FBX/interpreter/constraints.js.map +1 -0
- package/FBX/interpreter/fbxInterpreter.d.ts +89 -4
- package/FBX/interpreter/fbxInterpreter.js +474 -122
- package/FBX/interpreter/fbxInterpreter.js.map +1 -1
- package/FBX/interpreter/geometry.d.ts +1 -1
- package/FBX/interpreter/geometry.js +150 -92
- package/FBX/interpreter/geometry.js.map +1 -1
- package/FBX/interpreter/legacyDocument.d.ts +11 -0
- package/FBX/interpreter/legacyDocument.js +425 -0
- package/FBX/interpreter/legacyDocument.js.map +1 -0
- package/FBX/interpreter/materialModel.d.ts +71 -0
- package/FBX/interpreter/materialModel.js +622 -0
- package/FBX/interpreter/materialModel.js.map +1 -0
- package/FBX/interpreter/materials.d.ts +13 -1
- package/FBX/interpreter/materials.js +88 -5
- package/FBX/interpreter/materials.js.map +1 -1
- package/FBX/interpreter/nodeTransform.d.ts +32 -0
- package/FBX/interpreter/nodeTransform.js +54 -0
- package/FBX/interpreter/nodeTransform.js.map +1 -0
- package/FBX/interpreter/nurbs.d.ts +99 -0
- package/FBX/interpreter/nurbs.js +627 -0
- package/FBX/interpreter/nurbs.js.map +1 -0
- package/FBX/interpreter/propertyTemplates.d.ts +23 -0
- package/FBX/interpreter/propertyTemplates.js +109 -2
- package/FBX/interpreter/propertyTemplates.js.map +1 -1
- package/FBX/interpreter/rig.js +16 -0
- package/FBX/interpreter/rig.js.map +1 -1
- package/FBX/interpreter/sceneDiagnostics.js +28 -3
- package/FBX/interpreter/sceneDiagnostics.js.map +1 -1
- package/FBX/interpreter/skeleton.d.ts +4 -18
- package/FBX/interpreter/skeleton.js +16 -94
- package/FBX/interpreter/skeleton.js.map +1 -1
- package/FBX/parsers/fbxAsciiParser.js +119 -9
- package/FBX/parsers/fbxAsciiParser.js.map +1 -1
- package/FBX/parsers/fbxBinaryParser.js +74 -22
- package/FBX/parsers/fbxBinaryParser.js.map +1 -1
- package/FBX/pure.d.ts +1 -0
- package/FBX/pure.js +1 -0
- package/FBX/pure.js.map +1 -1
- package/FBX/types/fbxTypes.d.ts +18 -2
- package/FBX/types/fbxTypes.js +40 -12
- package/FBX/types/fbxTypes.js.map +1 -1
- package/SPLAT/gaussianSplattingStream.d.ts +79 -25
- package/SPLAT/gaussianSplattingStream.js +320 -95
- package/SPLAT/gaussianSplattingStream.js.map +1 -1
- package/USD/usdCommandProtocol.d.ts +20 -4
- package/USD/usdCommandProtocol.js +25 -3
- package/USD/usdCommandProtocol.js.map +1 -1
- package/USD/usdFileLoader.pure.js +2 -0
- package/USD/usdFileLoader.pure.js.map +1 -1
- package/USD/usdSceneMaterializer.js +430 -92
- package/USD/usdSceneMaterializer.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.d.ts +110 -3
- package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js +468 -74
- package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphEventReferenceBlock.d.ts +47 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphEventReferenceBlock.js +68 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphEventReferenceBlock.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphGLTFDataProvider.d.ts +2 -2
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphGLTFDataProvider.js +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphGLTFDataProvider.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphObjectReferenceBlock.d.ts +24 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphObjectReferenceBlock.js +38 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphObjectReferenceBlock.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphUnsupportedInteractivityBlock.d.ts +41 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphUnsupportedInteractivityBlock.js +63 -0
- package/glTF/2.0/Extensions/KHR_interactivity/flowGraphUnsupportedInteractivityBlock.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/index.d.ts +5 -0
- package/glTF/2.0/Extensions/KHR_interactivity/index.js +5 -0
- package/glTF/2.0/Extensions/KHR_interactivity/index.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.d.ts +112 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.js +773 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.d.ts +18 -10
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js +299 -54
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.d.ts +2 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js +7 -2
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityNodeState.d.ts +24 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityNodeState.js +89 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityNodeState.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/pure.d.ts +5 -0
- package/glTF/2.0/Extensions/KHR_interactivity/pure.js +5 -0
- package/glTF/2.0/Extensions/KHR_interactivity/pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity.pure.d.ts +55 -1
- package/glTF/2.0/Extensions/KHR_interactivity.pure.js +124 -76
- package/glTF/2.0/Extensions/KHR_interactivity.pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity.types.d.ts +18 -1
- package/glTF/2.0/Extensions/KHR_interactivity.types.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.d.ts +2 -0
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js +114 -56
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.d.ts +2 -0
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.js +80 -35
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.js.map +1 -1
- package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js +3 -2
- package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js.map +1 -1
- package/glTF/2.0/Extensions/objectModelMapping.d.ts +4 -2
- package/glTF/2.0/Extensions/objectModelMapping.js +33 -4
- package/glTF/2.0/Extensions/objectModelMapping.js.map +1 -1
- package/glTF/2.0/glTFLoader.pure.d.ts +1 -1
- package/glTF/2.0/glTFLoader.pure.js +9 -4
- package/glTF/2.0/glTFLoader.pure.js.map +1 -1
- package/glTF/2.0/glTFLoaderExtension.d.ts +2 -1
- package/glTF/2.0/glTFLoaderExtension.js.map +1 -1
- package/package.json +3 -3
|
@@ -4,12 +4,15 @@ import { AnimationGroup } from "@babylonjs/core/Animations/animationGroup.pure.j
|
|
|
4
4
|
import { AbstractAssetContainer, AssetContainer } from "@babylonjs/core/assetContainer.js";
|
|
5
5
|
import { Bone } from "@babylonjs/core/Bones/bone.js";
|
|
6
6
|
import { Skeleton } from "@babylonjs/core/Bones/skeleton.js";
|
|
7
|
-
import { Color3 } from "@babylonjs/core/Maths/math.color.pure.js";
|
|
7
|
+
import { Color3, Color4 } from "@babylonjs/core/Maths/math.color.pure.js";
|
|
8
8
|
import { Matrix, Quaternion, Vector3 } from "@babylonjs/core/Maths/math.vector.pure.js";
|
|
9
9
|
import { Material } from "@babylonjs/core/Materials/material.pure.js";
|
|
10
10
|
import { MultiMaterial } from "@babylonjs/core/Materials/multiMaterial.pure.js";
|
|
11
11
|
import { PBRMaterial } from "@babylonjs/core/Materials/PBR/pbrMaterial.pure.js";
|
|
12
12
|
import { Texture } from "@babylonjs/core/Materials/Textures/texture.pure.js";
|
|
13
|
+
import { CreateFactorOperand, CreateTextureOperand, LerpTexturesAsync, TextureChannel, TextureColorSpace, } from "@babylonjs/core/Materials/Textures/textureProcessor.js";
|
|
14
|
+
import { MorphTarget } from "@babylonjs/core/Morph/morphTarget.js";
|
|
15
|
+
import { MorphTargetManager } from "@babylonjs/core/Morph/morphTargetManager.js";
|
|
13
16
|
import { CreateBox } from "@babylonjs/core/Meshes/Builders/boxBuilder.pure.js";
|
|
14
17
|
import { CreateCylinder } from "@babylonjs/core/Meshes/Builders/cylinderBuilder.pure.js";
|
|
15
18
|
import { CreateSphere } from "@babylonjs/core/Meshes/Builders/sphereBuilder.pure.js";
|
|
@@ -17,6 +20,7 @@ import { Mesh } from "@babylonjs/core/Meshes/mesh.pure.js";
|
|
|
17
20
|
import { SubMesh } from "@babylonjs/core/Meshes/subMesh.js";
|
|
18
21
|
import { TransformNode } from "@babylonjs/core/Meshes/transformNode.pure.js";
|
|
19
22
|
import { VertexData } from "@babylonjs/core/Meshes/mesh.vertexData.js";
|
|
23
|
+
import { Constants } from "@babylonjs/core/Engines/constants.js";
|
|
20
24
|
import { MISSING_OFFSET, PayloadReader, readCommands, } from "./usdCommandProtocol.js";
|
|
21
25
|
class DirectAssetContainer extends AbstractAssetContainer {
|
|
22
26
|
dispose() {
|
|
@@ -26,6 +30,9 @@ class DirectAssetContainer extends AbstractAssetContainer {
|
|
|
26
30
|
for (const mesh of this.meshes.splice(0)) {
|
|
27
31
|
mesh.dispose();
|
|
28
32
|
}
|
|
33
|
+
for (const manager of this.morphTargetManagers.splice(0)) {
|
|
34
|
+
manager.dispose();
|
|
35
|
+
}
|
|
29
36
|
for (const skeleton of this.skeletons.splice(0)) {
|
|
30
37
|
skeleton.dispose();
|
|
31
38
|
}
|
|
@@ -92,6 +99,27 @@ function wrapMode(value) {
|
|
|
92
99
|
throw new Error(`Invalid texture wrap mode ${value}.`);
|
|
93
100
|
}
|
|
94
101
|
}
|
|
102
|
+
async function awaitAbortableAsync(promise, signal) {
|
|
103
|
+
if (!signal) {
|
|
104
|
+
return await promise;
|
|
105
|
+
}
|
|
106
|
+
let onAbort;
|
|
107
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
108
|
+
onAbort = () => reject(signal.reason instanceof Error ? signal.reason : new Error("USD materialization was aborted."));
|
|
109
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
110
|
+
if (signal.aborted) {
|
|
111
|
+
onAbort();
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
try {
|
|
115
|
+
return await Promise.race([promise, aborted]);
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
if (onAbort) {
|
|
119
|
+
signal.removeEventListener("abort", onAbort);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
95
123
|
export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer, addToScene, signal) {
|
|
96
124
|
signal?.throwIfAborted();
|
|
97
125
|
const started = performance.now();
|
|
@@ -106,12 +134,25 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
106
134
|
const bones = new Map();
|
|
107
135
|
const geometries = new Map();
|
|
108
136
|
const meshes = new Map();
|
|
137
|
+
const morphTargetManagers = new Map();
|
|
138
|
+
const morphTargets = new Map();
|
|
139
|
+
const classicInstanceSources = new Set();
|
|
140
|
+
const thinInstanceSources = new Set();
|
|
109
141
|
const animationGroups = new Map();
|
|
110
142
|
const textureLoads = [];
|
|
111
143
|
const textureUrls = new Set();
|
|
144
|
+
const materialTextureBindings = [];
|
|
145
|
+
const processedTextures = new Map();
|
|
112
146
|
const assetContainer = container instanceof AssetContainer ? container : undefined;
|
|
113
147
|
let root;
|
|
114
148
|
let timeCodesPerSecond = 24;
|
|
149
|
+
let rollingBack = false;
|
|
150
|
+
const caps = scene.getEngine().getCaps();
|
|
151
|
+
const processedTextureType = caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering
|
|
152
|
+
? Constants.TEXTURETYPE_HALF_FLOAT
|
|
153
|
+
: caps.textureFloatRender && caps.textureFloatLinearFiltering
|
|
154
|
+
? Constants.TEXTURETYPE_FLOAT
|
|
155
|
+
: Constants.TEXTURETYPE_UNSIGNED_BYTE;
|
|
115
156
|
const trackAsset = (assets, asset) => {
|
|
116
157
|
assets.push(asset);
|
|
117
158
|
if (assetContainer) {
|
|
@@ -137,6 +178,255 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
137
178
|
}
|
|
138
179
|
return variant;
|
|
139
180
|
};
|
|
181
|
+
const binding = (textureId, channel, label) => {
|
|
182
|
+
if (textureId === MISSING_OFFSET) {
|
|
183
|
+
if (channel !== MISSING_OFFSET) {
|
|
184
|
+
throw new Error(`USD ${label} binding has a channel without a texture.`);
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
const descriptor = textures.get(textureId);
|
|
189
|
+
if (!descriptor) {
|
|
190
|
+
throw new Error(`USD ${label} binding references missing texture ${textureId}.`);
|
|
191
|
+
}
|
|
192
|
+
if (channel < 0 /* TextureOutputChannel.R */ || channel > 4 /* TextureOutputChannel.RGB */) {
|
|
193
|
+
throw new Error(`USD ${label} binding has invalid output channel ${channel}.`);
|
|
194
|
+
}
|
|
195
|
+
return { descriptor, channel };
|
|
196
|
+
};
|
|
197
|
+
const channelIndex = (channel) => {
|
|
198
|
+
if (channel === 4 /* TextureOutputChannel.RGB */) {
|
|
199
|
+
throw new Error("A scalar USD texture binding cannot use the RGB output.");
|
|
200
|
+
}
|
|
201
|
+
return channel;
|
|
202
|
+
};
|
|
203
|
+
const processorChannel = (channel) => {
|
|
204
|
+
switch (channel) {
|
|
205
|
+
case 0 /* TextureOutputChannel.R */:
|
|
206
|
+
return TextureChannel.R;
|
|
207
|
+
case 1 /* TextureOutputChannel.G */:
|
|
208
|
+
return TextureChannel.G;
|
|
209
|
+
case 2 /* TextureOutputChannel.B */:
|
|
210
|
+
return TextureChannel.B;
|
|
211
|
+
case 3 /* TextureOutputChannel.A */:
|
|
212
|
+
return TextureChannel.A;
|
|
213
|
+
default:
|
|
214
|
+
return TextureChannel.RGBA;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
const processorColorSpace = (descriptor) => descriptor.sourceColorSpace === 1 /* USDTextureColorSpace.Raw */ ? TextureColorSpace.Linear : TextureColorSpace.SRGB;
|
|
218
|
+
const scalarTextureIsLinear = (binding) => binding.descriptor.sourceColorSpace === 1 /* USDTextureColorSpace.Raw */;
|
|
219
|
+
const valueTransformIs = (descriptor, scale, bias) => scale.every((value, index) => descriptor.scale[index] === value) && bias.every((value, index) => descriptor.bias[index] === value);
|
|
220
|
+
const trackProcessedTexture = (texture) => {
|
|
221
|
+
trackAsset(container.textures, texture);
|
|
222
|
+
return texture;
|
|
223
|
+
};
|
|
224
|
+
const processTextureAsync = async (name, binding, scale, bias, channel = binding.channel, preserveRange = false) => {
|
|
225
|
+
const source = binding.descriptor;
|
|
226
|
+
const size = source.texture.getSize();
|
|
227
|
+
const supportsMipMaps = !scene.getEngine().needPOTTextures || ((size.width & (size.width - 1)) === 0 && (size.height & (size.height - 1)) === 0);
|
|
228
|
+
const outputOptions = {
|
|
229
|
+
textureType: preserveRange ? processedTextureType : Constants.TEXTURETYPE_UNSIGNED_BYTE,
|
|
230
|
+
samplingMode: supportsMipMaps ? Constants.TEXTURE_TRILINEAR_SAMPLINGMODE : Constants.TEXTURE_BILINEAR_SAMPLINGMODE,
|
|
231
|
+
generateMipMaps: supportsMipMaps,
|
|
232
|
+
};
|
|
233
|
+
if (preserveRange &&
|
|
234
|
+
processedTextureType === Constants.TEXTURETYPE_UNSIGNED_BYTE &&
|
|
235
|
+
scale.slice(0, 3).some((value, index) => Math.min(bias[index], bias[index] + value) < 0)) {
|
|
236
|
+
throw new Error(`USD texture processing for '${name}' requires a floating-point render target to preserve signed values.`);
|
|
237
|
+
}
|
|
238
|
+
const key = `${source.id}:${channel}:${scale.join(",")}:${bias.join(",")}:${preserveRange}`;
|
|
239
|
+
const cached = processedTextures.get(key);
|
|
240
|
+
if (cached) {
|
|
241
|
+
return await cached;
|
|
242
|
+
}
|
|
243
|
+
const processing = (async () => {
|
|
244
|
+
const a = new Color4(bias[0], bias[1], bias[2], bias[3]);
|
|
245
|
+
const b = new Color4(bias[0] + scale[0], bias[1] + scale[1], bias[2] + scale[2], bias[3] + scale[3]);
|
|
246
|
+
const previousBlockEntityCollection = scene._blockEntityCollection;
|
|
247
|
+
scene._blockEntityCollection = true;
|
|
248
|
+
let processingPromise;
|
|
249
|
+
try {
|
|
250
|
+
processingPromise = LerpTexturesAsync(name, CreateFactorOperand(a), CreateFactorOperand(b), CreateTextureOperand(source.texture, processorChannel(channel), processorColorSpace(source)), scene, TextureColorSpace.Linear, undefined, outputOptions);
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
scene._blockEntityCollection = previousBlockEntityCollection;
|
|
254
|
+
}
|
|
255
|
+
const processed = await processingPromise;
|
|
256
|
+
if (!processed.texture) {
|
|
257
|
+
throw new Error(`USD texture processing for '${name}' did not produce a texture.`);
|
|
258
|
+
}
|
|
259
|
+
if (rollingBack || signal?.aborted) {
|
|
260
|
+
processed.dispose?.();
|
|
261
|
+
if (signal?.aborted) {
|
|
262
|
+
signal.throwIfAborted();
|
|
263
|
+
}
|
|
264
|
+
throw new Error("USD materialization was rolled back.");
|
|
265
|
+
}
|
|
266
|
+
if (!assetContainer) {
|
|
267
|
+
scene.addTexture(processed.texture);
|
|
268
|
+
}
|
|
269
|
+
const texture = trackProcessedTexture(processed.texture);
|
|
270
|
+
texture.gammaSpace = false;
|
|
271
|
+
const transformedTexture = texture;
|
|
272
|
+
transformedTexture.uRotationCenter = source.texture.uRotationCenter;
|
|
273
|
+
transformedTexture.vRotationCenter = source.texture.vRotationCenter;
|
|
274
|
+
transformedTexture.wRotationCenter = source.texture.wRotationCenter;
|
|
275
|
+
transformedTexture.homogeneousRotationInUVTransform = source.texture.homogeneousRotationInUVTransform;
|
|
276
|
+
return texture;
|
|
277
|
+
})();
|
|
278
|
+
processedTextures.set(key, processing);
|
|
279
|
+
try {
|
|
280
|
+
return await processing;
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
processedTextures.delete(key);
|
|
284
|
+
throw error;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
const processScalarTextureAsync = async (name, binding) => {
|
|
288
|
+
const index = channelIndex(binding.channel);
|
|
289
|
+
const scale = binding.descriptor.scale[index];
|
|
290
|
+
const bias = binding.descriptor.bias[index];
|
|
291
|
+
return await processTextureAsync(name, binding, [scale, scale, scale, 1], [bias, bias, bias, 0], binding.channel);
|
|
292
|
+
};
|
|
293
|
+
const applyMaterialTextureBindingsAsync = async (bindings) => {
|
|
294
|
+
const { material, normalScale, base, opacity, normal, metallic, roughness, occlusion, emissive } = bindings;
|
|
295
|
+
if (base) {
|
|
296
|
+
if (base.channel !== 4 /* TextureOutputChannel.RGB */) {
|
|
297
|
+
throw new Error("A USD base-color texture must use the RGB output.");
|
|
298
|
+
}
|
|
299
|
+
material.albedoColor = Color3.White();
|
|
300
|
+
material.albedoTexture = valueTransformIs(base.descriptor, [1, 1, 1, 1], [0, 0, 0, 0])
|
|
301
|
+
? base.descriptor.texture
|
|
302
|
+
: await processTextureAsync(`${material.name} base color`, base, base.descriptor.scale, base.descriptor.bias);
|
|
303
|
+
}
|
|
304
|
+
if (emissive) {
|
|
305
|
+
if (emissive.channel !== 4 /* TextureOutputChannel.RGB */) {
|
|
306
|
+
throw new Error("A USD emissive texture must use the RGB output.");
|
|
307
|
+
}
|
|
308
|
+
const descriptor = emissive.descriptor;
|
|
309
|
+
const zeroBias = descriptor.bias.slice(0, 3).every((value) => value === 0);
|
|
310
|
+
if (zeroBias) {
|
|
311
|
+
material.emissiveColor = new Color3(descriptor.scale[0], descriptor.scale[1], descriptor.scale[2]);
|
|
312
|
+
material.emissiveTexture = descriptor.texture;
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
const factors = Array.from({ length: 3 }, (_, index) => Math.max(1, Math.abs(descriptor.bias[index]), Math.abs(descriptor.bias[index] + descriptor.scale[index])));
|
|
316
|
+
const scale = descriptor.scale.map((value, index) => (index < 3 ? value / factors[index] : value));
|
|
317
|
+
const bias = descriptor.bias.map((value, index) => (index < 3 ? value / factors[index] : value));
|
|
318
|
+
material.emissiveColor = new Color3(factors[0], factors[1], factors[2]);
|
|
319
|
+
material.emissiveTexture = await processTextureAsync(`${material.name} emissive`, emissive, scale, bias, emissive.channel, true);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (normal) {
|
|
323
|
+
if (normal.channel !== 4 /* TextureOutputChannel.RGB */) {
|
|
324
|
+
throw new Error("A USD normal texture must use the RGB output.");
|
|
325
|
+
}
|
|
326
|
+
const canonicalNormal = normal.descriptor.sourceColorSpace === 1 /* USDTextureColorSpace.Raw */ && valueTransformIs(normal.descriptor, [2, 2, 2, 1], [-1, -1, -1, 0]);
|
|
327
|
+
if (canonicalNormal) {
|
|
328
|
+
material.bumpTexture = normal.descriptor.texture;
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
const scale = Array.from(normal.descriptor.scale, (value) => value * 0.5);
|
|
332
|
+
const bias = Array.from(normal.descriptor.bias, (value, index) => (index < 3 ? (value + 1) * 0.5 : value));
|
|
333
|
+
material.bumpTexture = await processTextureAsync(`${material.name} normal`, normal, scale, bias);
|
|
334
|
+
}
|
|
335
|
+
material.bumpTexture.gammaSpace = false;
|
|
336
|
+
material.bumpTexture.level = normalScale;
|
|
337
|
+
}
|
|
338
|
+
const packedMetallicRoughness = metallic &&
|
|
339
|
+
roughness &&
|
|
340
|
+
metallic.descriptor === roughness.descriptor &&
|
|
341
|
+
(metallic.channel === 0 /* TextureOutputChannel.R */ || metallic.channel === 2 /* TextureOutputChannel.B */) &&
|
|
342
|
+
(roughness.channel === 1 /* TextureOutputChannel.G */ || roughness.channel === 3 /* TextureOutputChannel.A */) &&
|
|
343
|
+
scalarTextureIsLinear(metallic) &&
|
|
344
|
+
metallic.descriptor.bias[channelIndex(metallic.channel)] === 0 &&
|
|
345
|
+
roughness.descriptor.bias[channelIndex(roughness.channel)] === 0;
|
|
346
|
+
let packedOcclusion = false;
|
|
347
|
+
if (packedMetallicRoughness) {
|
|
348
|
+
const descriptor = metallic.descriptor;
|
|
349
|
+
material.metallicTexture = descriptor.texture;
|
|
350
|
+
material.metallic = (material.metallic ?? 1) * descriptor.scale[channelIndex(metallic.channel)];
|
|
351
|
+
material.roughness = (material.roughness ?? 1) * descriptor.scale[channelIndex(roughness.channel)];
|
|
352
|
+
material.useRoughnessFromMetallicTextureAlpha = roughness.channel === 3 /* TextureOutputChannel.A */;
|
|
353
|
+
material.useRoughnessFromMetallicTextureGreen = roughness.channel === 1 /* TextureOutputChannel.G */;
|
|
354
|
+
material.useMetallnessFromMetallicTextureBlue = metallic.channel === 2 /* TextureOutputChannel.B */;
|
|
355
|
+
packedOcclusion =
|
|
356
|
+
occlusion?.descriptor === descriptor &&
|
|
357
|
+
occlusion.channel === 0 /* TextureOutputChannel.R */ &&
|
|
358
|
+
descriptor.scale[0 /* TextureOutputChannel.R */] === 1 &&
|
|
359
|
+
descriptor.bias[0 /* TextureOutputChannel.R */] === 0;
|
|
360
|
+
material.useAmbientOcclusionFromMetallicTextureRed = packedOcclusion;
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
if (metallic) {
|
|
364
|
+
const index = channelIndex(metallic.channel);
|
|
365
|
+
const direct = scalarTextureIsLinear(metallic) &&
|
|
366
|
+
(metallic.channel === 0 /* TextureOutputChannel.R */ || metallic.channel === 2 /* TextureOutputChannel.B */) &&
|
|
367
|
+
metallic.descriptor.bias[index] === 0;
|
|
368
|
+
material.metallicTexture = direct ? metallic.descriptor.texture : await processScalarTextureAsync(`${material.name} metallic`, metallic);
|
|
369
|
+
material.useRoughnessFromMetallicTextureAlpha = false;
|
|
370
|
+
material.useRoughnessFromMetallicTextureGreen = false;
|
|
371
|
+
material.useMetallnessFromMetallicTextureBlue = direct && metallic.channel === 2 /* TextureOutputChannel.B */;
|
|
372
|
+
material.metallic = direct ? (material.metallic ?? 1) * metallic.descriptor.scale[index] : 1;
|
|
373
|
+
}
|
|
374
|
+
if (roughness) {
|
|
375
|
+
const index = channelIndex(roughness.channel);
|
|
376
|
+
const direct = scalarTextureIsLinear(roughness) && roughness.channel === 0 /* TextureOutputChannel.R */ && roughness.descriptor.bias[index] === 0;
|
|
377
|
+
material.microSurfaceTexture = direct ? roughness.descriptor.texture : await processScalarTextureAsync(`${material.name} roughness`, roughness);
|
|
378
|
+
material.microSurfaceTexture.gammaSpace = direct ? roughness.descriptor.texture.gammaSpace : false;
|
|
379
|
+
material.roughness = direct ? (material.roughness ?? 1) * roughness.descriptor.scale[index] : 1;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (occlusion && !packedOcclusion) {
|
|
383
|
+
const index = channelIndex(occlusion.channel);
|
|
384
|
+
const direct = scalarTextureIsLinear(occlusion) &&
|
|
385
|
+
occlusion.channel === 0 /* TextureOutputChannel.R */ &&
|
|
386
|
+
occlusion.descriptor.scale[index] === 1 &&
|
|
387
|
+
occlusion.descriptor.bias[index] === 0;
|
|
388
|
+
material.ambientTexture = direct ? occlusion.descriptor.texture : await processScalarTextureAsync(`${material.name} occlusion`, occlusion);
|
|
389
|
+
material.useAmbientInGrayScale = true;
|
|
390
|
+
}
|
|
391
|
+
if (opacity) {
|
|
392
|
+
if (base &&
|
|
393
|
+
material.albedoTexture &&
|
|
394
|
+
opacity.descriptor === base.descriptor &&
|
|
395
|
+
opacity.channel === 3 /* TextureOutputChannel.A */ &&
|
|
396
|
+
opacity.descriptor.scale[3 /* TextureOutputChannel.A */] === 1 &&
|
|
397
|
+
opacity.descriptor.bias[3 /* TextureOutputChannel.A */] === 0) {
|
|
398
|
+
material.albedoTexture.hasAlpha = true;
|
|
399
|
+
material.useAlphaFromAlbedoTexture = true;
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
const direct = opacity.channel === 3 /* TextureOutputChannel.A */ && opacity.descriptor.scale[3 /* TextureOutputChannel.A */] === 1 && opacity.descriptor.bias[3 /* TextureOutputChannel.A */] === 0;
|
|
403
|
+
material.opacityTexture = direct ? opacity.descriptor.texture : await processScalarTextureAsync(`${material.name} opacity`, opacity);
|
|
404
|
+
material.opacityTexture.gammaSpace = direct ? opacity.descriptor.texture.gammaSpace : false;
|
|
405
|
+
material.opacityTexture.getAlphaFromRGB = !direct;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const doubleSidedVariant = doubleSidedMaterials.get(bindings.id);
|
|
409
|
+
if (doubleSidedVariant) {
|
|
410
|
+
doubleSidedVariant.albedoColor.copyFrom(material.albedoColor);
|
|
411
|
+
doubleSidedVariant.albedoTexture = material.albedoTexture;
|
|
412
|
+
doubleSidedVariant.emissiveColor.copyFrom(material.emissiveColor);
|
|
413
|
+
doubleSidedVariant.emissiveTexture = material.emissiveTexture;
|
|
414
|
+
doubleSidedVariant.bumpTexture = material.bumpTexture;
|
|
415
|
+
doubleSidedVariant.metallic = material.metallic;
|
|
416
|
+
doubleSidedVariant.roughness = material.roughness;
|
|
417
|
+
doubleSidedVariant.metallicTexture = material.metallicTexture;
|
|
418
|
+
doubleSidedVariant.microSurfaceTexture = material.microSurfaceTexture;
|
|
419
|
+
doubleSidedVariant.ambientTexture = material.ambientTexture;
|
|
420
|
+
doubleSidedVariant.opacityTexture = material.opacityTexture;
|
|
421
|
+
doubleSidedVariant.alpha = material.alpha;
|
|
422
|
+
doubleSidedVariant.useAlphaFromAlbedoTexture = material.useAlphaFromAlbedoTexture;
|
|
423
|
+
doubleSidedVariant.useRoughnessFromMetallicTextureAlpha = material.useRoughnessFromMetallicTextureAlpha;
|
|
424
|
+
doubleSidedVariant.useRoughnessFromMetallicTextureGreen = material.useRoughnessFromMetallicTextureGreen;
|
|
425
|
+
doubleSidedVariant.useMetallnessFromMetallicTextureBlue = material.useMetallnessFromMetallicTextureBlue;
|
|
426
|
+
doubleSidedVariant.useAmbientOcclusionFromMetallicTextureRed = material.useAmbientOcclusionFromMetallicTextureRed;
|
|
427
|
+
doubleSidedVariant.useAmbientInGrayScale = material.useAmbientInGrayScale;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
140
430
|
try {
|
|
141
431
|
const previousBlockEntityCollection = scene._blockEntityCollection;
|
|
142
432
|
if (!addToScene) {
|
|
@@ -163,6 +453,9 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
163
453
|
}
|
|
164
454
|
case 2 /* Command.Texture */: {
|
|
165
455
|
const id = payload.u32();
|
|
456
|
+
if (textures.has(id)) {
|
|
457
|
+
throw new Error(`Duplicate USD texture ${id}.`);
|
|
458
|
+
}
|
|
166
459
|
const nameOffset = payload.u32();
|
|
167
460
|
const nameLength = payload.u32();
|
|
168
461
|
const mime = mimeType(payload.u32());
|
|
@@ -172,9 +465,19 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
172
465
|
const transformOffset = payload.u32();
|
|
173
466
|
const wrapU = payload.u32();
|
|
174
467
|
const wrapV = payload.u32();
|
|
468
|
+
const sourceColorSpace = payload.u32();
|
|
469
|
+
const valueTransformOffset = payload.u32();
|
|
175
470
|
assertRange(dataBuffer, transformOffset, 5, 4, "texture transform");
|
|
471
|
+
assertRange(dataBuffer, valueTransformOffset, 8, 4, "texture value transform");
|
|
176
472
|
assertRange(dataBuffer, imageOffset, imageLength, 1, "texture image");
|
|
473
|
+
if (sourceColorSpace < 0 /* USDTextureColorSpace.Auto */ || sourceColorSpace > 2 /* USDTextureColorSpace.SRGB */) {
|
|
474
|
+
throw new Error(`Invalid USD texture color space ${sourceColorSpace}.`);
|
|
475
|
+
}
|
|
177
476
|
const transform = new Float32Array(dataBuffer, transformOffset, 5);
|
|
477
|
+
const valueTransform = new Float32Array(dataBuffer, valueTransformOffset, 8);
|
|
478
|
+
if (![...transform, ...valueTransform].every(Number.isFinite)) {
|
|
479
|
+
throw new Error(`USD texture ${id} has a non-finite transform.`);
|
|
480
|
+
}
|
|
178
481
|
const bytes = new Uint8Array(dataBuffer, imageOffset, imageLength);
|
|
179
482
|
const url = URL.createObjectURL(new Blob([bytes], { type: mime }));
|
|
180
483
|
textureUrls.add(url);
|
|
@@ -202,7 +505,14 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
202
505
|
texture.wAng = -transform[4];
|
|
203
506
|
texture.wrapU = wrapMode(wrapU);
|
|
204
507
|
texture.wrapV = wrapMode(wrapV);
|
|
205
|
-
|
|
508
|
+
texture.gammaSpace = sourceColorSpace !== 1 /* USDTextureColorSpace.Raw */;
|
|
509
|
+
textures.set(id, {
|
|
510
|
+
id,
|
|
511
|
+
texture,
|
|
512
|
+
sourceColorSpace,
|
|
513
|
+
scale: valueTransform.subarray(0, 4),
|
|
514
|
+
bias: valueTransform.subarray(4, 8),
|
|
515
|
+
});
|
|
206
516
|
break;
|
|
207
517
|
}
|
|
208
518
|
case 3 /* Command.Material */: {
|
|
@@ -216,15 +526,8 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
216
526
|
const normalScale = payload.f32();
|
|
217
527
|
const alphaCutoff = payload.f32();
|
|
218
528
|
const flags = payload.u32();
|
|
219
|
-
const
|
|
220
|
-
const
|
|
221
|
-
const normalTexture = payload.u32();
|
|
222
|
-
const ormTexture = payload.u32();
|
|
223
|
-
const emissiveTexture = payload.u32();
|
|
224
|
-
const opacityChannel = payload.u32();
|
|
225
|
-
const roughnessChannel = payload.u32();
|
|
226
|
-
const metallicChannel = payload.u32();
|
|
227
|
-
const occlusionChannel = payload.u32();
|
|
529
|
+
const textureIds = Array.from({ length: 7 }, () => payload.u32());
|
|
530
|
+
const textureChannels = Array.from({ length: 7 }, () => payload.u32());
|
|
228
531
|
assertRange(dataBuffer, baseOffset, 4, 4, "material base color");
|
|
229
532
|
assertRange(dataBuffer, emissiveOffset, 3, 4, "material emissive color");
|
|
230
533
|
const base = new Float32Array(dataBuffer, baseOffset, 4);
|
|
@@ -248,40 +551,18 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
248
551
|
material.transparencyMode = 1;
|
|
249
552
|
material.alphaCutOff = alphaCutoff;
|
|
250
553
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
if (normalTexture !== MISSING_OFFSET) {
|
|
266
|
-
material.bumpTexture = textures.get(normalTexture) ?? null;
|
|
267
|
-
if (material.bumpTexture) {
|
|
268
|
-
material.bumpTexture.gammaSpace = false;
|
|
269
|
-
material.bumpTexture.level = normalScale;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
if (ormTexture !== MISSING_OFFSET) {
|
|
273
|
-
material.metallicTexture = textures.get(ormTexture) ?? null;
|
|
274
|
-
if (material.metallicTexture) {
|
|
275
|
-
material.metallicTexture.gammaSpace = false;
|
|
276
|
-
material.useRoughnessFromMetallicTextureAlpha = roughnessChannel === 3;
|
|
277
|
-
material.useRoughnessFromMetallicTextureGreen = roughnessChannel === 1;
|
|
278
|
-
material.useMetallnessFromMetallicTextureBlue = metallicChannel === 2;
|
|
279
|
-
material.useAmbientOcclusionFromMetallicTextureRed = occlusionChannel === 0;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
if (emissiveTexture !== MISSING_OFFSET) {
|
|
283
|
-
material.emissiveTexture = textures.get(emissiveTexture) ?? null;
|
|
284
|
-
}
|
|
554
|
+
materialTextureBindings.push({
|
|
555
|
+
id,
|
|
556
|
+
material,
|
|
557
|
+
normalScale,
|
|
558
|
+
base: binding(textureIds[0], textureChannels[0], "base-color texture"),
|
|
559
|
+
opacity: binding(textureIds[1], textureChannels[1], "opacity texture"),
|
|
560
|
+
normal: binding(textureIds[2], textureChannels[2], "normal texture"),
|
|
561
|
+
metallic: binding(textureIds[3], textureChannels[3], "metallic texture"),
|
|
562
|
+
roughness: binding(textureIds[4], textureChannels[4], "roughness texture"),
|
|
563
|
+
occlusion: binding(textureIds[5], textureChannels[5], "occlusion texture"),
|
|
564
|
+
emissive: binding(textureIds[6], textureChannels[6], "emissive texture"),
|
|
565
|
+
});
|
|
285
566
|
materials.set(id, material);
|
|
286
567
|
break;
|
|
287
568
|
}
|
|
@@ -317,19 +598,20 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
317
598
|
const skeleton = new Skeleton(stringAt(dataBuffer, nameOffset, nameLength), `usd-skeleton-${id}`, scene);
|
|
318
599
|
trackAsset(container.skeletons, skeleton);
|
|
319
600
|
const jointView = new DataView(dataBuffer);
|
|
320
|
-
assertRange(dataBuffer, jointsOffset, jointCount *
|
|
601
|
+
assertRange(dataBuffer, jointsOffset, jointCount * 6, 4, "skeleton joints");
|
|
321
602
|
const created = [];
|
|
322
603
|
for (let index = 0; index < jointCount; ++index) {
|
|
323
|
-
const offset = jointsOffset + index *
|
|
604
|
+
const offset = jointsOffset + index * 24;
|
|
324
605
|
const parentIndex = jointView.getUint32(offset, true);
|
|
325
606
|
const boneId = jointView.getUint32(offset + 4, true);
|
|
326
607
|
const jointNameOffset = jointView.getUint32(offset + 8, true);
|
|
327
608
|
const jointNameLength = jointView.getUint32(offset + 12, true);
|
|
328
|
-
const
|
|
609
|
+
const restMatrixOffset = jointView.getUint32(offset + 16, true);
|
|
610
|
+
const bindMatrixOffset = jointView.getUint32(offset + 20, true);
|
|
329
611
|
if (parentIndex !== MISSING_OFFSET && parentIndex >= index) {
|
|
330
612
|
throw new Error(`Skeleton ${id} has an invalid parent joint index.`);
|
|
331
613
|
}
|
|
332
|
-
const bone = new Bone(stringAt(dataBuffer, jointNameOffset, jointNameLength), skeleton, parentIndex === MISSING_OFFSET ? null : created[parentIndex], matrixAt(dataBuffer,
|
|
614
|
+
const bone = new Bone(stringAt(dataBuffer, jointNameOffset, jointNameLength), skeleton, parentIndex === MISSING_OFFSET ? null : created[parentIndex], matrixAt(dataBuffer, restMatrixOffset), matrixAt(dataBuffer, restMatrixOffset), matrixAt(dataBuffer, bindMatrixOffset), index);
|
|
333
615
|
created.push(bone);
|
|
334
616
|
bones.set(boneId, bone);
|
|
335
617
|
}
|
|
@@ -439,6 +721,41 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
439
721
|
meshes.set(id, mesh);
|
|
440
722
|
break;
|
|
441
723
|
}
|
|
724
|
+
case 12 /* Command.MorphTarget */: {
|
|
725
|
+
const id = payload.u32();
|
|
726
|
+
const meshId = payload.u32();
|
|
727
|
+
const nameOffset = payload.u32();
|
|
728
|
+
const nameLength = payload.u32();
|
|
729
|
+
const vertexCount = payload.u32();
|
|
730
|
+
const positionsOffset = payload.u32();
|
|
731
|
+
const normalsOffset = payload.u32();
|
|
732
|
+
const influence = payload.f32();
|
|
733
|
+
const mesh = meshes.get(meshId);
|
|
734
|
+
if (!mesh) {
|
|
735
|
+
throw new Error(`Morph target references missing mesh ${meshId}.`);
|
|
736
|
+
}
|
|
737
|
+
if (morphTargets.has(id) || vertexCount !== mesh.getTotalVertices() || !Number.isFinite(influence)) {
|
|
738
|
+
throw new Error(`Morph target ${id} has invalid metadata.`);
|
|
739
|
+
}
|
|
740
|
+
assertRange(dataBuffer, positionsOffset, vertexCount * 3, 4, "morph target positions");
|
|
741
|
+
let manager = morphTargetManagers.get(meshId);
|
|
742
|
+
if (!manager) {
|
|
743
|
+
manager = new MorphTargetManager(scene, mesh.name);
|
|
744
|
+
manager.areUpdatesFrozen = true;
|
|
745
|
+
trackAsset(container.morphTargetManagers, manager);
|
|
746
|
+
morphTargetManagers.set(meshId, manager);
|
|
747
|
+
}
|
|
748
|
+
const target = new MorphTarget(stringAt(dataBuffer, nameOffset, nameLength), influence, scene, manager);
|
|
749
|
+
target.id = `usd-morph-target-${id}`;
|
|
750
|
+
target.setPositions(new Float32Array(dataBuffer, positionsOffset, vertexCount * 3));
|
|
751
|
+
if (normalsOffset !== MISSING_OFFSET) {
|
|
752
|
+
assertRange(dataBuffer, normalsOffset, vertexCount * 3, 4, "morph target normals");
|
|
753
|
+
target.setNormals(new Float32Array(dataBuffer, normalsOffset, vertexCount * 3));
|
|
754
|
+
}
|
|
755
|
+
manager.addTarget(target);
|
|
756
|
+
morphTargets.set(id, target);
|
|
757
|
+
break;
|
|
758
|
+
}
|
|
442
759
|
case 10 /* Command.AnalyticPrimitive */: {
|
|
443
760
|
const id = payload.u32();
|
|
444
761
|
const nodeId = payload.u32();
|
|
@@ -525,11 +842,32 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
525
842
|
if (!source) {
|
|
526
843
|
throw new Error(`Instance references missing mesh ${sourceId}.`);
|
|
527
844
|
}
|
|
845
|
+
if (thinInstanceSources.has(sourceId)) {
|
|
846
|
+
throw new Error(`Mesh ${sourceId} cannot mix classic and thin instances.`);
|
|
847
|
+
}
|
|
848
|
+
classicInstanceSources.add(sourceId);
|
|
528
849
|
const instance = source.createInstance(stringAt(dataBuffer, nameOffset, nameLength));
|
|
529
850
|
trackAsset(container.meshes, instance);
|
|
530
851
|
instance.parent = nodes.get(nodeId) ?? root ?? null;
|
|
531
852
|
break;
|
|
532
853
|
}
|
|
854
|
+
case 11 /* Command.ThinInstances */: {
|
|
855
|
+
const sourceId = payload.u32();
|
|
856
|
+
const transformsOffset = payload.u32();
|
|
857
|
+
const instanceCount = payload.u32();
|
|
858
|
+
const source = meshes.get(sourceId);
|
|
859
|
+
if (!source) {
|
|
860
|
+
throw new Error(`Thin instances reference missing mesh ${sourceId}.`);
|
|
861
|
+
}
|
|
862
|
+
if (thinInstanceSources.has(sourceId) || classicInstanceSources.has(sourceId)) {
|
|
863
|
+
throw new Error(`Mesh ${sourceId} has duplicate or mixed thin instances.`);
|
|
864
|
+
}
|
|
865
|
+
assertRange(dataBuffer, transformsOffset, instanceCount * 16, 4, "thin instance transforms");
|
|
866
|
+
source.thinInstanceSetBuffer("matrix", new Float32Array(dataBuffer, transformsOffset, instanceCount * 16), 16, true);
|
|
867
|
+
source.thinInstanceEnablePicking = true;
|
|
868
|
+
thinInstanceSources.add(sourceId);
|
|
869
|
+
break;
|
|
870
|
+
}
|
|
533
871
|
case 9 /* Command.Animation */: {
|
|
534
872
|
const targetKind = payload.u32();
|
|
535
873
|
const targetId = payload.u32();
|
|
@@ -539,20 +877,25 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
539
877
|
const timesOffset = payload.u32();
|
|
540
878
|
const valuesOffset = payload.u32();
|
|
541
879
|
const stride = payload.u32();
|
|
542
|
-
if (targetKind !== 0 /* AnimationTarget.Node */ && targetKind !== 1 /* AnimationTarget.Bone */) {
|
|
880
|
+
if (targetKind !== 0 /* AnimationTarget.Node */ && targetKind !== 1 /* AnimationTarget.Bone */ && targetKind !== 2 /* AnimationTarget.MorphTarget */) {
|
|
543
881
|
throw new Error(`Invalid animation target kind ${targetKind}.`);
|
|
544
882
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
883
|
+
if ((targetKind === 2 /* AnimationTarget.MorphTarget */) !== (property === 4 /* AnimationProperty.Influence */)) {
|
|
884
|
+
throw new Error(`Invalid animation property ${property} for target kind ${targetKind}.`);
|
|
885
|
+
}
|
|
886
|
+
const expectedStride = property === 4 /* AnimationProperty.Influence */
|
|
887
|
+
? 1
|
|
888
|
+
: property === 0 /* AnimationProperty.Position */ || property === 2 /* AnimationProperty.Scaling */
|
|
889
|
+
? 3
|
|
890
|
+
: property === 1 /* AnimationProperty.RotationQuaternion */
|
|
891
|
+
? 4
|
|
892
|
+
: property === 3 /* AnimationProperty.Matrix */
|
|
893
|
+
? 16
|
|
894
|
+
: 0;
|
|
552
895
|
if (stride !== expectedStride) {
|
|
553
896
|
throw new Error(`Invalid animation value stride ${stride} for property ${property}.`);
|
|
554
897
|
}
|
|
555
|
-
const target = targetKind === 0 /* AnimationTarget.Node */ ? nodes.get(targetId) : bones.get(targetId);
|
|
898
|
+
const target = targetKind === 0 /* AnimationTarget.Node */ ? nodes.get(targetId) : targetKind === 1 /* AnimationTarget.Bone */ ? bones.get(targetId) : morphTargets.get(targetId);
|
|
556
899
|
if (!target) {
|
|
557
900
|
break;
|
|
558
901
|
}
|
|
@@ -562,14 +905,18 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
562
905
|
? "rotationQuaternion"
|
|
563
906
|
: property === 2 /* AnimationProperty.Scaling */
|
|
564
907
|
? "scaling"
|
|
565
|
-
:
|
|
566
|
-
?
|
|
567
|
-
:
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
908
|
+
: property === 4 /* AnimationProperty.Influence */
|
|
909
|
+
? "influence"
|
|
910
|
+
: targetKind === 0 /* AnimationTarget.Node */
|
|
911
|
+
? NODE_MATRIX_PROPERTY
|
|
912
|
+
: "_matrix";
|
|
913
|
+
const dataType = property === 4 /* AnimationProperty.Influence */
|
|
914
|
+
? Animation.ANIMATIONTYPE_FLOAT
|
|
915
|
+
: property === 1 /* AnimationProperty.RotationQuaternion */
|
|
916
|
+
? Animation.ANIMATIONTYPE_QUATERNION
|
|
917
|
+
: property === 3 /* AnimationProperty.Matrix */
|
|
918
|
+
? Animation.ANIMATIONTYPE_MATRIX
|
|
919
|
+
: Animation.ANIMATIONTYPE_VECTOR3;
|
|
573
920
|
const animation = new Animation(`USD ${propertyName}`, propertyName, timeCodesPerSecond, dataType, Animation.ANIMATIONLOOPMODE_CYCLE);
|
|
574
921
|
assertRange(dataBuffer, timesOffset, keyCount, 4, "animation times");
|
|
575
922
|
assertRange(dataBuffer, valuesOffset, keyCount * stride, 4, "animation values");
|
|
@@ -581,7 +928,9 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
581
928
|
? Quaternion.FromArray(values, index * stride)
|
|
582
929
|
: dataType === Animation.ANIMATIONTYPE_MATRIX
|
|
583
930
|
? Matrix.FromArray(values, index * stride)
|
|
584
|
-
:
|
|
931
|
+
: dataType === Animation.ANIMATIONTYPE_FLOAT
|
|
932
|
+
? values[index * stride]
|
|
933
|
+
: Vector3.FromArray(values, index * stride),
|
|
585
934
|
})));
|
|
586
935
|
let group = animationGroups.get(trackIndex);
|
|
587
936
|
if (!group) {
|
|
@@ -594,46 +943,35 @@ export async function materializeCommandBuffers(scene, commandBuffer, dataBuffer
|
|
|
594
943
|
}
|
|
595
944
|
}
|
|
596
945
|
}
|
|
946
|
+
for (const [meshId, manager] of morphTargetManagers) {
|
|
947
|
+
manager.areUpdatesFrozen = false;
|
|
948
|
+
if (!manager.isUsingTextureForTargets && manager.numTargets <= MorphTargetManager.MaxActiveMorphTargetsInVertexAttributeMode) {
|
|
949
|
+
manager.optimizeInfluencers = false;
|
|
950
|
+
manager.numMaxInfluencers = manager.numTargets;
|
|
951
|
+
}
|
|
952
|
+
meshes.get(meshId).morphTargetManager = manager;
|
|
953
|
+
}
|
|
597
954
|
}
|
|
598
955
|
finally {
|
|
599
956
|
if (!addToScene) {
|
|
600
957
|
scene._blockEntityCollection = previousBlockEntityCollection;
|
|
601
958
|
}
|
|
602
959
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
onAbort = () => reject(signal.reason instanceof Error ? signal.reason : new Error("USD materialization was aborted."));
|
|
608
|
-
if (signal.aborted) {
|
|
609
|
-
onAbort();
|
|
610
|
-
}
|
|
611
|
-
else {
|
|
612
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
613
|
-
}
|
|
614
|
-
});
|
|
615
|
-
try {
|
|
616
|
-
await Promise.race([texturesLoaded, aborted]);
|
|
617
|
-
signal.throwIfAborted();
|
|
618
|
-
}
|
|
619
|
-
finally {
|
|
620
|
-
if (onAbort) {
|
|
621
|
-
signal.removeEventListener("abort", onAbort);
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
else {
|
|
626
|
-
await texturesLoaded;
|
|
627
|
-
}
|
|
960
|
+
await awaitAbortableAsync(Promise.all(textureLoads), signal);
|
|
961
|
+
await awaitAbortableAsync(Promise.all(materialTextureBindings.map(async (bindings) => {
|
|
962
|
+
await applyMaterialTextureBindingsAsync(bindings);
|
|
963
|
+
})), signal);
|
|
628
964
|
for (const { node, parentId } of pendingParents) {
|
|
629
965
|
node.parent = nodes.get(parentId) ?? root ?? null;
|
|
630
966
|
}
|
|
631
967
|
return { container, materializeMs: performance.now() - started };
|
|
632
968
|
}
|
|
633
969
|
catch (error) {
|
|
970
|
+
rollingBack = true;
|
|
634
971
|
// Decode callbacks can arrive after rollback; observe their rejections without
|
|
635
972
|
// delaying cancellation on an image load that may never finish.
|
|
636
973
|
void Promise.allSettled(textureLoads);
|
|
974
|
+
void Promise.allSettled(processedTextures.values());
|
|
637
975
|
container.dispose();
|
|
638
976
|
for (const url of textureUrls) {
|
|
639
977
|
URL.revokeObjectURL(url);
|