@babylonjs/loaders 5.25.0 → 5.26.1
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|