@babylonjs/loaders 5.25.0 → 5.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/glTF/2.0/Extensions/KHR_animation_pointer.d.ts +12 -31
- package/glTF/2.0/Extensions/KHR_animation_pointer.data.d.ts +133 -0
- package/glTF/2.0/Extensions/KHR_animation_pointer.data.js +169 -0
- package/glTF/2.0/Extensions/KHR_animation_pointer.data.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_animation_pointer.js +54 -204
- package/glTF/2.0/Extensions/KHR_animation_pointer.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_lights_punctual.js +2 -1
- package/glTF/2.0/Extensions/KHR_lights_punctual.js.map +1 -1
- package/glTF/2.0/glTFLoader.d.ts +42 -8
- package/glTF/2.0/glTFLoader.js +204 -47
- package/glTF/2.0/glTFLoader.js.map +1 -1
- package/glTF/2.0/glTFLoaderAnimation.d.ts +29 -0
- package/glTF/2.0/glTFLoaderAnimation.js +66 -0
- package/glTF/2.0/glTFLoaderAnimation.js.map +1 -0
- package/glTF/2.0/glTFLoaderExtension.d.ts +14 -1
- package/glTF/2.0/glTFLoaderExtension.js.map +1 -1
- package/glTF/2.0/glTFLoaderInterfaces.d.ts +38 -11
- package/glTF/2.0/glTFLoaderInterfaces.js.map +1 -1
- package/package.json +3 -3
- package/glTF/2.0/Extensions/KHR_animation_pointer.map.d.ts +0 -15
- package/glTF/2.0/Extensions/KHR_animation_pointer.map.js +0 -454
- package/glTF/2.0/Extensions/KHR_animation_pointer.map.js.map +0 -1
- package/glTF/2.0/glTFUtilities.d.ts +0 -7
- package/glTF/2.0/glTFUtilities.js +0 -23
- package/glTF/2.0/glTFUtilities.js.map +0 -1
package/glTF/2.0/glTFLoader.js
CHANGED
@@ -4,6 +4,7 @@ import { Color3 } from "@babylonjs/core/Maths/math.color.js";
|
|
4
4
|
import { Tools } from "@babylonjs/core/Misc/tools.js";
|
5
5
|
import { Camera } from "@babylonjs/core/Cameras/camera.js";
|
6
6
|
import { FreeCamera } from "@babylonjs/core/Cameras/freeCamera.js";
|
7
|
+
import { AnimationKeyInterpolation } from "@babylonjs/core/Animations/animationKey.js";
|
7
8
|
import { AnimationGroup } from "@babylonjs/core/Animations/animationGroup.js";
|
8
9
|
import { Bone } from "@babylonjs/core/Bones/bone.js";
|
9
10
|
import { Skeleton } from "@babylonjs/core/Bones/skeleton.js";
|
@@ -20,6 +21,27 @@ import { GLTFFileLoader, GLTFLoaderState, GLTFLoaderCoordinateSystemMode, GLTFLo
|
|
20
21
|
import { DecodeBase64UrlToBinary, IsBase64DataUrl, LoadFileError } from "@babylonjs/core/Misc/fileTools.js";
|
21
22
|
import { Logger } from "@babylonjs/core/Misc/logger.js";
|
22
23
|
import { BoundingInfo } from "@babylonjs/core/Culling/boundingInfo.js";
|
24
|
+
import { nodeAnimationData } from "./glTFLoaderAnimation.js";
|
25
|
+
// https://stackoverflow.com/a/48218209
|
26
|
+
function mergeDeep(...objects) {
|
27
|
+
const isObject = (obj) => obj && typeof obj === "object";
|
28
|
+
return objects.reduce((prev, obj) => {
|
29
|
+
Object.keys(obj).forEach((key) => {
|
30
|
+
const pVal = prev[key];
|
31
|
+
const oVal = obj[key];
|
32
|
+
if (Array.isArray(pVal) && Array.isArray(oVal)) {
|
33
|
+
prev[key] = pVal.concat(...oVal);
|
34
|
+
}
|
35
|
+
else if (isObject(pVal) && isObject(oVal)) {
|
36
|
+
prev[key] = mergeDeep(pVal, oVal);
|
37
|
+
}
|
38
|
+
else {
|
39
|
+
prev[key] = oVal;
|
40
|
+
}
|
41
|
+
});
|
42
|
+
return prev;
|
43
|
+
}, {});
|
44
|
+
}
|
23
45
|
/**
|
24
46
|
* Helper class for working with arrays when loading the glTF asset
|
25
47
|
*/
|
@@ -49,26 +71,6 @@ export class ArrayItem {
|
|
49
71
|
}
|
50
72
|
}
|
51
73
|
}
|
52
|
-
// https://stackoverflow.com/a/48218209
|
53
|
-
function mergeDeep(...objects) {
|
54
|
-
const isObject = (obj) => obj && typeof obj === "object";
|
55
|
-
return objects.reduce((prev, obj) => {
|
56
|
-
Object.keys(obj).forEach((key) => {
|
57
|
-
const pVal = prev[key];
|
58
|
-
const oVal = obj[key];
|
59
|
-
if (Array.isArray(pVal) && Array.isArray(oVal)) {
|
60
|
-
prev[key] = pVal.concat(...oVal);
|
61
|
-
}
|
62
|
-
else if (isObject(pVal) && isObject(oVal)) {
|
63
|
-
prev[key] = mergeDeep(pVal, oVal);
|
64
|
-
}
|
65
|
-
else {
|
66
|
-
prev[key] = oVal;
|
67
|
-
}
|
68
|
-
});
|
69
|
-
return prev;
|
70
|
-
}, {});
|
71
|
-
}
|
72
74
|
/**
|
73
75
|
* The glTF 2.0 loader
|
74
76
|
*/
|
@@ -1114,6 +1116,7 @@ export class GLTFLoader {
|
|
1114
1116
|
babylonCamera._parentContainer = this._assetContainer;
|
1115
1117
|
this._babylonScene._blockEntityCollection = false;
|
1116
1118
|
babylonCamera.ignoreParentScaling = true;
|
1119
|
+
camera._babylonCamera = babylonCamera;
|
1117
1120
|
babylonCamera.rotation = new Vector3(0, Math.PI, 0);
|
1118
1121
|
switch (camera.type) {
|
1119
1122
|
case "perspective" /* PERSPECTIVE */: {
|
@@ -1146,8 +1149,6 @@ export class GLTFLoader {
|
|
1146
1149
|
GLTFLoader.AddPointerMetadata(babylonCamera, context);
|
1147
1150
|
this._parent.onCameraLoadedObservable.notifyObservers(babylonCamera);
|
1148
1151
|
assign(babylonCamera);
|
1149
|
-
// register the camera to be used later.
|
1150
|
-
camera._babylonCamera = babylonCamera;
|
1151
1152
|
this.logClose();
|
1152
1153
|
return Promise.all(promises).then(() => {
|
1153
1154
|
return babylonCamera;
|
@@ -1177,32 +1178,190 @@ export class GLTFLoader {
|
|
1177
1178
|
* @returns A promise that resolves with the loaded Babylon animation group when the load is complete
|
1178
1179
|
*/
|
1179
1180
|
loadAnimationAsync(context, animation) {
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
continue;
|
1184
|
-
}
|
1185
|
-
// decorate the channel with a KHR_animation_pointer extension.
|
1186
|
-
channel.target.extensions = channel.target.extensions || {};
|
1187
|
-
channel.target.extensions.KHR_animation_pointer = {
|
1188
|
-
pointer: `/nodes/${channel.target.node}/${channel.target.path}`,
|
1189
|
-
};
|
1190
|
-
channel.target.path = "pointer" /* POINTER */;
|
1191
|
-
delete channel.target.node;
|
1192
|
-
// ensure to declare extension used.
|
1193
|
-
this._gltf.extensionsUsed = this._gltf.extensionsUsed || [];
|
1194
|
-
if (this._gltf.extensionsUsed.indexOf(GLTFLoader._KHRAnimationPointerName) === -1) {
|
1195
|
-
this._gltf.extensionsUsed.push(GLTFLoader._KHRAnimationPointerName);
|
1196
|
-
}
|
1181
|
+
const promise = this._extensionsLoadAnimationAsync(context, animation);
|
1182
|
+
if (promise) {
|
1183
|
+
return promise;
|
1197
1184
|
}
|
1198
|
-
// create the animation group to be passed to extension.
|
1199
1185
|
this._babylonScene._blockEntityCollection = !!this._assetContainer;
|
1200
1186
|
const babylonAnimationGroup = new AnimationGroup(animation.name || `animation${animation.index}`, this._babylonScene);
|
1201
1187
|
babylonAnimationGroup._parentContainer = this._assetContainer;
|
1202
1188
|
this._babylonScene._blockEntityCollection = false;
|
1203
1189
|
animation._babylonAnimationGroup = babylonAnimationGroup;
|
1204
|
-
const
|
1205
|
-
|
1190
|
+
const promises = new Array();
|
1191
|
+
ArrayItem.Assign(animation.channels);
|
1192
|
+
ArrayItem.Assign(animation.samplers);
|
1193
|
+
for (const channel of animation.channels) {
|
1194
|
+
promises.push(this._loadAnimationChannelAsync(`${context}/channels/${channel.index}`, context, animation, channel, (babylonTarget, babylonAnimation) => {
|
1195
|
+
babylonTarget.animations = babylonTarget.animations || [];
|
1196
|
+
babylonTarget.animations.push(babylonAnimation);
|
1197
|
+
babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonTarget);
|
1198
|
+
}));
|
1199
|
+
}
|
1200
|
+
return Promise.all(promises).then(() => {
|
1201
|
+
babylonAnimationGroup.normalize(0);
|
1202
|
+
return babylonAnimationGroup;
|
1203
|
+
});
|
1204
|
+
}
|
1205
|
+
/**
|
1206
|
+
* @hidden
|
1207
|
+
* Loads a glTF animation channel.
|
1208
|
+
* @param context The context when loading the asset
|
1209
|
+
* @param animationContext The context of the animation when loading the asset
|
1210
|
+
* @param animation The glTF animation property
|
1211
|
+
* @param channel The glTF animation channel property
|
1212
|
+
* @param onLoad Called for each animation loaded
|
1213
|
+
* @returns A void promise that resolves when the load is complete
|
1214
|
+
*/
|
1215
|
+
_loadAnimationChannelAsync(context, animationContext, animation, channel, onLoad) {
|
1216
|
+
const promise = this._extensionsLoadAnimationChannelAsync(context, animationContext, animation, channel, onLoad);
|
1217
|
+
if (promise) {
|
1218
|
+
return promise;
|
1219
|
+
}
|
1220
|
+
if (channel.target.node == undefined) {
|
1221
|
+
return Promise.resolve();
|
1222
|
+
}
|
1223
|
+
const targetNode = ArrayItem.Get(`${context}/target/node`, this._gltf.nodes, channel.target.node);
|
1224
|
+
// Ignore animations that have no animation targets.
|
1225
|
+
if ((channel.target.path === "weights" /* WEIGHTS */ && !targetNode._numMorphTargets) ||
|
1226
|
+
(channel.target.path !== "weights" /* WEIGHTS */ && !targetNode._babylonTransformNode)) {
|
1227
|
+
return Promise.resolve();
|
1228
|
+
}
|
1229
|
+
let properties;
|
1230
|
+
switch (channel.target.path) {
|
1231
|
+
case "translation" /* TRANSLATION */: {
|
1232
|
+
properties = nodeAnimationData.translation;
|
1233
|
+
break;
|
1234
|
+
}
|
1235
|
+
case "rotation" /* ROTATION */: {
|
1236
|
+
properties = nodeAnimationData.rotation;
|
1237
|
+
break;
|
1238
|
+
}
|
1239
|
+
case "scale" /* SCALE */: {
|
1240
|
+
properties = nodeAnimationData.scale;
|
1241
|
+
break;
|
1242
|
+
}
|
1243
|
+
case "weights" /* WEIGHTS */: {
|
1244
|
+
properties = nodeAnimationData.weights;
|
1245
|
+
break;
|
1246
|
+
}
|
1247
|
+
default: {
|
1248
|
+
throw new Error(`${context}/target/path: Invalid value (${channel.target.path})`);
|
1249
|
+
}
|
1250
|
+
}
|
1251
|
+
const targetInfo = {
|
1252
|
+
target: targetNode,
|
1253
|
+
properties: properties,
|
1254
|
+
};
|
1255
|
+
return this._loadAnimationChannelFromTargetInfoAsync(context, animationContext, animation, channel, targetInfo, onLoad);
|
1256
|
+
}
|
1257
|
+
/**
|
1258
|
+
* @hidden
|
1259
|
+
* Loads a glTF animation channel.
|
1260
|
+
* @param context The context when loading the asset
|
1261
|
+
* @param animationContext The context of the animation when loading the asset
|
1262
|
+
* @param animation The glTF animation property
|
1263
|
+
* @param channel The glTF animation channel property
|
1264
|
+
* @param targetInfo The glTF target and properties
|
1265
|
+
* @param onLoad Called for each animation loaded
|
1266
|
+
* @returns A void promise that resolves when the load is complete
|
1267
|
+
*/
|
1268
|
+
_loadAnimationChannelFromTargetInfoAsync(context, animationContext, animation, channel, targetInfo, onLoad) {
|
1269
|
+
const fps = this.parent.targetFps;
|
1270
|
+
const invfps = 1 / fps;
|
1271
|
+
const sampler = ArrayItem.Get(`${context}/sampler`, animation.samplers, channel.sampler);
|
1272
|
+
return this._loadAnimationSamplerAsync(`${animationContext}/samplers/${channel.sampler}`, sampler).then((data) => {
|
1273
|
+
let numAnimations = 0;
|
1274
|
+
// Extract the corresponding values from the read value.
|
1275
|
+
// GLTF values may be dispatched to several Babylon properties.
|
1276
|
+
// For example, baseColorFactor [`r`, `g`, `b`, `a`] is dispatched to
|
1277
|
+
// - albedoColor as Color3(`r`, `g`, `b`)
|
1278
|
+
// - alpha as `a`
|
1279
|
+
for (const property of targetInfo.properties) {
|
1280
|
+
const stride = property.getStride(targetInfo.target);
|
1281
|
+
const input = data.input;
|
1282
|
+
const output = data.output;
|
1283
|
+
const keys = new Array(input.length);
|
1284
|
+
let outputOffset = 0;
|
1285
|
+
switch (data.interpolation) {
|
1286
|
+
case "STEP" /* STEP */: {
|
1287
|
+
for (let index = 0; index < input.length; index++) {
|
1288
|
+
const value = property.getValue(targetInfo.target, output, outputOffset, 1);
|
1289
|
+
outputOffset += stride;
|
1290
|
+
keys[index] = {
|
1291
|
+
frame: input[index] * fps,
|
1292
|
+
value: value,
|
1293
|
+
interpolation: AnimationKeyInterpolation.STEP,
|
1294
|
+
};
|
1295
|
+
}
|
1296
|
+
break;
|
1297
|
+
}
|
1298
|
+
case "CUBICSPLINE" /* CUBICSPLINE */: {
|
1299
|
+
for (let index = 0; index < input.length; index++) {
|
1300
|
+
const inTangent = property.getValue(targetInfo.target, output, outputOffset, invfps);
|
1301
|
+
outputOffset += stride;
|
1302
|
+
const value = property.getValue(targetInfo.target, output, outputOffset, 1);
|
1303
|
+
outputOffset += stride;
|
1304
|
+
const outTangent = property.getValue(targetInfo.target, output, outputOffset, invfps);
|
1305
|
+
outputOffset += stride;
|
1306
|
+
keys[index] = {
|
1307
|
+
frame: input[index] * fps,
|
1308
|
+
inTangent: inTangent,
|
1309
|
+
value: value,
|
1310
|
+
outTangent: outTangent,
|
1311
|
+
};
|
1312
|
+
}
|
1313
|
+
break;
|
1314
|
+
}
|
1315
|
+
case "LINEAR" /* LINEAR */: {
|
1316
|
+
for (let index = 0; index < input.length; index++) {
|
1317
|
+
const value = property.getValue(targetInfo.target, output, outputOffset, 1);
|
1318
|
+
outputOffset += stride;
|
1319
|
+
keys[index] = {
|
1320
|
+
frame: input[index] * fps,
|
1321
|
+
value: value,
|
1322
|
+
};
|
1323
|
+
}
|
1324
|
+
break;
|
1325
|
+
}
|
1326
|
+
}
|
1327
|
+
if (outputOffset > 0) {
|
1328
|
+
const name = `${animation.name || `animation${animation.index}`}_channel${channel.index}_${numAnimations}`;
|
1329
|
+
property.buildAnimations(targetInfo.target, name, fps, keys, (babylonAnimatable, babylonAnimation) => {
|
1330
|
+
++numAnimations;
|
1331
|
+
onLoad(babylonAnimatable, babylonAnimation);
|
1332
|
+
});
|
1333
|
+
}
|
1334
|
+
}
|
1335
|
+
});
|
1336
|
+
}
|
1337
|
+
_loadAnimationSamplerAsync(context, sampler) {
|
1338
|
+
if (sampler._data) {
|
1339
|
+
return sampler._data;
|
1340
|
+
}
|
1341
|
+
const interpolation = sampler.interpolation || "LINEAR" /* LINEAR */;
|
1342
|
+
switch (interpolation) {
|
1343
|
+
case "STEP" /* STEP */:
|
1344
|
+
case "LINEAR" /* LINEAR */:
|
1345
|
+
case "CUBICSPLINE" /* CUBICSPLINE */: {
|
1346
|
+
break;
|
1347
|
+
}
|
1348
|
+
default: {
|
1349
|
+
throw new Error(`${context}/interpolation: Invalid value (${sampler.interpolation})`);
|
1350
|
+
}
|
1351
|
+
}
|
1352
|
+
const inputAccessor = ArrayItem.Get(`${context}/input`, this._gltf.accessors, sampler.input);
|
1353
|
+
const outputAccessor = ArrayItem.Get(`${context}/output`, this._gltf.accessors, sampler.output);
|
1354
|
+
sampler._data = Promise.all([
|
1355
|
+
this._loadFloatAccessorAsync(`/accessors/${inputAccessor.index}`, inputAccessor),
|
1356
|
+
this._loadFloatAccessorAsync(`/accessors/${outputAccessor.index}`, outputAccessor),
|
1357
|
+
]).then(([inputData, outputData]) => {
|
1358
|
+
return {
|
1359
|
+
input: inputData,
|
1360
|
+
interpolation: interpolation,
|
1361
|
+
output: outputData,
|
1362
|
+
};
|
1363
|
+
});
|
1364
|
+
return sampler._data;
|
1206
1365
|
}
|
1207
1366
|
/**
|
1208
1367
|
* Loads a glTF buffer.
|
@@ -1746,7 +1905,6 @@ export class GLTFLoader {
|
|
1746
1905
|
/**
|
1747
1906
|
* Adds a JSON pointer to the metadata of the Babylon object at `<object>.metadata.gltf.pointers`.
|
1748
1907
|
* @param babylonObject the Babylon object with metadata
|
1749
|
-
* @param babylonObject.metadata
|
1750
1908
|
* @param pointer the JSON pointer
|
1751
1909
|
*/
|
1752
1910
|
static AddPointerMetadata(babylonObject, pointer) {
|
@@ -2003,6 +2161,9 @@ export class GLTFLoader {
|
|
2003
2161
|
_extensionsLoadAnimationAsync(context, animation) {
|
2004
2162
|
return this._applyExtensions(animation, "loadAnimation", (extension) => extension.loadAnimationAsync && extension.loadAnimationAsync(context, animation));
|
2005
2163
|
}
|
2164
|
+
_extensionsLoadAnimationChannelAsync(context, animationContext, animation, channel, onLoad) {
|
2165
|
+
return this._applyExtensions(animation, "loadAnimationChannel", (extension) => extension._loadAnimationChannelAsync && extension._loadAnimationChannelAsync(context, animationContext, animation, channel, onLoad));
|
2166
|
+
}
|
2006
2167
|
_extensionsLoadSkinAsync(context, node, skin) {
|
2007
2168
|
return this._applyExtensions(skin, "loadSkin", (extension) => extension._loadSkinAsync && extension._loadSkinAsync(context, node, skin));
|
2008
2169
|
}
|
@@ -2096,10 +2257,6 @@ export class GLTFLoader {
|
|
2096
2257
|
this._parent._endPerformanceCounter(counterName);
|
2097
2258
|
}
|
2098
2259
|
}
|
2099
|
-
/** @internal */
|
2100
|
-
// note : KHR_animation_pointer is used to load animation in ALL case, turning everything
|
2101
|
-
// into pointer. This is the reason why this value is located here.
|
2102
|
-
GLTFLoader._KHRAnimationPointerName = "KHR_animation_pointer";
|
2103
2260
|
GLTFLoader._RegisteredExtensions = {};
|
2104
2261
|
/**
|
2105
2262
|
* The default glTF sampler.
|