@babylonjs/serializers 5.0.0-rc.6 → 5.0.0
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/OBJ/index.d.ts +1 -1
- package/OBJ/index.js +1 -1
- package/OBJ/objSerializer.d.ts +21 -21
- package/OBJ/objSerializer.js +174 -174
- package/OBJ/objSerializer.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_lights_punctual.d.ts +41 -41
- package/glTF/2.0/Extensions/KHR_lights_punctual.js +189 -189
- package/glTF/2.0/Extensions/KHR_lights_punctual.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.d.ts +24 -24
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.js +90 -90
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_sheen.d.ts +24 -24
- package/glTF/2.0/Extensions/KHR_materials_sheen.js +73 -73
- package/glTF/2.0/Extensions/KHR_materials_sheen.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_unlit.d.ts +20 -20
- package/glTF/2.0/Extensions/KHR_materials_unlit.js +51 -51
- package/glTF/2.0/Extensions/KHR_materials_unlit.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_texture_transform.d.ts +30 -30
- package/glTF/2.0/Extensions/KHR_texture_transform.js +137 -137
- package/glTF/2.0/Extensions/KHR_texture_transform.js.map +1 -1
- package/glTF/2.0/Extensions/index.d.ts +5 -5
- package/glTF/2.0/Extensions/index.js +5 -5
- package/glTF/2.0/glTFAnimation.d.ts +206 -205
- package/glTF/2.0/glTFAnimation.js +852 -852
- package/glTF/2.0/glTFAnimation.js.map +1 -1
- package/glTF/2.0/glTFData.d.ts +19 -19
- package/glTF/2.0/glTFData.js +52 -52
- package/glTF/2.0/glTFExporter.d.ts +456 -455
- package/glTF/2.0/glTFExporter.js +1975 -1972
- package/glTF/2.0/glTFExporter.js.map +1 -1
- package/glTF/2.0/glTFExporterExtension.d.ts +74 -74
- package/glTF/2.0/glTFExporterExtension.js +3 -3
- package/glTF/2.0/glTFExporterExtension.js.map +1 -1
- package/glTF/2.0/glTFMaterialExporter.d.ts +208 -207
- package/glTF/2.0/glTFMaterialExporter.js +1114 -1110
- package/glTF/2.0/glTFMaterialExporter.js.map +1 -1
- package/glTF/2.0/glTFSerializer.d.ts +60 -60
- package/glTF/2.0/glTFSerializer.js +62 -62
- package/glTF/2.0/glTFSerializer.js.map +1 -1
- package/glTF/2.0/glTFUtilities.d.ts +99 -97
- package/glTF/2.0/glTFUtilities.js +196 -196
- package/glTF/2.0/glTFUtilities.js.map +1 -1
- package/glTF/2.0/index.d.ts +8 -8
- package/glTF/2.0/index.js +9 -8
- package/glTF/2.0/index.js.map +1 -1
- package/glTF/2.0/shaders/textureTransform.fragment.d.ts +5 -5
- package/glTF/2.0/shaders/textureTransform.fragment.js +8 -8
- package/glTF/glTFFileExporter.d.ts +20 -20
- package/glTF/glTFFileExporter.js +3 -3
- package/glTF/index.d.ts +2 -2
- package/glTF/index.js +3 -2
- package/glTF/index.js.map +1 -1
- package/index.d.ts +3 -3
- package/index.js +4 -3
- package/index.js.map +1 -1
- package/legacy/legacy-glTF2Serializer.d.ts +2 -2
- package/legacy/legacy-glTF2Serializer.js +44 -43
- package/legacy/legacy-glTF2Serializer.js.map +1 -1
- package/legacy/legacy-objSerializer.d.ts +1 -1
- package/legacy/legacy-objSerializer.js +13 -12
- package/legacy/legacy-objSerializer.js.map +1 -1
- package/legacy/legacy-stlSerializer.d.ts +1 -1
- package/legacy/legacy-stlSerializer.js +13 -12
- package/legacy/legacy-stlSerializer.js.map +1 -1
- package/legacy/legacy.d.ts +4 -4
- package/legacy/legacy.js +6 -5
- package/legacy/legacy.js.map +1 -1
- package/license.md +71 -0
- package/package.json +25 -6
- package/stl/index.d.ts +1 -1
- package/stl/index.js +1 -1
- package/stl/stlSerializer.d.ts +17 -17
- package/stl/stlSerializer.js +107 -107
- package/stl/stlSerializer.js.map +1 -1
|
@@ -1,853 +1,853 @@
|
|
|
1
|
-
import { Vector3, Quaternion } from "@babylonjs/core/Maths/math.vector.js";
|
|
2
|
-
import { Tools } from "@babylonjs/core/Misc/tools.js";
|
|
3
|
-
import { Animation } from "@babylonjs/core/Animations/animation.js";
|
|
4
|
-
import { TransformNode } from "@babylonjs/core/Meshes/transformNode.js";
|
|
5
|
-
import { MorphTarget } from "@babylonjs/core/Morph/morphTarget.js";
|
|
6
|
-
import { Mesh } from "@babylonjs/core/Meshes/mesh.js";
|
|
7
|
-
import { _GLTFUtilities } from "./glTFUtilities.js";
|
|
8
|
-
import { AnimationKeyInterpolation } from "@babylonjs/core/Animations/animationKey.js";
|
|
9
|
-
/**
|
|
10
|
-
* @hidden
|
|
11
|
-
* Enum for handling in tangent and out tangent.
|
|
12
|
-
*/
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
14
|
-
var _TangentType;
|
|
15
|
-
(function (_TangentType) {
|
|
16
|
-
/**
|
|
17
|
-
* Specifies that input tangents are used.
|
|
18
|
-
*/
|
|
19
|
-
_TangentType[_TangentType["INTANGENT"] = 0] = "INTANGENT";
|
|
20
|
-
/**
|
|
21
|
-
* Specifies that output tangents are used.
|
|
22
|
-
*/
|
|
23
|
-
_TangentType[_TangentType["OUTTANGENT"] = 1] = "OUTTANGENT";
|
|
24
|
-
})(_TangentType || (_TangentType = {}));
|
|
25
|
-
/**
|
|
26
|
-
* @hidden
|
|
27
|
-
* Utility class for generating glTF animation data from BabylonJS.
|
|
28
|
-
*/
|
|
29
|
-
var _GLTFAnimation = /** @class */ (function () {
|
|
30
|
-
function _GLTFAnimation() {
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* @ignore
|
|
34
|
-
*
|
|
35
|
-
* Creates glTF channel animation from BabylonJS animation.
|
|
36
|
-
* @param babylonTransformNode - BabylonJS mesh.
|
|
37
|
-
* @param animation - animation.
|
|
38
|
-
* @param animationChannelTargetPath - The target animation channel.
|
|
39
|
-
* @param convertToRightHandedSystem - Specifies if the values should be converted to right-handed.
|
|
40
|
-
* @param useQuaternion - Specifies if quaternions are used.
|
|
41
|
-
* @returns nullable IAnimationData
|
|
42
|
-
*/
|
|
43
|
-
_GLTFAnimation._CreateNodeAnimation = function (babylonTransformNode, animation, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion, animationSampleRate) {
|
|
44
|
-
var inputs = [];
|
|
45
|
-
var outputs = [];
|
|
46
|
-
var keyFrames = animation.getKeys();
|
|
47
|
-
var minMaxKeyFrames = _GLTFAnimation._CalculateMinMaxKeyFrames(keyFrames);
|
|
48
|
-
var interpolationOrBake = _GLTFAnimation._DeduceInterpolation(keyFrames, animationChannelTargetPath, useQuaternion);
|
|
49
|
-
var frameDelta = minMaxKeyFrames.max - minMaxKeyFrames.min;
|
|
50
|
-
var interpolation = interpolationOrBake.interpolationType;
|
|
51
|
-
var shouldBakeAnimation = interpolationOrBake.shouldBakeAnimation;
|
|
52
|
-
if (shouldBakeAnimation) {
|
|
53
|
-
_GLTFAnimation._CreateBakedAnimation(babylonTransformNode, animation, animationChannelTargetPath, minMaxKeyFrames.min, minMaxKeyFrames.max, animation.framePerSecond, animationSampleRate, inputs, outputs, minMaxKeyFrames, convertToRightHandedSystem, useQuaternion);
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
if (interpolation === "LINEAR" /* LINEAR */ || interpolation === "STEP" /* STEP */) {
|
|
57
|
-
_GLTFAnimation._CreateLinearOrStepAnimation(babylonTransformNode, animation, animationChannelTargetPath, frameDelta, inputs, outputs, convertToRightHandedSystem, useQuaternion);
|
|
58
|
-
}
|
|
59
|
-
else if (interpolation === "CUBICSPLINE" /* CUBICSPLINE */) {
|
|
60
|
-
_GLTFAnimation._CreateCubicSplineAnimation(babylonTransformNode, animation, animationChannelTargetPath, frameDelta, inputs, outputs, convertToRightHandedSystem, useQuaternion);
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
_GLTFAnimation._CreateBakedAnimation(babylonTransformNode, animation, animationChannelTargetPath, minMaxKeyFrames.min, minMaxKeyFrames.max, animation.framePerSecond, animationSampleRate, inputs, outputs, minMaxKeyFrames, convertToRightHandedSystem, useQuaternion);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
if (inputs.length && outputs.length) {
|
|
67
|
-
var result = {
|
|
68
|
-
inputs: inputs,
|
|
69
|
-
outputs: outputs,
|
|
70
|
-
samplerInterpolation: interpolation,
|
|
71
|
-
inputsMin: shouldBakeAnimation ? minMaxKeyFrames.min : Tools.FloatRound(minMaxKeyFrames.min / animation.framePerSecond),
|
|
72
|
-
inputsMax: shouldBakeAnimation ? minMaxKeyFrames.max : Tools.FloatRound(minMaxKeyFrames.max / animation.framePerSecond),
|
|
73
|
-
};
|
|
74
|
-
return result;
|
|
75
|
-
}
|
|
76
|
-
return null;
|
|
77
|
-
};
|
|
78
|
-
_GLTFAnimation._DeduceAnimationInfo = function (animation) {
|
|
79
|
-
var animationChannelTargetPath = null;
|
|
80
|
-
var dataAccessorType = "VEC3" /* VEC3 */;
|
|
81
|
-
var useQuaternion = false;
|
|
82
|
-
var property = animation.targetProperty.split(".");
|
|
83
|
-
switch (property[0]) {
|
|
84
|
-
case "scaling": {
|
|
85
|
-
animationChannelTargetPath = "scale" /* SCALE */;
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
case "position": {
|
|
89
|
-
animationChannelTargetPath = "translation" /* TRANSLATION */;
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
case "rotation": {
|
|
93
|
-
dataAccessorType = "VEC4" /* VEC4 */;
|
|
94
|
-
animationChannelTargetPath = "rotation" /* ROTATION */;
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
case "rotationQuaternion": {
|
|
98
|
-
dataAccessorType = "VEC4" /* VEC4 */;
|
|
99
|
-
useQuaternion = true;
|
|
100
|
-
animationChannelTargetPath = "rotation" /* ROTATION */;
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
case "influence": {
|
|
104
|
-
dataAccessorType = "SCALAR" /* SCALAR */;
|
|
105
|
-
animationChannelTargetPath = "weights" /* WEIGHTS */;
|
|
106
|
-
break;
|
|
107
|
-
}
|
|
108
|
-
default: {
|
|
109
|
-
Tools.Error("Unsupported animatable property ".concat(property[0]));
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (animationChannelTargetPath) {
|
|
113
|
-
return { animationChannelTargetPath: animationChannelTargetPath, dataAccessorType: dataAccessorType, useQuaternion: useQuaternion };
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
Tools.Error("animation channel target path and data accessor type could be deduced");
|
|
117
|
-
}
|
|
118
|
-
return null;
|
|
119
|
-
};
|
|
120
|
-
/**
|
|
121
|
-
* @ignore
|
|
122
|
-
* Create node animations from the transform node animations
|
|
123
|
-
* @param babylonNode
|
|
124
|
-
* @param runtimeGLTFAnimation
|
|
125
|
-
* @param idleGLTFAnimations
|
|
126
|
-
* @param nodeMap
|
|
127
|
-
* @param nodes
|
|
128
|
-
* @param binaryWriter
|
|
129
|
-
* @param bufferViews
|
|
130
|
-
* @param accessors
|
|
131
|
-
* @param convertToRightHandedSystem
|
|
132
|
-
* @param animationSampleRate
|
|
133
|
-
*/
|
|
134
|
-
_GLTFAnimation._CreateNodeAnimationFromNodeAnimations = function (babylonNode, runtimeGLTFAnimation, idleGLTFAnimations, nodeMap, nodes, binaryWriter, bufferViews, accessors, convertToRightHandedSystem, animationSampleRate) {
|
|
135
|
-
var glTFAnimation;
|
|
136
|
-
if (babylonNode instanceof TransformNode) {
|
|
137
|
-
if (babylonNode.animations) {
|
|
138
|
-
for (var _i = 0, _a = babylonNode.animations; _i < _a.length; _i++) {
|
|
139
|
-
var animation = _a[_i];
|
|
140
|
-
var animationInfo = _GLTFAnimation._DeduceAnimationInfo(animation);
|
|
141
|
-
if (animationInfo) {
|
|
142
|
-
glTFAnimation = {
|
|
143
|
-
name: animation.name,
|
|
144
|
-
samplers: [],
|
|
145
|
-
channels: [],
|
|
146
|
-
};
|
|
147
|
-
_GLTFAnimation._AddAnimation("".concat(animation.name), animation.hasRunningRuntimeAnimations ? runtimeGLTFAnimation : glTFAnimation, babylonNode, animation, animationInfo.dataAccessorType, animationInfo.animationChannelTargetPath, nodeMap, binaryWriter, bufferViews, accessors, convertToRightHandedSystem, animationInfo.useQuaternion, animationSampleRate);
|
|
148
|
-
if (glTFAnimation.samplers.length && glTFAnimation.channels.length) {
|
|
149
|
-
idleGLTFAnimations.push(glTFAnimation);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
/**
|
|
157
|
-
* @ignore
|
|
158
|
-
* Create individual morph animations from the mesh's morph target animation tracks
|
|
159
|
-
* @param babylonNode
|
|
160
|
-
* @param runtimeGLTFAnimation
|
|
161
|
-
* @param idleGLTFAnimations
|
|
162
|
-
* @param nodeMap
|
|
163
|
-
* @param nodes
|
|
164
|
-
* @param binaryWriter
|
|
165
|
-
* @param bufferViews
|
|
166
|
-
* @param accessors
|
|
167
|
-
* @param convertToRightHandedSystem
|
|
168
|
-
* @param animationSampleRate
|
|
169
|
-
*/
|
|
170
|
-
_GLTFAnimation._CreateMorphTargetAnimationFromMorphTargetAnimations = function (babylonNode, runtimeGLTFAnimation, idleGLTFAnimations, nodeMap, nodes, binaryWriter, bufferViews, accessors, convertToRightHandedSystem, animationSampleRate) {
|
|
171
|
-
var glTFAnimation;
|
|
172
|
-
if (babylonNode instanceof Mesh) {
|
|
173
|
-
var morphTargetManager = babylonNode.morphTargetManager;
|
|
174
|
-
if (morphTargetManager) {
|
|
175
|
-
for (var i = 0; i < morphTargetManager.numTargets; ++i) {
|
|
176
|
-
var morphTarget = morphTargetManager.getTarget(i);
|
|
177
|
-
for (var _i = 0, _a = morphTarget.animations; _i < _a.length; _i++) {
|
|
178
|
-
var animation = _a[_i];
|
|
179
|
-
var combinedAnimation = new Animation("".concat(animation.name), "influence", animation.framePerSecond, animation.dataType, animation.loopMode, animation.enableBlending);
|
|
180
|
-
var combinedAnimationKeys = [];
|
|
181
|
-
var animationKeys = animation.getKeys();
|
|
182
|
-
for (var j = 0; j < animationKeys.length; ++j) {
|
|
183
|
-
var animationKey = animationKeys[j];
|
|
184
|
-
for (var k = 0; k < morphTargetManager.numTargets; ++k) {
|
|
185
|
-
if (k == i) {
|
|
186
|
-
combinedAnimationKeys.push(animationKey);
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
combinedAnimationKeys.push({ frame: animationKey.frame, value: 0 });
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
combinedAnimation.setKeys(combinedAnimationKeys);
|
|
194
|
-
var animationInfo = _GLTFAnimation._DeduceAnimationInfo(combinedAnimation);
|
|
195
|
-
if (animationInfo) {
|
|
196
|
-
glTFAnimation = {
|
|
197
|
-
name: combinedAnimation.name,
|
|
198
|
-
samplers: [],
|
|
199
|
-
channels: [],
|
|
200
|
-
};
|
|
201
|
-
_GLTFAnimation._AddAnimation(animation.name, animation.hasRunningRuntimeAnimations ? runtimeGLTFAnimation : glTFAnimation, babylonNode, combinedAnimation, animationInfo.dataAccessorType, animationInfo.animationChannelTargetPath, nodeMap, binaryWriter, bufferViews, accessors, convertToRightHandedSystem, animationInfo.useQuaternion, animationSampleRate, morphTargetManager.numTargets);
|
|
202
|
-
if (glTFAnimation.samplers.length && glTFAnimation.channels.length) {
|
|
203
|
-
idleGLTFAnimations.push(glTFAnimation);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
/**
|
|
212
|
-
* @ignore
|
|
213
|
-
* Create node and morph animations from the animation groups
|
|
214
|
-
* @param babylonScene
|
|
215
|
-
* @param glTFAnimations
|
|
216
|
-
* @param nodeMap
|
|
217
|
-
* @param nodes
|
|
218
|
-
* @param binaryWriter
|
|
219
|
-
* @param bufferViews
|
|
220
|
-
* @param accessors
|
|
221
|
-
* @param convertToRightHandedSystemMap
|
|
222
|
-
* @param animationSampleRate
|
|
223
|
-
*/
|
|
224
|
-
_GLTFAnimation._CreateNodeAndMorphAnimationFromAnimationGroups = function (babylonScene, glTFAnimations, nodeMap, nodes, binaryWriter, bufferViews, accessors, convertToRightHandedSystemMap, animationSampleRate) {
|
|
225
|
-
var _a;
|
|
226
|
-
var glTFAnimation;
|
|
227
|
-
if (babylonScene.animationGroups) {
|
|
228
|
-
var animationGroups = babylonScene.animationGroups;
|
|
229
|
-
var _loop_1 = function (animationGroup) {
|
|
230
|
-
var morphAnimations = new Map();
|
|
231
|
-
var sampleAnimations = new Map();
|
|
232
|
-
var morphAnimationMeshes = new Set();
|
|
233
|
-
var animationGroupFrameDiff = animationGroup.to - animationGroup.from;
|
|
234
|
-
glTFAnimation = {
|
|
235
|
-
name: animationGroup.name,
|
|
236
|
-
channels: [],
|
|
237
|
-
samplers: [],
|
|
238
|
-
};
|
|
239
|
-
var _loop_2 = function (i) {
|
|
240
|
-
var targetAnimation = animationGroup.targetedAnimations[i];
|
|
241
|
-
var target = targetAnimation.target;
|
|
242
|
-
var animation = targetAnimation.animation;
|
|
243
|
-
if (target instanceof TransformNode || (target.length === 1 && target[0] instanceof TransformNode)) {
|
|
244
|
-
var animationInfo = _GLTFAnimation._DeduceAnimationInfo(targetAnimation.animation);
|
|
245
|
-
if (animationInfo) {
|
|
246
|
-
var babylonTransformNode = target instanceof TransformNode ? target : target[0];
|
|
247
|
-
var convertToRightHandedSystem = convertToRightHandedSystemMap[babylonTransformNode.uniqueId];
|
|
248
|
-
_GLTFAnimation._AddAnimation("".concat(animation.name), glTFAnimation, babylonTransformNode, animation, animationInfo.dataAccessorType, animationInfo.animationChannelTargetPath, nodeMap, binaryWriter, bufferViews, accessors, convertToRightHandedSystem, animationInfo.useQuaternion, animationSampleRate);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
else if (target instanceof MorphTarget || (target.length === 1 && target[0] instanceof MorphTarget)) {
|
|
252
|
-
var animationInfo = _GLTFAnimation._DeduceAnimationInfo(targetAnimation.animation);
|
|
253
|
-
if (animationInfo) {
|
|
254
|
-
var babylonMorphTarget_1 = target instanceof MorphTarget ? target : target[0];
|
|
255
|
-
if (babylonMorphTarget_1) {
|
|
256
|
-
var babylonMorphTargetManager_1 = babylonScene.morphTargetManagers.find(function (morphTargetManager) {
|
|
257
|
-
for (var j = 0; j < morphTargetManager.numTargets; ++j) {
|
|
258
|
-
if (morphTargetManager.getTarget(j) === babylonMorphTarget_1) {
|
|
259
|
-
return true;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
return false;
|
|
263
|
-
});
|
|
264
|
-
if (babylonMorphTargetManager_1) {
|
|
265
|
-
var babylonMesh = babylonScene.meshes.find(function (mesh) {
|
|
266
|
-
return mesh.morphTargetManager === babylonMorphTargetManager_1;
|
|
267
|
-
});
|
|
268
|
-
if (babylonMesh) {
|
|
269
|
-
if (!morphAnimations.has(babylonMesh)) {
|
|
270
|
-
morphAnimations.set(babylonMesh, new Map());
|
|
271
|
-
}
|
|
272
|
-
(_a = morphAnimations.get(babylonMesh)) === null || _a === void 0 ? void 0 : _a.set(babylonMorphTarget_1, animation);
|
|
273
|
-
morphAnimationMeshes.add(babylonMesh);
|
|
274
|
-
sampleAnimations.set(babylonMesh, animation);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
for (var i = 0; i < animationGroup.targetedAnimations.length; ++i) {
|
|
282
|
-
_loop_2(i);
|
|
283
|
-
}
|
|
284
|
-
morphAnimationMeshes.forEach(function (mesh) {
|
|
285
|
-
var morphTargetManager = mesh.morphTargetManager;
|
|
286
|
-
var combinedAnimationGroup = null;
|
|
287
|
-
var animationKeys = [];
|
|
288
|
-
var sampleAnimation = sampleAnimations.get(mesh);
|
|
289
|
-
var sampleAnimationKeys = sampleAnimation.getKeys();
|
|
290
|
-
var numAnimationKeys = sampleAnimationKeys.length;
|
|
291
|
-
/*
|
|
292
|
-
Due to how glTF expects morph target animation data to be formatted, we need to rearrange the individual morph target animation tracks,
|
|
293
|
-
such that we have a single animation, where a given keyframe input value has successive output values for each morph target belonging to the manager.
|
|
294
|
-
See: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations
|
|
295
|
-
|
|
296
|
-
We do this via constructing a new Animation track, and interleaving the frames of each morph target animation track in the current Animation Group
|
|
297
|
-
We reuse the Babylon Animation data structure for ease of handling export of cubic spline animation keys, and to reuse the
|
|
298
|
-
existing _GLTFAnimation.AddAnimation codepath with minimal modification, however the constructed Babylon Animation is NOT intended for use in-engine.
|
|
299
|
-
*/
|
|
300
|
-
for (var i = 0; i < numAnimationKeys; ++i) {
|
|
301
|
-
for (var j = 0; j < morphTargetManager.numTargets; ++j) {
|
|
302
|
-
var morphTarget = morphTargetManager.getTarget(j);
|
|
303
|
-
var animationsByMorphTarget = morphAnimations.get(mesh);
|
|
304
|
-
if (animationsByMorphTarget) {
|
|
305
|
-
var morphTargetAnimation = animationsByMorphTarget.get(morphTarget);
|
|
306
|
-
if (morphTargetAnimation) {
|
|
307
|
-
if (!combinedAnimationGroup) {
|
|
308
|
-
combinedAnimationGroup = new Animation("".concat(animationGroup.name, "_").concat(mesh.name, "_MorphWeightAnimation"), "influence", morphTargetAnimation.framePerSecond, Animation.ANIMATIONTYPE_FLOAT, morphTargetAnimation.loopMode, morphTargetAnimation.enableBlending);
|
|
309
|
-
}
|
|
310
|
-
animationKeys.push(morphTargetAnimation.getKeys()[i]);
|
|
311
|
-
}
|
|
312
|
-
else {
|
|
313
|
-
animationKeys.push({
|
|
314
|
-
frame: animationGroup.from + (animationGroupFrameDiff / numAnimationKeys) * i,
|
|
315
|
-
value: morphTarget.influence,
|
|
316
|
-
inTangent: sampleAnimationKeys[0].inTangent ? 0 : undefined,
|
|
317
|
-
outTangent: sampleAnimationKeys[0].outTangent ? 0 : undefined,
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
combinedAnimationGroup.setKeys(animationKeys);
|
|
324
|
-
var animationInfo = _GLTFAnimation._DeduceAnimationInfo(combinedAnimationGroup);
|
|
325
|
-
if (animationInfo) {
|
|
326
|
-
_GLTFAnimation._AddAnimation("".concat(animationGroup.name, "_").concat(mesh.name, "_MorphWeightAnimation"), glTFAnimation, mesh, combinedAnimationGroup, animationInfo.dataAccessorType, animationInfo.animationChannelTargetPath, nodeMap, binaryWriter, bufferViews, accessors, false, animationInfo.useQuaternion, animationSampleRate, morphTargetManager === null || morphTargetManager === void 0 ? void 0 : morphTargetManager.numTargets);
|
|
327
|
-
}
|
|
328
|
-
});
|
|
329
|
-
if (glTFAnimation.channels.length && glTFAnimation.samplers.length) {
|
|
330
|
-
glTFAnimations.push(glTFAnimation);
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
for (var _i = 0, animationGroups_1 = animationGroups; _i < animationGroups_1.length; _i++) {
|
|
334
|
-
var animationGroup = animationGroups_1[_i];
|
|
335
|
-
_loop_1(animationGroup);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
_GLTFAnimation._AddAnimation = function (name, glTFAnimation, babylonTransformNode, animation, dataAccessorType, animationChannelTargetPath, nodeMap, binaryWriter, bufferViews, accessors, convertToRightHandedSystem, useQuaternion, animationSampleRate, morphAnimationChannels) {
|
|
340
|
-
var animationData = _GLTFAnimation._CreateNodeAnimation(babylonTransformNode, animation, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion, animationSampleRate);
|
|
341
|
-
var bufferView;
|
|
342
|
-
var accessor;
|
|
343
|
-
var keyframeAccessorIndex;
|
|
344
|
-
var dataAccessorIndex;
|
|
345
|
-
var outputLength;
|
|
346
|
-
var animationSampler;
|
|
347
|
-
var animationChannel;
|
|
348
|
-
if (animationData) {
|
|
349
|
-
/*
|
|
350
|
-
* Now that we have the glTF converted morph target animation data,
|
|
351
|
-
* we can remove redundant input data so that we have n input frames,
|
|
352
|
-
* and morphAnimationChannels * n output frames
|
|
353
|
-
*/
|
|
354
|
-
if (morphAnimationChannels) {
|
|
355
|
-
var index = 0;
|
|
356
|
-
var currentInput = 0;
|
|
357
|
-
var newInputs = [];
|
|
358
|
-
while (animationData.inputs.length > 0) {
|
|
359
|
-
currentInput = animationData.inputs.shift();
|
|
360
|
-
if (index % morphAnimationChannels == 0) {
|
|
361
|
-
newInputs.push(currentInput);
|
|
362
|
-
}
|
|
363
|
-
index++;
|
|
364
|
-
}
|
|
365
|
-
animationData.inputs = newInputs;
|
|
366
|
-
}
|
|
367
|
-
var nodeIndex = nodeMap[babylonTransformNode.uniqueId];
|
|
368
|
-
// Creates buffer view and accessor for key frames.
|
|
369
|
-
var byteLength = animationData.inputs.length * 4;
|
|
370
|
-
bufferView = _GLTFUtilities._CreateBufferView(0, binaryWriter.getByteOffset(), byteLength, undefined, "".concat(name, " keyframe data view"));
|
|
371
|
-
bufferViews.push(bufferView);
|
|
372
|
-
animationData.inputs.forEach(function (input) {
|
|
373
|
-
binaryWriter.setFloat32(input);
|
|
374
|
-
});
|
|
375
|
-
accessor = _GLTFUtilities._CreateAccessor(bufferViews.length - 1, "".concat(name, " keyframes"), "SCALAR" /* SCALAR */, 5126 /* FLOAT */, animationData.inputs.length, null, [animationData.inputsMin], [animationData.inputsMax]);
|
|
376
|
-
accessors.push(accessor);
|
|
377
|
-
keyframeAccessorIndex = accessors.length - 1;
|
|
378
|
-
// create bufferview and accessor for keyed values.
|
|
379
|
-
outputLength = animationData.outputs.length;
|
|
380
|
-
byteLength = _GLTFUtilities._GetDataAccessorElementCount(dataAccessorType) * 4 * animationData.outputs.length;
|
|
381
|
-
// check for in and out tangents
|
|
382
|
-
bufferView = _GLTFUtilities._CreateBufferView(0, binaryWriter.getByteOffset(), byteLength, undefined, "".concat(name, " data view"));
|
|
383
|
-
bufferViews.push(bufferView);
|
|
384
|
-
animationData.outputs.forEach(function (output) {
|
|
385
|
-
output.forEach(function (entry) {
|
|
386
|
-
binaryWriter.setFloat32(entry);
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
accessor = _GLTFUtilities._CreateAccessor(bufferViews.length - 1, "".concat(name, " data"), dataAccessorType, 5126 /* FLOAT */, outputLength, null, null, null);
|
|
390
|
-
accessors.push(accessor);
|
|
391
|
-
dataAccessorIndex = accessors.length - 1;
|
|
392
|
-
// create sampler
|
|
393
|
-
animationSampler = {
|
|
394
|
-
interpolation: animationData.samplerInterpolation,
|
|
395
|
-
input: keyframeAccessorIndex,
|
|
396
|
-
output: dataAccessorIndex,
|
|
397
|
-
};
|
|
398
|
-
glTFAnimation.samplers.push(animationSampler);
|
|
399
|
-
// create channel
|
|
400
|
-
animationChannel = {
|
|
401
|
-
sampler: glTFAnimation.samplers.length - 1,
|
|
402
|
-
target: {
|
|
403
|
-
node: nodeIndex,
|
|
404
|
-
path: animationChannelTargetPath,
|
|
405
|
-
},
|
|
406
|
-
};
|
|
407
|
-
glTFAnimation.channels.push(animationChannel);
|
|
408
|
-
}
|
|
409
|
-
};
|
|
410
|
-
/**
|
|
411
|
-
* Create a baked animation
|
|
412
|
-
* @param babylonTransformNode BabylonJS mesh
|
|
413
|
-
* @param animation BabylonJS animation corresponding to the BabylonJS mesh
|
|
414
|
-
* @param animationChannelTargetPath animation target channel
|
|
415
|
-
* @param minFrame minimum animation frame
|
|
416
|
-
* @param maxFrame maximum animation frame
|
|
417
|
-
* @param fps frames per second of the animation
|
|
418
|
-
* @param sampleRate
|
|
419
|
-
* @param inputs input key frames of the animation
|
|
420
|
-
* @param outputs output key frame data of the animation
|
|
421
|
-
* @param minMaxFrames
|
|
422
|
-
* @param minMaxFrames.min
|
|
423
|
-
* @param minMaxFrames.max
|
|
424
|
-
* @param convertToRightHandedSystem converts the values to right-handed
|
|
425
|
-
* @param useQuaternion specifies if quaternions should be used
|
|
426
|
-
*/
|
|
427
|
-
_GLTFAnimation._CreateBakedAnimation = function (babylonTransformNode, animation, animationChannelTargetPath, minFrame, maxFrame, fps, sampleRate, inputs, outputs, minMaxFrames, convertToRightHandedSystem, useQuaternion) {
|
|
428
|
-
var value;
|
|
429
|
-
var quaternionCache = Quaternion.Identity();
|
|
430
|
-
var previousTime = null;
|
|
431
|
-
var time;
|
|
432
|
-
var maxUsedFrame = null;
|
|
433
|
-
var currKeyFrame = null;
|
|
434
|
-
var nextKeyFrame = null;
|
|
435
|
-
var prevKeyFrame = null;
|
|
436
|
-
var endFrame = null;
|
|
437
|
-
minMaxFrames.min = Tools.FloatRound(minFrame / fps);
|
|
438
|
-
var keyFrames = animation.getKeys();
|
|
439
|
-
for (var i = 0, length_1 = keyFrames.length; i < length_1; ++i) {
|
|
440
|
-
endFrame = null;
|
|
441
|
-
currKeyFrame = keyFrames[i];
|
|
442
|
-
if (i + 1 < length_1) {
|
|
443
|
-
nextKeyFrame = keyFrames[i + 1];
|
|
444
|
-
if ((currKeyFrame.value.equals && currKeyFrame.value.equals(nextKeyFrame.value)) || currKeyFrame.value === nextKeyFrame.value) {
|
|
445
|
-
if (i === 0) {
|
|
446
|
-
// set the first frame to itself
|
|
447
|
-
endFrame = currKeyFrame.frame;
|
|
448
|
-
}
|
|
449
|
-
else {
|
|
450
|
-
continue;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
endFrame = nextKeyFrame.frame;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
else {
|
|
458
|
-
// at the last key frame
|
|
459
|
-
prevKeyFrame = keyFrames[i - 1];
|
|
460
|
-
if ((currKeyFrame.value.equals && currKeyFrame.value.equals(prevKeyFrame.value)) || currKeyFrame.value === prevKeyFrame.value) {
|
|
461
|
-
continue;
|
|
462
|
-
}
|
|
463
|
-
else {
|
|
464
|
-
endFrame = maxFrame;
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
if (endFrame) {
|
|
468
|
-
for (var f = currKeyFrame.frame; f <= endFrame; f += sampleRate) {
|
|
469
|
-
time = Tools.FloatRound(f / fps);
|
|
470
|
-
if (time === previousTime) {
|
|
471
|
-
continue;
|
|
472
|
-
}
|
|
473
|
-
previousTime = time;
|
|
474
|
-
maxUsedFrame = time;
|
|
475
|
-
var state = {
|
|
476
|
-
key: 0,
|
|
477
|
-
repeatCount: 0,
|
|
478
|
-
loopMode: animation.loopMode,
|
|
479
|
-
};
|
|
480
|
-
value = animation._interpolate(f, state);
|
|
481
|
-
_GLTFAnimation._SetInterpolatedValue(babylonTransformNode, value, time, animation, animationChannelTargetPath, quaternionCache, inputs, outputs, convertToRightHandedSystem, useQuaternion);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
if (maxUsedFrame) {
|
|
486
|
-
minMaxFrames.max = maxUsedFrame;
|
|
487
|
-
}
|
|
488
|
-
};
|
|
489
|
-
_GLTFAnimation._ConvertFactorToVector3OrQuaternion = function (factor, babylonTransformNode, animation, animationType, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion) {
|
|
490
|
-
var property;
|
|
491
|
-
var componentName;
|
|
492
|
-
var value = null;
|
|
493
|
-
var basePositionRotationOrScale = _GLTFAnimation._GetBasePositionRotationOrScale(babylonTransformNode, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion);
|
|
494
|
-
if (animationType === Animation.ANIMATIONTYPE_FLOAT) {
|
|
495
|
-
// handles single component x, y, z or w component animation by using a base property and animating over a component.
|
|
496
|
-
property = animation.targetProperty.split(".");
|
|
497
|
-
componentName = property ? property[1] : ""; // x, y, or z component
|
|
498
|
-
value = useQuaternion ? Quaternion.FromArray(basePositionRotationOrScale).normalize() : Vector3.FromArray(basePositionRotationOrScale);
|
|
499
|
-
switch (componentName) {
|
|
500
|
-
case "x": {
|
|
501
|
-
value[componentName] = convertToRightHandedSystem && useQuaternion && animationChannelTargetPath !== "scale" /* SCALE */ ? -factor : factor;
|
|
502
|
-
break;
|
|
503
|
-
}
|
|
504
|
-
case "y": {
|
|
505
|
-
value[componentName] = convertToRightHandedSystem && useQuaternion && animationChannelTargetPath !== "scale" /* SCALE */ ? -factor : factor;
|
|
506
|
-
break;
|
|
507
|
-
}
|
|
508
|
-
case "z": {
|
|
509
|
-
value[componentName] = convertToRightHandedSystem && !useQuaternion && animationChannelTargetPath !== "scale" /* SCALE */ ? -factor : factor;
|
|
510
|
-
break;
|
|
511
|
-
}
|
|
512
|
-
case "w": {
|
|
513
|
-
value.w = factor;
|
|
514
|
-
break;
|
|
515
|
-
}
|
|
516
|
-
default: {
|
|
517
|
-
Tools.Error("glTFAnimation: Unsupported component type \"".concat(componentName, "\" for scale animation!"));
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
return value;
|
|
522
|
-
};
|
|
523
|
-
_GLTFAnimation._SetInterpolatedValue = function (babylonTransformNode, value, time, animation, animationChannelTargetPath, quaternionCache, inputs, outputs, convertToRightHandedSystem, useQuaternion) {
|
|
524
|
-
var animationType = animation.dataType;
|
|
525
|
-
var cacheValue;
|
|
526
|
-
inputs.push(time);
|
|
527
|
-
if (typeof value === "number" && babylonTransformNode instanceof TransformNode) {
|
|
528
|
-
value = this._ConvertFactorToVector3OrQuaternion(value, babylonTransformNode, animation, animationType, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion);
|
|
529
|
-
}
|
|
530
|
-
if (value) {
|
|
531
|
-
if (animationChannelTargetPath === "rotation" /* ROTATION */) {
|
|
532
|
-
if (useQuaternion) {
|
|
533
|
-
quaternionCache = value;
|
|
534
|
-
}
|
|
535
|
-
else {
|
|
536
|
-
cacheValue = value;
|
|
537
|
-
Quaternion.RotationYawPitchRollToRef(cacheValue.y, cacheValue.x, cacheValue.z, quaternionCache);
|
|
538
|
-
}
|
|
539
|
-
if (convertToRightHandedSystem) {
|
|
540
|
-
_GLTFUtilities._GetRightHandedQuaternionFromRef(quaternionCache);
|
|
541
|
-
if (!babylonTransformNode.parent) {
|
|
542
|
-
quaternionCache = Quaternion.FromArray([0, 1, 0, 0]).multiply(quaternionCache);
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
outputs.push(quaternionCache.asArray());
|
|
546
|
-
}
|
|
547
|
-
else if (animationChannelTargetPath === "weights" /* WEIGHTS */) {
|
|
548
|
-
outputs.push([value]);
|
|
549
|
-
}
|
|
550
|
-
else {
|
|
551
|
-
// scaling and position animation
|
|
552
|
-
cacheValue = value;
|
|
553
|
-
if (convertToRightHandedSystem && animationChannelTargetPath !== "scale" /* SCALE */) {
|
|
554
|
-
_GLTFUtilities._GetRightHandedPositionVector3FromRef(cacheValue);
|
|
555
|
-
if (!babylonTransformNode.parent) {
|
|
556
|
-
cacheValue.x *= -1;
|
|
557
|
-
cacheValue.z *= -1;
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
outputs.push(cacheValue.asArray());
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
};
|
|
564
|
-
/**
|
|
565
|
-
* Creates linear animation from the animation key frames
|
|
566
|
-
* @param babylonTransformNode BabylonJS mesh
|
|
567
|
-
* @param animation BabylonJS animation
|
|
568
|
-
* @param animationChannelTargetPath The target animation channel
|
|
569
|
-
* @param frameDelta The difference between the last and first frame of the animation
|
|
570
|
-
* @param inputs Array to store the key frame times
|
|
571
|
-
* @param outputs Array to store the key frame data
|
|
572
|
-
* @param convertToRightHandedSystem Specifies if the position data should be converted to right handed
|
|
573
|
-
* @param useQuaternion Specifies if quaternions are used in the animation
|
|
574
|
-
*/
|
|
575
|
-
_GLTFAnimation._CreateLinearOrStepAnimation = function (babylonTransformNode, animation, animationChannelTargetPath, frameDelta, inputs, outputs, convertToRightHandedSystem, useQuaternion) {
|
|
576
|
-
for (var _i = 0, _a = animation.getKeys(); _i < _a.length; _i++) {
|
|
577
|
-
var keyFrame = _a[_i];
|
|
578
|
-
inputs.push(keyFrame.frame / animation.framePerSecond); // keyframes in seconds.
|
|
579
|
-
_GLTFAnimation._AddKeyframeValue(keyFrame, animation, outputs, animationChannelTargetPath, babylonTransformNode, convertToRightHandedSystem, useQuaternion);
|
|
580
|
-
}
|
|
581
|
-
};
|
|
582
|
-
/**
|
|
583
|
-
* Creates cubic spline animation from the animation key frames
|
|
584
|
-
* @param babylonTransformNode BabylonJS mesh
|
|
585
|
-
* @param animation BabylonJS animation
|
|
586
|
-
* @param animationChannelTargetPath The target animation channel
|
|
587
|
-
* @param frameDelta The difference between the last and first frame of the animation
|
|
588
|
-
* @param inputs Array to store the key frame times
|
|
589
|
-
* @param outputs Array to store the key frame data
|
|
590
|
-
* @param convertToRightHandedSystem Specifies if the position data should be converted to right handed
|
|
591
|
-
* @param useQuaternion Specifies if quaternions are used in the animation
|
|
592
|
-
*/
|
|
593
|
-
_GLTFAnimation._CreateCubicSplineAnimation = function (babylonTransformNode, animation, animationChannelTargetPath, frameDelta, inputs, outputs, convertToRightHandedSystem, useQuaternion) {
|
|
594
|
-
animation.getKeys().forEach(function (keyFrame) {
|
|
595
|
-
inputs.push(keyFrame.frame / animation.framePerSecond); // keyframes in seconds.
|
|
596
|
-
_GLTFAnimation._AddSplineTangent(babylonTransformNode, _TangentType.INTANGENT, outputs, animationChannelTargetPath, "CUBICSPLINE" /* CUBICSPLINE */, keyFrame, frameDelta, useQuaternion, convertToRightHandedSystem);
|
|
597
|
-
_GLTFAnimation._AddKeyframeValue(keyFrame, animation, outputs, animationChannelTargetPath, babylonTransformNode, convertToRightHandedSystem, useQuaternion);
|
|
598
|
-
_GLTFAnimation._AddSplineTangent(babylonTransformNode, _TangentType.OUTTANGENT, outputs, animationChannelTargetPath, "CUBICSPLINE" /* CUBICSPLINE */, keyFrame, frameDelta, useQuaternion, convertToRightHandedSystem);
|
|
599
|
-
});
|
|
600
|
-
};
|
|
601
|
-
_GLTFAnimation._GetBasePositionRotationOrScale = function (babylonTransformNode, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion) {
|
|
602
|
-
var basePositionRotationOrScale;
|
|
603
|
-
if (animationChannelTargetPath === "rotation" /* ROTATION */) {
|
|
604
|
-
if (useQuaternion) {
|
|
605
|
-
if (babylonTransformNode.rotationQuaternion) {
|
|
606
|
-
basePositionRotationOrScale = babylonTransformNode.rotationQuaternion.asArray();
|
|
607
|
-
if (convertToRightHandedSystem) {
|
|
608
|
-
_GLTFUtilities._GetRightHandedQuaternionArrayFromRef(basePositionRotationOrScale);
|
|
609
|
-
if (!babylonTransformNode.parent) {
|
|
610
|
-
basePositionRotationOrScale = Quaternion.FromArray([0, 1, 0, 0]).multiply(Quaternion.FromArray(basePositionRotationOrScale)).asArray();
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
else {
|
|
615
|
-
basePositionRotationOrScale = Quaternion.Identity().asArray();
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
else {
|
|
619
|
-
basePositionRotationOrScale = babylonTransformNode.rotation.asArray();
|
|
620
|
-
_GLTFUtilities._GetRightHandedNormalArray3FromRef(basePositionRotationOrScale);
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
else if (animationChannelTargetPath === "translation" /* TRANSLATION */) {
|
|
624
|
-
basePositionRotationOrScale = babylonTransformNode.position.asArray();
|
|
625
|
-
if (convertToRightHandedSystem) {
|
|
626
|
-
_GLTFUtilities._GetRightHandedPositionArray3FromRef(basePositionRotationOrScale);
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
else {
|
|
630
|
-
// scale
|
|
631
|
-
basePositionRotationOrScale = babylonTransformNode.scaling.asArray();
|
|
632
|
-
}
|
|
633
|
-
return basePositionRotationOrScale;
|
|
634
|
-
};
|
|
635
|
-
/**
|
|
636
|
-
* Adds a key frame value
|
|
637
|
-
* @param keyFrame
|
|
638
|
-
* @param animation
|
|
639
|
-
* @param outputs
|
|
640
|
-
* @param animationChannelTargetPath
|
|
641
|
-
* @param babylonTransformNode
|
|
642
|
-
* @param convertToRightHandedSystem
|
|
643
|
-
* @param useQuaternion
|
|
644
|
-
*/
|
|
645
|
-
_GLTFAnimation._AddKeyframeValue = function (keyFrame, animation, outputs, animationChannelTargetPath, babylonTransformNode, convertToRightHandedSystem, useQuaternion) {
|
|
646
|
-
var value;
|
|
647
|
-
var newPositionRotationOrScale;
|
|
648
|
-
var animationType = animation.dataType;
|
|
649
|
-
if (animationType === Animation.ANIMATIONTYPE_VECTOR3) {
|
|
650
|
-
value = keyFrame.value.asArray();
|
|
651
|
-
if (animationChannelTargetPath === "rotation" /* ROTATION */) {
|
|
652
|
-
var array = Vector3.FromArray(value);
|
|
653
|
-
var rotationQuaternion = Quaternion.RotationYawPitchRoll(array.y, array.x, array.z);
|
|
654
|
-
if (convertToRightHandedSystem) {
|
|
655
|
-
_GLTFUtilities._GetRightHandedQuaternionFromRef(rotationQuaternion);
|
|
656
|
-
if (!babylonTransformNode.parent) {
|
|
657
|
-
rotationQuaternion = Quaternion.FromArray([0, 1, 0, 0]).multiply(rotationQuaternion);
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
value = rotationQuaternion.asArray();
|
|
661
|
-
}
|
|
662
|
-
else if (animationChannelTargetPath === "translation" /* TRANSLATION */) {
|
|
663
|
-
if (convertToRightHandedSystem) {
|
|
664
|
-
_GLTFUtilities._GetRightHandedNormalArray3FromRef(value);
|
|
665
|
-
if (!babylonTransformNode.parent) {
|
|
666
|
-
value[0] *= -1;
|
|
667
|
-
value[2] *= -1;
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
outputs.push(value); // scale vector.
|
|
672
|
-
}
|
|
673
|
-
else if (animationType === Animation.ANIMATIONTYPE_FLOAT) {
|
|
674
|
-
if (animationChannelTargetPath === "weights" /* WEIGHTS */) {
|
|
675
|
-
outputs.push([keyFrame.value]);
|
|
676
|
-
}
|
|
677
|
-
else {
|
|
678
|
-
// handles single component x, y, z or w component animation by using a base property and animating over a component.
|
|
679
|
-
newPositionRotationOrScale = this._ConvertFactorToVector3OrQuaternion(keyFrame.value, babylonTransformNode, animation, animationType, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion);
|
|
680
|
-
if (newPositionRotationOrScale) {
|
|
681
|
-
if (animationChannelTargetPath === "rotation" /* ROTATION */) {
|
|
682
|
-
var posRotScale = useQuaternion
|
|
683
|
-
? newPositionRotationOrScale
|
|
684
|
-
: Quaternion.RotationYawPitchRoll(newPositionRotationOrScale.y, newPositionRotationOrScale.x, newPositionRotationOrScale.z).normalize();
|
|
685
|
-
if (convertToRightHandedSystem) {
|
|
686
|
-
_GLTFUtilities._GetRightHandedQuaternionFromRef(posRotScale);
|
|
687
|
-
if (!babylonTransformNode.parent) {
|
|
688
|
-
posRotScale = Quaternion.FromArray([0, 1, 0, 0]).multiply(posRotScale);
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
outputs.push(posRotScale.asArray());
|
|
692
|
-
}
|
|
693
|
-
else if (animationChannelTargetPath === "translation" /* TRANSLATION */) {
|
|
694
|
-
if (convertToRightHandedSystem) {
|
|
695
|
-
_GLTFUtilities._GetRightHandedNormalVector3FromRef(newPositionRotationOrScale);
|
|
696
|
-
if (!babylonTransformNode.parent) {
|
|
697
|
-
newPositionRotationOrScale.x *= -1;
|
|
698
|
-
newPositionRotationOrScale.z *= -1;
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
outputs.push(newPositionRotationOrScale.asArray());
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
else if (animationType === Animation.ANIMATIONTYPE_QUATERNION) {
|
|
707
|
-
value = keyFrame.value.normalize().asArray();
|
|
708
|
-
if (convertToRightHandedSystem) {
|
|
709
|
-
_GLTFUtilities._GetRightHandedQuaternionArrayFromRef(value);
|
|
710
|
-
if (!babylonTransformNode.parent) {
|
|
711
|
-
value = Quaternion.FromArray([0, 1, 0, 0]).multiply(Quaternion.FromArray(value)).asArray();
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
outputs.push(value);
|
|
715
|
-
}
|
|
716
|
-
else {
|
|
717
|
-
Tools.Error("glTFAnimation: Unsupported key frame values for animation!");
|
|
718
|
-
}
|
|
719
|
-
};
|
|
720
|
-
/**
|
|
721
|
-
* Determine the interpolation based on the key frames
|
|
722
|
-
* @param keyFrames
|
|
723
|
-
* @param animationChannelTargetPath
|
|
724
|
-
* @param useQuaternion
|
|
725
|
-
*/
|
|
726
|
-
_GLTFAnimation._DeduceInterpolation = function (keyFrames, animationChannelTargetPath, useQuaternion) {
|
|
727
|
-
var interpolationType;
|
|
728
|
-
var shouldBakeAnimation = false;
|
|
729
|
-
var key;
|
|
730
|
-
if (animationChannelTargetPath === "rotation" /* ROTATION */ && !useQuaternion) {
|
|
731
|
-
return { interpolationType: "LINEAR" /* LINEAR */, shouldBakeAnimation: true };
|
|
732
|
-
}
|
|
733
|
-
for (var i = 0, length_2 = keyFrames.length; i < length_2; ++i) {
|
|
734
|
-
key = keyFrames[i];
|
|
735
|
-
if (key.inTangent || key.outTangent) {
|
|
736
|
-
if (interpolationType) {
|
|
737
|
-
if (interpolationType !== "CUBICSPLINE" /* CUBICSPLINE */) {
|
|
738
|
-
interpolationType = "LINEAR" /* LINEAR */;
|
|
739
|
-
shouldBakeAnimation = true;
|
|
740
|
-
break;
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
else {
|
|
744
|
-
interpolationType = "CUBICSPLINE" /* CUBICSPLINE */;
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
else {
|
|
748
|
-
if (interpolationType) {
|
|
749
|
-
if (interpolationType === "CUBICSPLINE" /* CUBICSPLINE */ ||
|
|
750
|
-
(key.interpolation && key.interpolation === AnimationKeyInterpolation.STEP && interpolationType !== "STEP" /* STEP */)) {
|
|
751
|
-
interpolationType = "LINEAR" /* LINEAR */;
|
|
752
|
-
shouldBakeAnimation = true;
|
|
753
|
-
break;
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
else {
|
|
757
|
-
if (key.interpolation && key.interpolation === AnimationKeyInterpolation.STEP) {
|
|
758
|
-
interpolationType = "STEP" /* STEP */;
|
|
759
|
-
}
|
|
760
|
-
else {
|
|
761
|
-
interpolationType = "LINEAR" /* LINEAR */;
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
if (!interpolationType) {
|
|
767
|
-
interpolationType = "LINEAR" /* LINEAR */;
|
|
768
|
-
}
|
|
769
|
-
return { interpolationType: interpolationType, shouldBakeAnimation: shouldBakeAnimation };
|
|
770
|
-
};
|
|
771
|
-
/**
|
|
772
|
-
* Adds an input tangent or output tangent to the output data
|
|
773
|
-
* If an input tangent or output tangent is missing, it uses the zero vector or zero quaternion
|
|
774
|
-
* @param babylonTransformNode
|
|
775
|
-
* @param tangentType Specifies which type of tangent to handle (inTangent or outTangent)
|
|
776
|
-
* @param outputs The animation data by keyframe
|
|
777
|
-
* @param animationChannelTargetPath The target animation channel
|
|
778
|
-
* @param interpolation The interpolation type
|
|
779
|
-
* @param keyFrame The key frame with the animation data
|
|
780
|
-
* @param frameDelta Time difference between two frames used to scale the tangent by the frame delta
|
|
781
|
-
* @param useQuaternion Specifies if quaternions are used
|
|
782
|
-
* @param convertToRightHandedSystem Specifies if the values should be converted to right-handed
|
|
783
|
-
*/
|
|
784
|
-
_GLTFAnimation._AddSplineTangent = function (babylonTransformNode, tangentType, outputs, animationChannelTargetPath, interpolation, keyFrame, frameDelta, useQuaternion, convertToRightHandedSystem) {
|
|
785
|
-
var tangent;
|
|
786
|
-
var tangentValue = tangentType === _TangentType.INTANGENT ? keyFrame.inTangent : keyFrame.outTangent;
|
|
787
|
-
if (interpolation === "CUBICSPLINE" /* CUBICSPLINE */) {
|
|
788
|
-
if (animationChannelTargetPath === "rotation" /* ROTATION */) {
|
|
789
|
-
if (tangentValue) {
|
|
790
|
-
if (useQuaternion) {
|
|
791
|
-
tangent = tangentValue.asArray();
|
|
792
|
-
}
|
|
793
|
-
else {
|
|
794
|
-
var array = tangentValue;
|
|
795
|
-
tangent = Quaternion.RotationYawPitchRoll(array.y, array.x, array.z).asArray();
|
|
796
|
-
}
|
|
797
|
-
if (convertToRightHandedSystem) {
|
|
798
|
-
_GLTFUtilities._GetRightHandedQuaternionArrayFromRef(tangent);
|
|
799
|
-
if (!babylonTransformNode.parent) {
|
|
800
|
-
tangent = Quaternion.FromArray([0, 1, 0, 0]).multiply(Quaternion.FromArray(tangent)).asArray();
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
else {
|
|
805
|
-
tangent = [0, 0, 0, 0];
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
else if (animationChannelTargetPath === "weights" /* WEIGHTS */) {
|
|
809
|
-
if (tangentValue) {
|
|
810
|
-
tangent = [tangentValue];
|
|
811
|
-
}
|
|
812
|
-
else {
|
|
813
|
-
tangent = [0];
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
else {
|
|
817
|
-
if (tangentValue) {
|
|
818
|
-
tangent = tangentValue.asArray();
|
|
819
|
-
if (convertToRightHandedSystem) {
|
|
820
|
-
if (animationChannelTargetPath === "translation" /* TRANSLATION */) {
|
|
821
|
-
_GLTFUtilities._GetRightHandedPositionArray3FromRef(tangent);
|
|
822
|
-
if (!babylonTransformNode.parent) {
|
|
823
|
-
tangent[0] *= -1; // x
|
|
824
|
-
tangent[2] *= -1; // z
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
else {
|
|
830
|
-
tangent = [0, 0, 0];
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
outputs.push(tangent);
|
|
834
|
-
}
|
|
835
|
-
};
|
|
836
|
-
/**
|
|
837
|
-
* Get the minimum and maximum key frames' frame values
|
|
838
|
-
* @param keyFrames animation key frames
|
|
839
|
-
* @returns the minimum and maximum key frame value
|
|
840
|
-
*/
|
|
841
|
-
_GLTFAnimation._CalculateMinMaxKeyFrames = function (keyFrames) {
|
|
842
|
-
var min = Infinity;
|
|
843
|
-
var max = -Infinity;
|
|
844
|
-
keyFrames.forEach(function (keyFrame) {
|
|
845
|
-
min = Math.min(min, keyFrame.frame);
|
|
846
|
-
max = Math.max(max, keyFrame.frame);
|
|
847
|
-
});
|
|
848
|
-
return { min: min, max: max };
|
|
849
|
-
};
|
|
850
|
-
return _GLTFAnimation;
|
|
851
|
-
}());
|
|
852
|
-
export { _GLTFAnimation };
|
|
1
|
+
import { Vector3, Quaternion } from "@babylonjs/core/Maths/math.vector.js";
|
|
2
|
+
import { Tools } from "@babylonjs/core/Misc/tools.js";
|
|
3
|
+
import { Animation } from "@babylonjs/core/Animations/animation.js";
|
|
4
|
+
import { TransformNode } from "@babylonjs/core/Meshes/transformNode.js";
|
|
5
|
+
import { MorphTarget } from "@babylonjs/core/Morph/morphTarget.js";
|
|
6
|
+
import { Mesh } from "@babylonjs/core/Meshes/mesh.js";
|
|
7
|
+
import { _GLTFUtilities } from "./glTFUtilities.js";
|
|
8
|
+
import { AnimationKeyInterpolation } from "@babylonjs/core/Animations/animationKey.js";
|
|
9
|
+
/**
|
|
10
|
+
* @hidden
|
|
11
|
+
* Enum for handling in tangent and out tangent.
|
|
12
|
+
*/
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
14
|
+
var _TangentType;
|
|
15
|
+
(function (_TangentType) {
|
|
16
|
+
/**
|
|
17
|
+
* Specifies that input tangents are used.
|
|
18
|
+
*/
|
|
19
|
+
_TangentType[_TangentType["INTANGENT"] = 0] = "INTANGENT";
|
|
20
|
+
/**
|
|
21
|
+
* Specifies that output tangents are used.
|
|
22
|
+
*/
|
|
23
|
+
_TangentType[_TangentType["OUTTANGENT"] = 1] = "OUTTANGENT";
|
|
24
|
+
})(_TangentType || (_TangentType = {}));
|
|
25
|
+
/**
|
|
26
|
+
* @hidden
|
|
27
|
+
* Utility class for generating glTF animation data from BabylonJS.
|
|
28
|
+
*/
|
|
29
|
+
var _GLTFAnimation = /** @class */ (function () {
|
|
30
|
+
function _GLTFAnimation() {
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* @ignore
|
|
34
|
+
*
|
|
35
|
+
* Creates glTF channel animation from BabylonJS animation.
|
|
36
|
+
* @param babylonTransformNode - BabylonJS mesh.
|
|
37
|
+
* @param animation - animation.
|
|
38
|
+
* @param animationChannelTargetPath - The target animation channel.
|
|
39
|
+
* @param convertToRightHandedSystem - Specifies if the values should be converted to right-handed.
|
|
40
|
+
* @param useQuaternion - Specifies if quaternions are used.
|
|
41
|
+
* @returns nullable IAnimationData
|
|
42
|
+
*/
|
|
43
|
+
_GLTFAnimation._CreateNodeAnimation = function (babylonTransformNode, animation, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion, animationSampleRate) {
|
|
44
|
+
var inputs = [];
|
|
45
|
+
var outputs = [];
|
|
46
|
+
var keyFrames = animation.getKeys();
|
|
47
|
+
var minMaxKeyFrames = _GLTFAnimation._CalculateMinMaxKeyFrames(keyFrames);
|
|
48
|
+
var interpolationOrBake = _GLTFAnimation._DeduceInterpolation(keyFrames, animationChannelTargetPath, useQuaternion);
|
|
49
|
+
var frameDelta = minMaxKeyFrames.max - minMaxKeyFrames.min;
|
|
50
|
+
var interpolation = interpolationOrBake.interpolationType;
|
|
51
|
+
var shouldBakeAnimation = interpolationOrBake.shouldBakeAnimation;
|
|
52
|
+
if (shouldBakeAnimation) {
|
|
53
|
+
_GLTFAnimation._CreateBakedAnimation(babylonTransformNode, animation, animationChannelTargetPath, minMaxKeyFrames.min, minMaxKeyFrames.max, animation.framePerSecond, animationSampleRate, inputs, outputs, minMaxKeyFrames, convertToRightHandedSystem, useQuaternion);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
if (interpolation === "LINEAR" /* LINEAR */ || interpolation === "STEP" /* STEP */) {
|
|
57
|
+
_GLTFAnimation._CreateLinearOrStepAnimation(babylonTransformNode, animation, animationChannelTargetPath, frameDelta, inputs, outputs, convertToRightHandedSystem, useQuaternion);
|
|
58
|
+
}
|
|
59
|
+
else if (interpolation === "CUBICSPLINE" /* CUBICSPLINE */) {
|
|
60
|
+
_GLTFAnimation._CreateCubicSplineAnimation(babylonTransformNode, animation, animationChannelTargetPath, frameDelta, inputs, outputs, convertToRightHandedSystem, useQuaternion);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
_GLTFAnimation._CreateBakedAnimation(babylonTransformNode, animation, animationChannelTargetPath, minMaxKeyFrames.min, minMaxKeyFrames.max, animation.framePerSecond, animationSampleRate, inputs, outputs, minMaxKeyFrames, convertToRightHandedSystem, useQuaternion);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (inputs.length && outputs.length) {
|
|
67
|
+
var result = {
|
|
68
|
+
inputs: inputs,
|
|
69
|
+
outputs: outputs,
|
|
70
|
+
samplerInterpolation: interpolation,
|
|
71
|
+
inputsMin: shouldBakeAnimation ? minMaxKeyFrames.min : Tools.FloatRound(minMaxKeyFrames.min / animation.framePerSecond),
|
|
72
|
+
inputsMax: shouldBakeAnimation ? minMaxKeyFrames.max : Tools.FloatRound(minMaxKeyFrames.max / animation.framePerSecond),
|
|
73
|
+
};
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
};
|
|
78
|
+
_GLTFAnimation._DeduceAnimationInfo = function (animation) {
|
|
79
|
+
var animationChannelTargetPath = null;
|
|
80
|
+
var dataAccessorType = "VEC3" /* VEC3 */;
|
|
81
|
+
var useQuaternion = false;
|
|
82
|
+
var property = animation.targetProperty.split(".");
|
|
83
|
+
switch (property[0]) {
|
|
84
|
+
case "scaling": {
|
|
85
|
+
animationChannelTargetPath = "scale" /* SCALE */;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case "position": {
|
|
89
|
+
animationChannelTargetPath = "translation" /* TRANSLATION */;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case "rotation": {
|
|
93
|
+
dataAccessorType = "VEC4" /* VEC4 */;
|
|
94
|
+
animationChannelTargetPath = "rotation" /* ROTATION */;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case "rotationQuaternion": {
|
|
98
|
+
dataAccessorType = "VEC4" /* VEC4 */;
|
|
99
|
+
useQuaternion = true;
|
|
100
|
+
animationChannelTargetPath = "rotation" /* ROTATION */;
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
case "influence": {
|
|
104
|
+
dataAccessorType = "SCALAR" /* SCALAR */;
|
|
105
|
+
animationChannelTargetPath = "weights" /* WEIGHTS */;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
default: {
|
|
109
|
+
Tools.Error("Unsupported animatable property ".concat(property[0]));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (animationChannelTargetPath) {
|
|
113
|
+
return { animationChannelTargetPath: animationChannelTargetPath, dataAccessorType: dataAccessorType, useQuaternion: useQuaternion };
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
Tools.Error("animation channel target path and data accessor type could be deduced");
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* @ignore
|
|
122
|
+
* Create node animations from the transform node animations
|
|
123
|
+
* @param babylonNode
|
|
124
|
+
* @param runtimeGLTFAnimation
|
|
125
|
+
* @param idleGLTFAnimations
|
|
126
|
+
* @param nodeMap
|
|
127
|
+
* @param nodes
|
|
128
|
+
* @param binaryWriter
|
|
129
|
+
* @param bufferViews
|
|
130
|
+
* @param accessors
|
|
131
|
+
* @param convertToRightHandedSystem
|
|
132
|
+
* @param animationSampleRate
|
|
133
|
+
*/
|
|
134
|
+
_GLTFAnimation._CreateNodeAnimationFromNodeAnimations = function (babylonNode, runtimeGLTFAnimation, idleGLTFAnimations, nodeMap, nodes, binaryWriter, bufferViews, accessors, convertToRightHandedSystem, animationSampleRate) {
|
|
135
|
+
var glTFAnimation;
|
|
136
|
+
if (babylonNode instanceof TransformNode) {
|
|
137
|
+
if (babylonNode.animations) {
|
|
138
|
+
for (var _i = 0, _a = babylonNode.animations; _i < _a.length; _i++) {
|
|
139
|
+
var animation = _a[_i];
|
|
140
|
+
var animationInfo = _GLTFAnimation._DeduceAnimationInfo(animation);
|
|
141
|
+
if (animationInfo) {
|
|
142
|
+
glTFAnimation = {
|
|
143
|
+
name: animation.name,
|
|
144
|
+
samplers: [],
|
|
145
|
+
channels: [],
|
|
146
|
+
};
|
|
147
|
+
_GLTFAnimation._AddAnimation("".concat(animation.name), animation.hasRunningRuntimeAnimations ? runtimeGLTFAnimation : glTFAnimation, babylonNode, animation, animationInfo.dataAccessorType, animationInfo.animationChannelTargetPath, nodeMap, binaryWriter, bufferViews, accessors, convertToRightHandedSystem, animationInfo.useQuaternion, animationSampleRate);
|
|
148
|
+
if (glTFAnimation.samplers.length && glTFAnimation.channels.length) {
|
|
149
|
+
idleGLTFAnimations.push(glTFAnimation);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* @ignore
|
|
158
|
+
* Create individual morph animations from the mesh's morph target animation tracks
|
|
159
|
+
* @param babylonNode
|
|
160
|
+
* @param runtimeGLTFAnimation
|
|
161
|
+
* @param idleGLTFAnimations
|
|
162
|
+
* @param nodeMap
|
|
163
|
+
* @param nodes
|
|
164
|
+
* @param binaryWriter
|
|
165
|
+
* @param bufferViews
|
|
166
|
+
* @param accessors
|
|
167
|
+
* @param convertToRightHandedSystem
|
|
168
|
+
* @param animationSampleRate
|
|
169
|
+
*/
|
|
170
|
+
_GLTFAnimation._CreateMorphTargetAnimationFromMorphTargetAnimations = function (babylonNode, runtimeGLTFAnimation, idleGLTFAnimations, nodeMap, nodes, binaryWriter, bufferViews, accessors, convertToRightHandedSystem, animationSampleRate) {
|
|
171
|
+
var glTFAnimation;
|
|
172
|
+
if (babylonNode instanceof Mesh) {
|
|
173
|
+
var morphTargetManager = babylonNode.morphTargetManager;
|
|
174
|
+
if (morphTargetManager) {
|
|
175
|
+
for (var i = 0; i < morphTargetManager.numTargets; ++i) {
|
|
176
|
+
var morphTarget = morphTargetManager.getTarget(i);
|
|
177
|
+
for (var _i = 0, _a = morphTarget.animations; _i < _a.length; _i++) {
|
|
178
|
+
var animation = _a[_i];
|
|
179
|
+
var combinedAnimation = new Animation("".concat(animation.name), "influence", animation.framePerSecond, animation.dataType, animation.loopMode, animation.enableBlending);
|
|
180
|
+
var combinedAnimationKeys = [];
|
|
181
|
+
var animationKeys = animation.getKeys();
|
|
182
|
+
for (var j = 0; j < animationKeys.length; ++j) {
|
|
183
|
+
var animationKey = animationKeys[j];
|
|
184
|
+
for (var k = 0; k < morphTargetManager.numTargets; ++k) {
|
|
185
|
+
if (k == i) {
|
|
186
|
+
combinedAnimationKeys.push(animationKey);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
combinedAnimationKeys.push({ frame: animationKey.frame, value: 0 });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
combinedAnimation.setKeys(combinedAnimationKeys);
|
|
194
|
+
var animationInfo = _GLTFAnimation._DeduceAnimationInfo(combinedAnimation);
|
|
195
|
+
if (animationInfo) {
|
|
196
|
+
glTFAnimation = {
|
|
197
|
+
name: combinedAnimation.name,
|
|
198
|
+
samplers: [],
|
|
199
|
+
channels: [],
|
|
200
|
+
};
|
|
201
|
+
_GLTFAnimation._AddAnimation(animation.name, animation.hasRunningRuntimeAnimations ? runtimeGLTFAnimation : glTFAnimation, babylonNode, combinedAnimation, animationInfo.dataAccessorType, animationInfo.animationChannelTargetPath, nodeMap, binaryWriter, bufferViews, accessors, convertToRightHandedSystem, animationInfo.useQuaternion, animationSampleRate, morphTargetManager.numTargets);
|
|
202
|
+
if (glTFAnimation.samplers.length && glTFAnimation.channels.length) {
|
|
203
|
+
idleGLTFAnimations.push(glTFAnimation);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* @ignore
|
|
213
|
+
* Create node and morph animations from the animation groups
|
|
214
|
+
* @param babylonScene
|
|
215
|
+
* @param glTFAnimations
|
|
216
|
+
* @param nodeMap
|
|
217
|
+
* @param nodes
|
|
218
|
+
* @param binaryWriter
|
|
219
|
+
* @param bufferViews
|
|
220
|
+
* @param accessors
|
|
221
|
+
* @param convertToRightHandedSystemMap
|
|
222
|
+
* @param animationSampleRate
|
|
223
|
+
*/
|
|
224
|
+
_GLTFAnimation._CreateNodeAndMorphAnimationFromAnimationGroups = function (babylonScene, glTFAnimations, nodeMap, nodes, binaryWriter, bufferViews, accessors, convertToRightHandedSystemMap, animationSampleRate) {
|
|
225
|
+
var _a;
|
|
226
|
+
var glTFAnimation;
|
|
227
|
+
if (babylonScene.animationGroups) {
|
|
228
|
+
var animationGroups = babylonScene.animationGroups;
|
|
229
|
+
var _loop_1 = function (animationGroup) {
|
|
230
|
+
var morphAnimations = new Map();
|
|
231
|
+
var sampleAnimations = new Map();
|
|
232
|
+
var morphAnimationMeshes = new Set();
|
|
233
|
+
var animationGroupFrameDiff = animationGroup.to - animationGroup.from;
|
|
234
|
+
glTFAnimation = {
|
|
235
|
+
name: animationGroup.name,
|
|
236
|
+
channels: [],
|
|
237
|
+
samplers: [],
|
|
238
|
+
};
|
|
239
|
+
var _loop_2 = function (i) {
|
|
240
|
+
var targetAnimation = animationGroup.targetedAnimations[i];
|
|
241
|
+
var target = targetAnimation.target;
|
|
242
|
+
var animation = targetAnimation.animation;
|
|
243
|
+
if (target instanceof TransformNode || (target.length === 1 && target[0] instanceof TransformNode)) {
|
|
244
|
+
var animationInfo = _GLTFAnimation._DeduceAnimationInfo(targetAnimation.animation);
|
|
245
|
+
if (animationInfo) {
|
|
246
|
+
var babylonTransformNode = target instanceof TransformNode ? target : target[0];
|
|
247
|
+
var convertToRightHandedSystem = convertToRightHandedSystemMap[babylonTransformNode.uniqueId];
|
|
248
|
+
_GLTFAnimation._AddAnimation("".concat(animation.name), glTFAnimation, babylonTransformNode, animation, animationInfo.dataAccessorType, animationInfo.animationChannelTargetPath, nodeMap, binaryWriter, bufferViews, accessors, convertToRightHandedSystem, animationInfo.useQuaternion, animationSampleRate);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else if (target instanceof MorphTarget || (target.length === 1 && target[0] instanceof MorphTarget)) {
|
|
252
|
+
var animationInfo = _GLTFAnimation._DeduceAnimationInfo(targetAnimation.animation);
|
|
253
|
+
if (animationInfo) {
|
|
254
|
+
var babylonMorphTarget_1 = target instanceof MorphTarget ? target : target[0];
|
|
255
|
+
if (babylonMorphTarget_1) {
|
|
256
|
+
var babylonMorphTargetManager_1 = babylonScene.morphTargetManagers.find(function (morphTargetManager) {
|
|
257
|
+
for (var j = 0; j < morphTargetManager.numTargets; ++j) {
|
|
258
|
+
if (morphTargetManager.getTarget(j) === babylonMorphTarget_1) {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return false;
|
|
263
|
+
});
|
|
264
|
+
if (babylonMorphTargetManager_1) {
|
|
265
|
+
var babylonMesh = babylonScene.meshes.find(function (mesh) {
|
|
266
|
+
return mesh.morphTargetManager === babylonMorphTargetManager_1;
|
|
267
|
+
});
|
|
268
|
+
if (babylonMesh) {
|
|
269
|
+
if (!morphAnimations.has(babylonMesh)) {
|
|
270
|
+
morphAnimations.set(babylonMesh, new Map());
|
|
271
|
+
}
|
|
272
|
+
(_a = morphAnimations.get(babylonMesh)) === null || _a === void 0 ? void 0 : _a.set(babylonMorphTarget_1, animation);
|
|
273
|
+
morphAnimationMeshes.add(babylonMesh);
|
|
274
|
+
sampleAnimations.set(babylonMesh, animation);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
for (var i = 0; i < animationGroup.targetedAnimations.length; ++i) {
|
|
282
|
+
_loop_2(i);
|
|
283
|
+
}
|
|
284
|
+
morphAnimationMeshes.forEach(function (mesh) {
|
|
285
|
+
var morphTargetManager = mesh.morphTargetManager;
|
|
286
|
+
var combinedAnimationGroup = null;
|
|
287
|
+
var animationKeys = [];
|
|
288
|
+
var sampleAnimation = sampleAnimations.get(mesh);
|
|
289
|
+
var sampleAnimationKeys = sampleAnimation.getKeys();
|
|
290
|
+
var numAnimationKeys = sampleAnimationKeys.length;
|
|
291
|
+
/*
|
|
292
|
+
Due to how glTF expects morph target animation data to be formatted, we need to rearrange the individual morph target animation tracks,
|
|
293
|
+
such that we have a single animation, where a given keyframe input value has successive output values for each morph target belonging to the manager.
|
|
294
|
+
See: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations
|
|
295
|
+
|
|
296
|
+
We do this via constructing a new Animation track, and interleaving the frames of each morph target animation track in the current Animation Group
|
|
297
|
+
We reuse the Babylon Animation data structure for ease of handling export of cubic spline animation keys, and to reuse the
|
|
298
|
+
existing _GLTFAnimation.AddAnimation codepath with minimal modification, however the constructed Babylon Animation is NOT intended for use in-engine.
|
|
299
|
+
*/
|
|
300
|
+
for (var i = 0; i < numAnimationKeys; ++i) {
|
|
301
|
+
for (var j = 0; j < morphTargetManager.numTargets; ++j) {
|
|
302
|
+
var morphTarget = morphTargetManager.getTarget(j);
|
|
303
|
+
var animationsByMorphTarget = morphAnimations.get(mesh);
|
|
304
|
+
if (animationsByMorphTarget) {
|
|
305
|
+
var morphTargetAnimation = animationsByMorphTarget.get(morphTarget);
|
|
306
|
+
if (morphTargetAnimation) {
|
|
307
|
+
if (!combinedAnimationGroup) {
|
|
308
|
+
combinedAnimationGroup = new Animation("".concat(animationGroup.name, "_").concat(mesh.name, "_MorphWeightAnimation"), "influence", morphTargetAnimation.framePerSecond, Animation.ANIMATIONTYPE_FLOAT, morphTargetAnimation.loopMode, morphTargetAnimation.enableBlending);
|
|
309
|
+
}
|
|
310
|
+
animationKeys.push(morphTargetAnimation.getKeys()[i]);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
animationKeys.push({
|
|
314
|
+
frame: animationGroup.from + (animationGroupFrameDiff / numAnimationKeys) * i,
|
|
315
|
+
value: morphTarget.influence,
|
|
316
|
+
inTangent: sampleAnimationKeys[0].inTangent ? 0 : undefined,
|
|
317
|
+
outTangent: sampleAnimationKeys[0].outTangent ? 0 : undefined,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
combinedAnimationGroup.setKeys(animationKeys);
|
|
324
|
+
var animationInfo = _GLTFAnimation._DeduceAnimationInfo(combinedAnimationGroup);
|
|
325
|
+
if (animationInfo) {
|
|
326
|
+
_GLTFAnimation._AddAnimation("".concat(animationGroup.name, "_").concat(mesh.name, "_MorphWeightAnimation"), glTFAnimation, mesh, combinedAnimationGroup, animationInfo.dataAccessorType, animationInfo.animationChannelTargetPath, nodeMap, binaryWriter, bufferViews, accessors, false, animationInfo.useQuaternion, animationSampleRate, morphTargetManager === null || morphTargetManager === void 0 ? void 0 : morphTargetManager.numTargets);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
if (glTFAnimation.channels.length && glTFAnimation.samplers.length) {
|
|
330
|
+
glTFAnimations.push(glTFAnimation);
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
for (var _i = 0, animationGroups_1 = animationGroups; _i < animationGroups_1.length; _i++) {
|
|
334
|
+
var animationGroup = animationGroups_1[_i];
|
|
335
|
+
_loop_1(animationGroup);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
_GLTFAnimation._AddAnimation = function (name, glTFAnimation, babylonTransformNode, animation, dataAccessorType, animationChannelTargetPath, nodeMap, binaryWriter, bufferViews, accessors, convertToRightHandedSystem, useQuaternion, animationSampleRate, morphAnimationChannels) {
|
|
340
|
+
var animationData = _GLTFAnimation._CreateNodeAnimation(babylonTransformNode, animation, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion, animationSampleRate);
|
|
341
|
+
var bufferView;
|
|
342
|
+
var accessor;
|
|
343
|
+
var keyframeAccessorIndex;
|
|
344
|
+
var dataAccessorIndex;
|
|
345
|
+
var outputLength;
|
|
346
|
+
var animationSampler;
|
|
347
|
+
var animationChannel;
|
|
348
|
+
if (animationData) {
|
|
349
|
+
/*
|
|
350
|
+
* Now that we have the glTF converted morph target animation data,
|
|
351
|
+
* we can remove redundant input data so that we have n input frames,
|
|
352
|
+
* and morphAnimationChannels * n output frames
|
|
353
|
+
*/
|
|
354
|
+
if (morphAnimationChannels) {
|
|
355
|
+
var index = 0;
|
|
356
|
+
var currentInput = 0;
|
|
357
|
+
var newInputs = [];
|
|
358
|
+
while (animationData.inputs.length > 0) {
|
|
359
|
+
currentInput = animationData.inputs.shift();
|
|
360
|
+
if (index % morphAnimationChannels == 0) {
|
|
361
|
+
newInputs.push(currentInput);
|
|
362
|
+
}
|
|
363
|
+
index++;
|
|
364
|
+
}
|
|
365
|
+
animationData.inputs = newInputs;
|
|
366
|
+
}
|
|
367
|
+
var nodeIndex = nodeMap[babylonTransformNode.uniqueId];
|
|
368
|
+
// Creates buffer view and accessor for key frames.
|
|
369
|
+
var byteLength = animationData.inputs.length * 4;
|
|
370
|
+
bufferView = _GLTFUtilities._CreateBufferView(0, binaryWriter.getByteOffset(), byteLength, undefined, "".concat(name, " keyframe data view"));
|
|
371
|
+
bufferViews.push(bufferView);
|
|
372
|
+
animationData.inputs.forEach(function (input) {
|
|
373
|
+
binaryWriter.setFloat32(input);
|
|
374
|
+
});
|
|
375
|
+
accessor = _GLTFUtilities._CreateAccessor(bufferViews.length - 1, "".concat(name, " keyframes"), "SCALAR" /* SCALAR */, 5126 /* FLOAT */, animationData.inputs.length, null, [animationData.inputsMin], [animationData.inputsMax]);
|
|
376
|
+
accessors.push(accessor);
|
|
377
|
+
keyframeAccessorIndex = accessors.length - 1;
|
|
378
|
+
// create bufferview and accessor for keyed values.
|
|
379
|
+
outputLength = animationData.outputs.length;
|
|
380
|
+
byteLength = _GLTFUtilities._GetDataAccessorElementCount(dataAccessorType) * 4 * animationData.outputs.length;
|
|
381
|
+
// check for in and out tangents
|
|
382
|
+
bufferView = _GLTFUtilities._CreateBufferView(0, binaryWriter.getByteOffset(), byteLength, undefined, "".concat(name, " data view"));
|
|
383
|
+
bufferViews.push(bufferView);
|
|
384
|
+
animationData.outputs.forEach(function (output) {
|
|
385
|
+
output.forEach(function (entry) {
|
|
386
|
+
binaryWriter.setFloat32(entry);
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
accessor = _GLTFUtilities._CreateAccessor(bufferViews.length - 1, "".concat(name, " data"), dataAccessorType, 5126 /* FLOAT */, outputLength, null, null, null);
|
|
390
|
+
accessors.push(accessor);
|
|
391
|
+
dataAccessorIndex = accessors.length - 1;
|
|
392
|
+
// create sampler
|
|
393
|
+
animationSampler = {
|
|
394
|
+
interpolation: animationData.samplerInterpolation,
|
|
395
|
+
input: keyframeAccessorIndex,
|
|
396
|
+
output: dataAccessorIndex,
|
|
397
|
+
};
|
|
398
|
+
glTFAnimation.samplers.push(animationSampler);
|
|
399
|
+
// create channel
|
|
400
|
+
animationChannel = {
|
|
401
|
+
sampler: glTFAnimation.samplers.length - 1,
|
|
402
|
+
target: {
|
|
403
|
+
node: nodeIndex,
|
|
404
|
+
path: animationChannelTargetPath,
|
|
405
|
+
},
|
|
406
|
+
};
|
|
407
|
+
glTFAnimation.channels.push(animationChannel);
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
/**
|
|
411
|
+
* Create a baked animation
|
|
412
|
+
* @param babylonTransformNode BabylonJS mesh
|
|
413
|
+
* @param animation BabylonJS animation corresponding to the BabylonJS mesh
|
|
414
|
+
* @param animationChannelTargetPath animation target channel
|
|
415
|
+
* @param minFrame minimum animation frame
|
|
416
|
+
* @param maxFrame maximum animation frame
|
|
417
|
+
* @param fps frames per second of the animation
|
|
418
|
+
* @param sampleRate
|
|
419
|
+
* @param inputs input key frames of the animation
|
|
420
|
+
* @param outputs output key frame data of the animation
|
|
421
|
+
* @param minMaxFrames
|
|
422
|
+
* @param minMaxFrames.min
|
|
423
|
+
* @param minMaxFrames.max
|
|
424
|
+
* @param convertToRightHandedSystem converts the values to right-handed
|
|
425
|
+
* @param useQuaternion specifies if quaternions should be used
|
|
426
|
+
*/
|
|
427
|
+
_GLTFAnimation._CreateBakedAnimation = function (babylonTransformNode, animation, animationChannelTargetPath, minFrame, maxFrame, fps, sampleRate, inputs, outputs, minMaxFrames, convertToRightHandedSystem, useQuaternion) {
|
|
428
|
+
var value;
|
|
429
|
+
var quaternionCache = Quaternion.Identity();
|
|
430
|
+
var previousTime = null;
|
|
431
|
+
var time;
|
|
432
|
+
var maxUsedFrame = null;
|
|
433
|
+
var currKeyFrame = null;
|
|
434
|
+
var nextKeyFrame = null;
|
|
435
|
+
var prevKeyFrame = null;
|
|
436
|
+
var endFrame = null;
|
|
437
|
+
minMaxFrames.min = Tools.FloatRound(minFrame / fps);
|
|
438
|
+
var keyFrames = animation.getKeys();
|
|
439
|
+
for (var i = 0, length_1 = keyFrames.length; i < length_1; ++i) {
|
|
440
|
+
endFrame = null;
|
|
441
|
+
currKeyFrame = keyFrames[i];
|
|
442
|
+
if (i + 1 < length_1) {
|
|
443
|
+
nextKeyFrame = keyFrames[i + 1];
|
|
444
|
+
if ((currKeyFrame.value.equals && currKeyFrame.value.equals(nextKeyFrame.value)) || currKeyFrame.value === nextKeyFrame.value) {
|
|
445
|
+
if (i === 0) {
|
|
446
|
+
// set the first frame to itself
|
|
447
|
+
endFrame = currKeyFrame.frame;
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
endFrame = nextKeyFrame.frame;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
// at the last key frame
|
|
459
|
+
prevKeyFrame = keyFrames[i - 1];
|
|
460
|
+
if ((currKeyFrame.value.equals && currKeyFrame.value.equals(prevKeyFrame.value)) || currKeyFrame.value === prevKeyFrame.value) {
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
endFrame = maxFrame;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
if (endFrame) {
|
|
468
|
+
for (var f = currKeyFrame.frame; f <= endFrame; f += sampleRate) {
|
|
469
|
+
time = Tools.FloatRound(f / fps);
|
|
470
|
+
if (time === previousTime) {
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
previousTime = time;
|
|
474
|
+
maxUsedFrame = time;
|
|
475
|
+
var state = {
|
|
476
|
+
key: 0,
|
|
477
|
+
repeatCount: 0,
|
|
478
|
+
loopMode: animation.loopMode,
|
|
479
|
+
};
|
|
480
|
+
value = animation._interpolate(f, state);
|
|
481
|
+
_GLTFAnimation._SetInterpolatedValue(babylonTransformNode, value, time, animation, animationChannelTargetPath, quaternionCache, inputs, outputs, convertToRightHandedSystem, useQuaternion);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (maxUsedFrame) {
|
|
486
|
+
minMaxFrames.max = maxUsedFrame;
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
_GLTFAnimation._ConvertFactorToVector3OrQuaternion = function (factor, babylonTransformNode, animation, animationType, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion) {
|
|
490
|
+
var property;
|
|
491
|
+
var componentName;
|
|
492
|
+
var value = null;
|
|
493
|
+
var basePositionRotationOrScale = _GLTFAnimation._GetBasePositionRotationOrScale(babylonTransformNode, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion);
|
|
494
|
+
if (animationType === Animation.ANIMATIONTYPE_FLOAT) {
|
|
495
|
+
// handles single component x, y, z or w component animation by using a base property and animating over a component.
|
|
496
|
+
property = animation.targetProperty.split(".");
|
|
497
|
+
componentName = property ? property[1] : ""; // x, y, or z component
|
|
498
|
+
value = useQuaternion ? Quaternion.FromArray(basePositionRotationOrScale).normalize() : Vector3.FromArray(basePositionRotationOrScale);
|
|
499
|
+
switch (componentName) {
|
|
500
|
+
case "x": {
|
|
501
|
+
value[componentName] = convertToRightHandedSystem && useQuaternion && animationChannelTargetPath !== "scale" /* SCALE */ ? -factor : factor;
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
case "y": {
|
|
505
|
+
value[componentName] = convertToRightHandedSystem && useQuaternion && animationChannelTargetPath !== "scale" /* SCALE */ ? -factor : factor;
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
case "z": {
|
|
509
|
+
value[componentName] = convertToRightHandedSystem && !useQuaternion && animationChannelTargetPath !== "scale" /* SCALE */ ? -factor : factor;
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
case "w": {
|
|
513
|
+
value.w = factor;
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
default: {
|
|
517
|
+
Tools.Error("glTFAnimation: Unsupported component type \"".concat(componentName, "\" for scale animation!"));
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return value;
|
|
522
|
+
};
|
|
523
|
+
_GLTFAnimation._SetInterpolatedValue = function (babylonTransformNode, value, time, animation, animationChannelTargetPath, quaternionCache, inputs, outputs, convertToRightHandedSystem, useQuaternion) {
|
|
524
|
+
var animationType = animation.dataType;
|
|
525
|
+
var cacheValue;
|
|
526
|
+
inputs.push(time);
|
|
527
|
+
if (typeof value === "number" && babylonTransformNode instanceof TransformNode) {
|
|
528
|
+
value = this._ConvertFactorToVector3OrQuaternion(value, babylonTransformNode, animation, animationType, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion);
|
|
529
|
+
}
|
|
530
|
+
if (value) {
|
|
531
|
+
if (animationChannelTargetPath === "rotation" /* ROTATION */) {
|
|
532
|
+
if (useQuaternion) {
|
|
533
|
+
quaternionCache = value;
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
cacheValue = value;
|
|
537
|
+
Quaternion.RotationYawPitchRollToRef(cacheValue.y, cacheValue.x, cacheValue.z, quaternionCache);
|
|
538
|
+
}
|
|
539
|
+
if (convertToRightHandedSystem) {
|
|
540
|
+
_GLTFUtilities._GetRightHandedQuaternionFromRef(quaternionCache);
|
|
541
|
+
if (!babylonTransformNode.parent) {
|
|
542
|
+
quaternionCache = Quaternion.FromArray([0, 1, 0, 0]).multiply(quaternionCache);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
outputs.push(quaternionCache.asArray());
|
|
546
|
+
}
|
|
547
|
+
else if (animationChannelTargetPath === "weights" /* WEIGHTS */) {
|
|
548
|
+
outputs.push([value]);
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
// scaling and position animation
|
|
552
|
+
cacheValue = value;
|
|
553
|
+
if (convertToRightHandedSystem && animationChannelTargetPath !== "scale" /* SCALE */) {
|
|
554
|
+
_GLTFUtilities._GetRightHandedPositionVector3FromRef(cacheValue);
|
|
555
|
+
if (!babylonTransformNode.parent) {
|
|
556
|
+
cacheValue.x *= -1;
|
|
557
|
+
cacheValue.z *= -1;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
outputs.push(cacheValue.asArray());
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
/**
|
|
565
|
+
* Creates linear animation from the animation key frames
|
|
566
|
+
* @param babylonTransformNode BabylonJS mesh
|
|
567
|
+
* @param animation BabylonJS animation
|
|
568
|
+
* @param animationChannelTargetPath The target animation channel
|
|
569
|
+
* @param frameDelta The difference between the last and first frame of the animation
|
|
570
|
+
* @param inputs Array to store the key frame times
|
|
571
|
+
* @param outputs Array to store the key frame data
|
|
572
|
+
* @param convertToRightHandedSystem Specifies if the position data should be converted to right handed
|
|
573
|
+
* @param useQuaternion Specifies if quaternions are used in the animation
|
|
574
|
+
*/
|
|
575
|
+
_GLTFAnimation._CreateLinearOrStepAnimation = function (babylonTransformNode, animation, animationChannelTargetPath, frameDelta, inputs, outputs, convertToRightHandedSystem, useQuaternion) {
|
|
576
|
+
for (var _i = 0, _a = animation.getKeys(); _i < _a.length; _i++) {
|
|
577
|
+
var keyFrame = _a[_i];
|
|
578
|
+
inputs.push(keyFrame.frame / animation.framePerSecond); // keyframes in seconds.
|
|
579
|
+
_GLTFAnimation._AddKeyframeValue(keyFrame, animation, outputs, animationChannelTargetPath, babylonTransformNode, convertToRightHandedSystem, useQuaternion);
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
/**
|
|
583
|
+
* Creates cubic spline animation from the animation key frames
|
|
584
|
+
* @param babylonTransformNode BabylonJS mesh
|
|
585
|
+
* @param animation BabylonJS animation
|
|
586
|
+
* @param animationChannelTargetPath The target animation channel
|
|
587
|
+
* @param frameDelta The difference between the last and first frame of the animation
|
|
588
|
+
* @param inputs Array to store the key frame times
|
|
589
|
+
* @param outputs Array to store the key frame data
|
|
590
|
+
* @param convertToRightHandedSystem Specifies if the position data should be converted to right handed
|
|
591
|
+
* @param useQuaternion Specifies if quaternions are used in the animation
|
|
592
|
+
*/
|
|
593
|
+
_GLTFAnimation._CreateCubicSplineAnimation = function (babylonTransformNode, animation, animationChannelTargetPath, frameDelta, inputs, outputs, convertToRightHandedSystem, useQuaternion) {
|
|
594
|
+
animation.getKeys().forEach(function (keyFrame) {
|
|
595
|
+
inputs.push(keyFrame.frame / animation.framePerSecond); // keyframes in seconds.
|
|
596
|
+
_GLTFAnimation._AddSplineTangent(babylonTransformNode, _TangentType.INTANGENT, outputs, animationChannelTargetPath, "CUBICSPLINE" /* CUBICSPLINE */, keyFrame, frameDelta, useQuaternion, convertToRightHandedSystem);
|
|
597
|
+
_GLTFAnimation._AddKeyframeValue(keyFrame, animation, outputs, animationChannelTargetPath, babylonTransformNode, convertToRightHandedSystem, useQuaternion);
|
|
598
|
+
_GLTFAnimation._AddSplineTangent(babylonTransformNode, _TangentType.OUTTANGENT, outputs, animationChannelTargetPath, "CUBICSPLINE" /* CUBICSPLINE */, keyFrame, frameDelta, useQuaternion, convertToRightHandedSystem);
|
|
599
|
+
});
|
|
600
|
+
};
|
|
601
|
+
_GLTFAnimation._GetBasePositionRotationOrScale = function (babylonTransformNode, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion) {
|
|
602
|
+
var basePositionRotationOrScale;
|
|
603
|
+
if (animationChannelTargetPath === "rotation" /* ROTATION */) {
|
|
604
|
+
if (useQuaternion) {
|
|
605
|
+
if (babylonTransformNode.rotationQuaternion) {
|
|
606
|
+
basePositionRotationOrScale = babylonTransformNode.rotationQuaternion.asArray();
|
|
607
|
+
if (convertToRightHandedSystem) {
|
|
608
|
+
_GLTFUtilities._GetRightHandedQuaternionArrayFromRef(basePositionRotationOrScale);
|
|
609
|
+
if (!babylonTransformNode.parent) {
|
|
610
|
+
basePositionRotationOrScale = Quaternion.FromArray([0, 1, 0, 0]).multiply(Quaternion.FromArray(basePositionRotationOrScale)).asArray();
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
else {
|
|
615
|
+
basePositionRotationOrScale = Quaternion.Identity().asArray();
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
basePositionRotationOrScale = babylonTransformNode.rotation.asArray();
|
|
620
|
+
_GLTFUtilities._GetRightHandedNormalArray3FromRef(basePositionRotationOrScale);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
else if (animationChannelTargetPath === "translation" /* TRANSLATION */) {
|
|
624
|
+
basePositionRotationOrScale = babylonTransformNode.position.asArray();
|
|
625
|
+
if (convertToRightHandedSystem) {
|
|
626
|
+
_GLTFUtilities._GetRightHandedPositionArray3FromRef(basePositionRotationOrScale);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
// scale
|
|
631
|
+
basePositionRotationOrScale = babylonTransformNode.scaling.asArray();
|
|
632
|
+
}
|
|
633
|
+
return basePositionRotationOrScale;
|
|
634
|
+
};
|
|
635
|
+
/**
|
|
636
|
+
* Adds a key frame value
|
|
637
|
+
* @param keyFrame
|
|
638
|
+
* @param animation
|
|
639
|
+
* @param outputs
|
|
640
|
+
* @param animationChannelTargetPath
|
|
641
|
+
* @param babylonTransformNode
|
|
642
|
+
* @param convertToRightHandedSystem
|
|
643
|
+
* @param useQuaternion
|
|
644
|
+
*/
|
|
645
|
+
_GLTFAnimation._AddKeyframeValue = function (keyFrame, animation, outputs, animationChannelTargetPath, babylonTransformNode, convertToRightHandedSystem, useQuaternion) {
|
|
646
|
+
var value;
|
|
647
|
+
var newPositionRotationOrScale;
|
|
648
|
+
var animationType = animation.dataType;
|
|
649
|
+
if (animationType === Animation.ANIMATIONTYPE_VECTOR3) {
|
|
650
|
+
value = keyFrame.value.asArray();
|
|
651
|
+
if (animationChannelTargetPath === "rotation" /* ROTATION */) {
|
|
652
|
+
var array = Vector3.FromArray(value);
|
|
653
|
+
var rotationQuaternion = Quaternion.RotationYawPitchRoll(array.y, array.x, array.z);
|
|
654
|
+
if (convertToRightHandedSystem) {
|
|
655
|
+
_GLTFUtilities._GetRightHandedQuaternionFromRef(rotationQuaternion);
|
|
656
|
+
if (!babylonTransformNode.parent) {
|
|
657
|
+
rotationQuaternion = Quaternion.FromArray([0, 1, 0, 0]).multiply(rotationQuaternion);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
value = rotationQuaternion.asArray();
|
|
661
|
+
}
|
|
662
|
+
else if (animationChannelTargetPath === "translation" /* TRANSLATION */) {
|
|
663
|
+
if (convertToRightHandedSystem) {
|
|
664
|
+
_GLTFUtilities._GetRightHandedNormalArray3FromRef(value);
|
|
665
|
+
if (!babylonTransformNode.parent) {
|
|
666
|
+
value[0] *= -1;
|
|
667
|
+
value[2] *= -1;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
outputs.push(value); // scale vector.
|
|
672
|
+
}
|
|
673
|
+
else if (animationType === Animation.ANIMATIONTYPE_FLOAT) {
|
|
674
|
+
if (animationChannelTargetPath === "weights" /* WEIGHTS */) {
|
|
675
|
+
outputs.push([keyFrame.value]);
|
|
676
|
+
}
|
|
677
|
+
else {
|
|
678
|
+
// handles single component x, y, z or w component animation by using a base property and animating over a component.
|
|
679
|
+
newPositionRotationOrScale = this._ConvertFactorToVector3OrQuaternion(keyFrame.value, babylonTransformNode, animation, animationType, animationChannelTargetPath, convertToRightHandedSystem, useQuaternion);
|
|
680
|
+
if (newPositionRotationOrScale) {
|
|
681
|
+
if (animationChannelTargetPath === "rotation" /* ROTATION */) {
|
|
682
|
+
var posRotScale = useQuaternion
|
|
683
|
+
? newPositionRotationOrScale
|
|
684
|
+
: Quaternion.RotationYawPitchRoll(newPositionRotationOrScale.y, newPositionRotationOrScale.x, newPositionRotationOrScale.z).normalize();
|
|
685
|
+
if (convertToRightHandedSystem) {
|
|
686
|
+
_GLTFUtilities._GetRightHandedQuaternionFromRef(posRotScale);
|
|
687
|
+
if (!babylonTransformNode.parent) {
|
|
688
|
+
posRotScale = Quaternion.FromArray([0, 1, 0, 0]).multiply(posRotScale);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
outputs.push(posRotScale.asArray());
|
|
692
|
+
}
|
|
693
|
+
else if (animationChannelTargetPath === "translation" /* TRANSLATION */) {
|
|
694
|
+
if (convertToRightHandedSystem) {
|
|
695
|
+
_GLTFUtilities._GetRightHandedNormalVector3FromRef(newPositionRotationOrScale);
|
|
696
|
+
if (!babylonTransformNode.parent) {
|
|
697
|
+
newPositionRotationOrScale.x *= -1;
|
|
698
|
+
newPositionRotationOrScale.z *= -1;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
outputs.push(newPositionRotationOrScale.asArray());
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
else if (animationType === Animation.ANIMATIONTYPE_QUATERNION) {
|
|
707
|
+
value = keyFrame.value.normalize().asArray();
|
|
708
|
+
if (convertToRightHandedSystem) {
|
|
709
|
+
_GLTFUtilities._GetRightHandedQuaternionArrayFromRef(value);
|
|
710
|
+
if (!babylonTransformNode.parent) {
|
|
711
|
+
value = Quaternion.FromArray([0, 1, 0, 0]).multiply(Quaternion.FromArray(value)).asArray();
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
outputs.push(value);
|
|
715
|
+
}
|
|
716
|
+
else {
|
|
717
|
+
Tools.Error("glTFAnimation: Unsupported key frame values for animation!");
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
/**
|
|
721
|
+
* Determine the interpolation based on the key frames
|
|
722
|
+
* @param keyFrames
|
|
723
|
+
* @param animationChannelTargetPath
|
|
724
|
+
* @param useQuaternion
|
|
725
|
+
*/
|
|
726
|
+
_GLTFAnimation._DeduceInterpolation = function (keyFrames, animationChannelTargetPath, useQuaternion) {
|
|
727
|
+
var interpolationType;
|
|
728
|
+
var shouldBakeAnimation = false;
|
|
729
|
+
var key;
|
|
730
|
+
if (animationChannelTargetPath === "rotation" /* ROTATION */ && !useQuaternion) {
|
|
731
|
+
return { interpolationType: "LINEAR" /* LINEAR */, shouldBakeAnimation: true };
|
|
732
|
+
}
|
|
733
|
+
for (var i = 0, length_2 = keyFrames.length; i < length_2; ++i) {
|
|
734
|
+
key = keyFrames[i];
|
|
735
|
+
if (key.inTangent || key.outTangent) {
|
|
736
|
+
if (interpolationType) {
|
|
737
|
+
if (interpolationType !== "CUBICSPLINE" /* CUBICSPLINE */) {
|
|
738
|
+
interpolationType = "LINEAR" /* LINEAR */;
|
|
739
|
+
shouldBakeAnimation = true;
|
|
740
|
+
break;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
else {
|
|
744
|
+
interpolationType = "CUBICSPLINE" /* CUBICSPLINE */;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
if (interpolationType) {
|
|
749
|
+
if (interpolationType === "CUBICSPLINE" /* CUBICSPLINE */ ||
|
|
750
|
+
(key.interpolation && key.interpolation === AnimationKeyInterpolation.STEP && interpolationType !== "STEP" /* STEP */)) {
|
|
751
|
+
interpolationType = "LINEAR" /* LINEAR */;
|
|
752
|
+
shouldBakeAnimation = true;
|
|
753
|
+
break;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
else {
|
|
757
|
+
if (key.interpolation && key.interpolation === AnimationKeyInterpolation.STEP) {
|
|
758
|
+
interpolationType = "STEP" /* STEP */;
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
interpolationType = "LINEAR" /* LINEAR */;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
if (!interpolationType) {
|
|
767
|
+
interpolationType = "LINEAR" /* LINEAR */;
|
|
768
|
+
}
|
|
769
|
+
return { interpolationType: interpolationType, shouldBakeAnimation: shouldBakeAnimation };
|
|
770
|
+
};
|
|
771
|
+
/**
|
|
772
|
+
* Adds an input tangent or output tangent to the output data
|
|
773
|
+
* If an input tangent or output tangent is missing, it uses the zero vector or zero quaternion
|
|
774
|
+
* @param babylonTransformNode
|
|
775
|
+
* @param tangentType Specifies which type of tangent to handle (inTangent or outTangent)
|
|
776
|
+
* @param outputs The animation data by keyframe
|
|
777
|
+
* @param animationChannelTargetPath The target animation channel
|
|
778
|
+
* @param interpolation The interpolation type
|
|
779
|
+
* @param keyFrame The key frame with the animation data
|
|
780
|
+
* @param frameDelta Time difference between two frames used to scale the tangent by the frame delta
|
|
781
|
+
* @param useQuaternion Specifies if quaternions are used
|
|
782
|
+
* @param convertToRightHandedSystem Specifies if the values should be converted to right-handed
|
|
783
|
+
*/
|
|
784
|
+
_GLTFAnimation._AddSplineTangent = function (babylonTransformNode, tangentType, outputs, animationChannelTargetPath, interpolation, keyFrame, frameDelta, useQuaternion, convertToRightHandedSystem) {
|
|
785
|
+
var tangent;
|
|
786
|
+
var tangentValue = tangentType === _TangentType.INTANGENT ? keyFrame.inTangent : keyFrame.outTangent;
|
|
787
|
+
if (interpolation === "CUBICSPLINE" /* CUBICSPLINE */) {
|
|
788
|
+
if (animationChannelTargetPath === "rotation" /* ROTATION */) {
|
|
789
|
+
if (tangentValue) {
|
|
790
|
+
if (useQuaternion) {
|
|
791
|
+
tangent = tangentValue.asArray();
|
|
792
|
+
}
|
|
793
|
+
else {
|
|
794
|
+
var array = tangentValue;
|
|
795
|
+
tangent = Quaternion.RotationYawPitchRoll(array.y, array.x, array.z).asArray();
|
|
796
|
+
}
|
|
797
|
+
if (convertToRightHandedSystem) {
|
|
798
|
+
_GLTFUtilities._GetRightHandedQuaternionArrayFromRef(tangent);
|
|
799
|
+
if (!babylonTransformNode.parent) {
|
|
800
|
+
tangent = Quaternion.FromArray([0, 1, 0, 0]).multiply(Quaternion.FromArray(tangent)).asArray();
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
else {
|
|
805
|
+
tangent = [0, 0, 0, 0];
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
else if (animationChannelTargetPath === "weights" /* WEIGHTS */) {
|
|
809
|
+
if (tangentValue) {
|
|
810
|
+
tangent = [tangentValue];
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
tangent = [0];
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
else {
|
|
817
|
+
if (tangentValue) {
|
|
818
|
+
tangent = tangentValue.asArray();
|
|
819
|
+
if (convertToRightHandedSystem) {
|
|
820
|
+
if (animationChannelTargetPath === "translation" /* TRANSLATION */) {
|
|
821
|
+
_GLTFUtilities._GetRightHandedPositionArray3FromRef(tangent);
|
|
822
|
+
if (!babylonTransformNode.parent) {
|
|
823
|
+
tangent[0] *= -1; // x
|
|
824
|
+
tangent[2] *= -1; // z
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
else {
|
|
830
|
+
tangent = [0, 0, 0];
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
outputs.push(tangent);
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
/**
|
|
837
|
+
* Get the minimum and maximum key frames' frame values
|
|
838
|
+
* @param keyFrames animation key frames
|
|
839
|
+
* @returns the minimum and maximum key frame value
|
|
840
|
+
*/
|
|
841
|
+
_GLTFAnimation._CalculateMinMaxKeyFrames = function (keyFrames) {
|
|
842
|
+
var min = Infinity;
|
|
843
|
+
var max = -Infinity;
|
|
844
|
+
keyFrames.forEach(function (keyFrame) {
|
|
845
|
+
min = Math.min(min, keyFrame.frame);
|
|
846
|
+
max = Math.max(max, keyFrame.frame);
|
|
847
|
+
});
|
|
848
|
+
return { min: min, max: max };
|
|
849
|
+
};
|
|
850
|
+
return _GLTFAnimation;
|
|
851
|
+
}());
|
|
852
|
+
export { _GLTFAnimation };
|
|
853
853
|
//# sourceMappingURL=glTFAnimation.js.map
|