@zephyr3d/scene 0.8.2 → 0.9.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/dist/animation/animationset.js +473 -60
- package/dist/animation/animationset.js.map +1 -1
- package/dist/animation/cloth/gpu_cloth_system.js +2516 -0
- package/dist/animation/cloth/gpu_cloth_system.js.map +1 -0
- package/dist/animation/fixed_geometry_cache_track.js +138 -0
- package/dist/animation/fixed_geometry_cache_track.js.map +1 -0
- package/dist/animation/geometry_cache_utils.js +120 -0
- package/dist/animation/geometry_cache_utils.js.map +1 -0
- package/dist/animation/ik_modifier.js +9 -1
- package/dist/animation/ik_modifier.js.map +1 -1
- package/dist/animation/joint_dynamics/collision.js +469 -0
- package/dist/animation/joint_dynamics/collision.js.map +1 -0
- package/dist/animation/joint_dynamics/constraints.js +329 -0
- package/dist/animation/joint_dynamics/constraints.js.map +1 -0
- package/dist/animation/joint_dynamics/controller.js +699 -0
- package/dist/animation/joint_dynamics/controller.js.map +1 -0
- package/dist/animation/joint_dynamics/joint_dynamics_system.js +393 -0
- package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -0
- package/dist/animation/joint_dynamics/solver.js +794 -0
- package/dist/animation/joint_dynamics/solver.js.map +1 -0
- package/dist/animation/joint_dynamics/types.js +19 -0
- package/dist/animation/joint_dynamics/types.js.map +1 -0
- package/dist/animation/joint_dynamics/vrm_spring_bone.js +46 -0
- package/dist/animation/joint_dynamics/vrm_spring_bone.js.map +1 -0
- package/dist/animation/joint_dynamics_modifier.js +51 -0
- package/dist/animation/joint_dynamics_modifier.js.map +1 -0
- package/dist/animation/pca_geometry_cache_track.js +222 -0
- package/dist/animation/pca_geometry_cache_track.js.map +1 -0
- package/dist/animation/skeleton.js +2011 -139
- package/dist/animation/skeleton.js.map +1 -1
- package/dist/animation/skeleton_modifier.js +3 -5
- package/dist/animation/skeleton_modifier.js.map +1 -1
- package/dist/animation/spring/multi_chain_spring_system.js +2 -0
- package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
- package/dist/animation/spring/spring_chain.js +3 -2
- package/dist/animation/spring/spring_chain.js.map +1 -1
- package/dist/animation/spring/spring_collider.js +35 -5
- package/dist/animation/spring/spring_collider.js.map +1 -1
- package/dist/animation/spring/spring_particle.js +1 -0
- package/dist/animation/spring/spring_particle.js.map +1 -1
- package/dist/animation/spring/spring_system.js +325 -28
- package/dist/animation/spring/spring_system.js.map +1 -1
- package/dist/animation/spring2/collision.js +469 -0
- package/dist/animation/spring2/collision.js.map +1 -0
- package/dist/animation/spring2/constraints.js +329 -0
- package/dist/animation/spring2/constraints.js.map +1 -0
- package/dist/animation/spring2/controller.js +434 -0
- package/dist/animation/spring2/controller.js.map +1 -0
- package/dist/animation/spring2/math.js +16 -0
- package/dist/animation/spring2/math.js.map +1 -0
- package/dist/animation/spring2/solver.js +624 -0
- package/dist/animation/spring2/solver.js.map +1 -0
- package/dist/animation/spring2/spring_system.js +118 -0
- package/dist/animation/spring2/spring_system.js.map +1 -0
- package/dist/animation/spring2/types.js +19 -0
- package/dist/animation/spring2/types.js.map +1 -0
- package/dist/animation/spring_modifier.js +17 -1
- package/dist/animation/spring_modifier.js.map +1 -1
- package/dist/app/engine.js +42 -15
- package/dist/app/engine.js.map +1 -1
- package/dist/app/runtimescript.js +132 -1
- package/dist/app/runtimescript.js.map +1 -1
- package/dist/app/screen.js +3 -3
- package/dist/app/screen.js.map +1 -1
- package/dist/app/scriptingsystem.js +69 -37
- package/dist/app/scriptingsystem.js.map +1 -1
- package/dist/app/scriptregistry.js +157 -146
- package/dist/app/scriptregistry.js.map +1 -1
- package/dist/asset/assetmanager.js +2 -1
- package/dist/asset/assetmanager.js.map +1 -1
- package/dist/asset/loaders/zabc/zabc_loader.js +570 -0
- package/dist/asset/loaders/zabc/zabc_loader.js.map +1 -0
- package/dist/asset/model.js +192 -0
- package/dist/asset/model.js.map +1 -1
- package/dist/camera/base.js +26 -7
- package/dist/camera/base.js.map +1 -1
- package/dist/camera/camera.js +146 -24
- package/dist/camera/camera.js.map +1 -1
- package/dist/camera/fps.js +2 -2
- package/dist/camera/fps.js.map +1 -1
- package/dist/camera/orbit.js +2 -2
- package/dist/camera/orbit.js.map +1 -1
- package/dist/index.d.ts +11728 -8535
- package/dist/index.js +29 -8
- package/dist/index.js.map +1 -1
- package/dist/material/lambert.js +1 -1
- package/dist/material/lambert.js.map +1 -1
- package/dist/material/material.js +9 -3
- package/dist/material/material.js.map +1 -1
- package/dist/material/meshmaterial.js +54 -7
- package/dist/material/meshmaterial.js.map +1 -1
- package/dist/material/mixins/lightmodel/blinnphong.js +17 -7
- package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
- package/dist/material/mixins/lightmodel/lambert.js +7 -2
- package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +108 -16
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +222 -14
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js +24 -12
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
- package/dist/material/mixins/lit.js +11 -8
- package/dist/material/mixins/lit.js.map +1 -1
- package/dist/material/mixins/pbr/common.js +72 -5
- package/dist/material/mixins/pbr/common.js.map +1 -1
- package/dist/material/pbrblueprint.js +148 -1
- package/dist/material/pbrblueprint.js.map +1 -1
- package/dist/material/pbrmr.js +125 -2
- package/dist/material/pbrmr.js.map +1 -1
- package/dist/material/shader/helper.js +10 -4
- package/dist/material/shader/helper.js.map +1 -1
- package/dist/material/water.js +2 -2
- package/dist/material/water.js.map +1 -1
- package/dist/posteffect/coloradjust.js +145 -0
- package/dist/posteffect/coloradjust.js.map +1 -0
- package/dist/posteffect/taa.js +68 -32
- package/dist/posteffect/taa.js.map +1 -1
- package/dist/render/cluster_light.js +17 -12
- package/dist/render/cluster_light.js.map +1 -1
- package/dist/render/deferredlightpass.js +510 -0
- package/dist/render/deferredlightpass.js.map +1 -0
- package/dist/render/deferredshadowlightpass.js +428 -0
- package/dist/render/deferredshadowlightpass.js.map +1 -0
- package/dist/render/drawable.js.map +1 -1
- package/dist/render/drawable_mixin.js +21 -12
- package/dist/render/drawable_mixin.js.map +1 -1
- package/dist/render/envlight.js +20 -22
- package/dist/render/envlight.js.map +1 -1
- package/dist/render/gbufferpass.js +50 -0
- package/dist/render/gbufferpass.js.map +1 -0
- package/dist/render/lightpass.js +1 -2
- package/dist/render/lightpass.js.map +1 -1
- package/dist/render/primitive.js +1 -1
- package/dist/render/primitive.js.map +1 -1
- package/dist/render/render_queue.js +3 -2
- package/dist/render/render_queue.js.map +1 -1
- package/dist/render/renderer.js +5 -358
- package/dist/render/renderer.js.map +1 -1
- package/dist/render/rendergraph/executor.js +15 -12
- package/dist/render/rendergraph/executor.js.map +1 -1
- package/dist/render/rendergraph/forward_plus_builder.js +144 -88
- package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
- package/dist/render/rendergraph/history_resource_manager.js +178 -0
- package/dist/render/rendergraph/history_resource_manager.js.map +1 -0
- package/dist/render/rendergraph/rendergraph.js +12 -1
- package/dist/render/rendergraph/rendergraph.js.map +1 -1
- package/dist/render/rendergraph/types.js +2 -2
- package/dist/render/rendergraph/types.js.map +1 -1
- package/dist/render/sky.js +26 -9
- package/dist/render/sky.js.map +1 -1
- package/dist/scene/basesprite.js +4 -3
- package/dist/scene/basesprite.js.map +1 -1
- package/dist/scene/batchgroup.js +4 -4
- package/dist/scene/environment.js +7 -4
- package/dist/scene/environment.js.map +1 -1
- package/dist/scene/light.js +184 -18
- package/dist/scene/light.js.map +1 -1
- package/dist/scene/mesh.js +30 -0
- package/dist/scene/mesh.js.map +1 -1
- package/dist/scene/particlesys.js +3 -2
- package/dist/scene/particlesys.js.map +1 -1
- package/dist/scene/raycast_visitor.js +29 -3
- package/dist/scene/raycast_visitor.js.map +1 -1
- package/dist/scene/scene.js +86 -19
- package/dist/scene/scene.js.map +1 -1
- package/dist/scene/scene_node.js +87 -31
- package/dist/scene/scene_node.js.map +1 -1
- package/dist/scene/script_attachment.js +59 -0
- package/dist/scene/script_attachment.js.map +1 -0
- package/dist/scene/terrain-cm/grass.js +3 -2
- package/dist/scene/terrain-cm/grass.js.map +1 -1
- package/dist/scene/terrain-cm/terrain-cm.js +4 -3
- package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
- package/dist/scene/water.js +3 -2
- package/dist/scene/water.js.map +1 -1
- package/dist/shaders/shadow.js +2 -2
- package/dist/shaders/shadow.js.map +1 -1
- package/dist/shadow/shadowmapper.js +74 -4
- package/dist/shadow/shadowmapper.js.map +1 -1
- package/dist/shapes/box.js +163 -0
- package/dist/shapes/box.js.map +1 -1
- package/dist/shapes/capsule.js +216 -0
- package/dist/shapes/capsule.js.map +1 -0
- package/dist/shapes/cylinder.js +91 -0
- package/dist/shapes/cylinder.js.map +1 -1
- package/dist/shapes/plane.js +32 -0
- package/dist/shapes/plane.js.map +1 -1
- package/dist/shapes/tetrahedron.js +211 -0
- package/dist/shapes/tetrahedron.js.map +1 -1
- package/dist/shapes/torus.js +173 -0
- package/dist/shapes/torus.js.map +1 -1
- package/dist/utility/blueprint/common/math.js +111 -1
- package/dist/utility/blueprint/common/math.js.map +1 -1
- package/dist/utility/blueprint/material/inputs.js +235 -1
- package/dist/utility/blueprint/material/inputs.js.map +1 -1
- package/dist/utility/blueprint/material/ir.js +154 -10
- package/dist/utility/blueprint/material/ir.js.map +1 -1
- package/dist/utility/blueprint/material/texture.js +273 -19
- package/dist/utility/blueprint/material/texture.js.map +1 -1
- package/dist/utility/serialization/json.js +12 -2
- package/dist/utility/serialization/json.js.map +1 -1
- package/dist/utility/serialization/manager.js +30 -11
- package/dist/utility/serialization/manager.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +250 -7
- package/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/utility/serialization/scene/batch.js +4 -2
- package/dist/utility/serialization/scene/batch.js.map +1 -1
- package/dist/utility/serialization/scene/camera.js +154 -2
- package/dist/utility/serialization/scene/camera.js.map +1 -1
- package/dist/utility/serialization/scene/cloth_script.js +834 -0
- package/dist/utility/serialization/scene/cloth_script.js.map +1 -0
- package/dist/utility/serialization/scene/common.js +7 -0
- package/dist/utility/serialization/scene/common.js.map +1 -1
- package/dist/utility/serialization/scene/light.js +120 -4
- package/dist/utility/serialization/scene/light.js.map +1 -1
- package/dist/utility/serialization/scene/material.js +453 -1
- package/dist/utility/serialization/scene/material.js.map +1 -1
- package/dist/utility/serialization/scene/mesh.js +4 -2
- package/dist/utility/serialization/scene/mesh.js.map +1 -1
- package/dist/utility/serialization/scene/node.js +298 -10
- package/dist/utility/serialization/scene/node.js.map +1 -1
- package/dist/utility/serialization/scene/particle.js +4 -2
- package/dist/utility/serialization/scene/particle.js.map +1 -1
- package/dist/utility/serialization/scene/primitive.js +100 -3
- package/dist/utility/serialization/scene/primitive.js.map +1 -1
- package/dist/utility/serialization/scene/scene.js +130 -3
- package/dist/utility/serialization/scene/scene.js.map +1 -1
- package/dist/utility/serialization/scene/script.js +66 -0
- package/dist/utility/serialization/scene/script.js.map +1 -0
- package/dist/utility/serialization/scene/spring_script.js +596 -0
- package/dist/utility/serialization/scene/spring_script.js.map +1 -0
- package/dist/utility/serialization/scene/sprite.js +5 -3
- package/dist/utility/serialization/scene/sprite.js.map +1 -1
- package/dist/utility/serialization/scene/terrain.js +4 -2
- package/dist/utility/serialization/scene/terrain.js.map +1 -1
- package/dist/utility/serialization/scene/water.js +4 -2
- package/dist/utility/serialization/scene/water.js.map +1 -1
- package/dist/utility/serialization/types.js.map +1 -1
- package/dist/values.js +5 -1
- package/dist/values.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,11 +1,297 @@
|
|
|
1
|
-
import { Disposable, weightedAverage, Interpolator } from '@zephyr3d/base';
|
|
1
|
+
import { Disposable, weightedAverage, Quaternion, Interpolator, Vector3 } from '@zephyr3d/base';
|
|
2
2
|
import { AnimationClip } from './animation.js';
|
|
3
3
|
import { NodeRotationTrack } from './rotationtrack.js';
|
|
4
4
|
import { NodeEulerRotationTrack } from './eulerrotationtrack.js';
|
|
5
5
|
import { NodeTranslationTrack } from './translationtrack.js';
|
|
6
6
|
import { NodeScaleTrack } from './scaletrack.js';
|
|
7
|
-
import { Skeleton } from './skeleton.js';
|
|
7
|
+
import { Skeleton, HumanoidBodyRig } from './skeleton.js';
|
|
8
8
|
|
|
9
|
+
function cloneInterpolator(src) {
|
|
10
|
+
return new Interpolator(src.mode, src.target, src.inputs instanceof Float32Array ? new Float32Array(src.inputs) : [
|
|
11
|
+
...src.inputs
|
|
12
|
+
], src.outputs instanceof Float32Array ? new Float32Array(src.outputs) : [
|
|
13
|
+
...src.outputs
|
|
14
|
+
]);
|
|
15
|
+
}
|
|
16
|
+
function createJointRetargetRemap(srcSkeleton, dstSkeleton, srcJoint, dstJoint, translationRotation) {
|
|
17
|
+
const si = srcSkeleton.joints.indexOf(srcJoint);
|
|
18
|
+
const di = dstSkeleton.joints.indexOf(dstJoint);
|
|
19
|
+
const srcBindPose = srcSkeleton.bindPose[si];
|
|
20
|
+
const dstBindPose = dstSkeleton.bindPose[di];
|
|
21
|
+
const srcLen = srcBindPose.position.magnitude;
|
|
22
|
+
const dstLen = dstBindPose.position.magnitude;
|
|
23
|
+
return {
|
|
24
|
+
dstNode: dstJoint,
|
|
25
|
+
dstJointIndex: di,
|
|
26
|
+
srcNode: srcJoint,
|
|
27
|
+
srcBindRotInv: Quaternion.inverse(srcBindPose.rotation),
|
|
28
|
+
dstBindRot: dstBindPose.rotation.clone(),
|
|
29
|
+
srcBindPos: srcBindPose.position.clone(),
|
|
30
|
+
dstBindPos: dstBindPose.position.clone(),
|
|
31
|
+
translationScale: srcLen > 1e-6 ? dstLen / srcLen : 1,
|
|
32
|
+
translationRotation
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function retargetRotation(qSrcAnim, remap, out) {
|
|
36
|
+
Quaternion.multiply(remap.srcBindRotInv, qSrcAnim, out);
|
|
37
|
+
Quaternion.multiply(remap.dstBindRot, out, out);
|
|
38
|
+
return out.inplaceNormalize();
|
|
39
|
+
}
|
|
40
|
+
function retargetRotationTangent(qSrcTangent, remap, out) {
|
|
41
|
+
Quaternion.multiply(remap.srcBindRotInv, qSrcTangent, out);
|
|
42
|
+
Quaternion.multiply(remap.dstBindRot, out, out);
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
function retargetTranslationValue(srcValue, remap, out) {
|
|
46
|
+
out.setXYZ(srcValue.x, srcValue.y, srcValue.z);
|
|
47
|
+
out.subBy(remap.srcBindPos);
|
|
48
|
+
out.scaleBy(remap.translationScale);
|
|
49
|
+
if (remap.translationRotation) {
|
|
50
|
+
remap.translationRotation.transform(out, out);
|
|
51
|
+
}
|
|
52
|
+
out.addBy(remap.dstBindPos);
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
function retargetTranslationTangent(srcValue, remap, out) {
|
|
56
|
+
out.setXYZ(srcValue.x, srcValue.y, srcValue.z);
|
|
57
|
+
out.scaleBy(remap.translationScale);
|
|
58
|
+
if (remap.translationRotation) {
|
|
59
|
+
remap.translationRotation.transform(out, out);
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
function retargetRotationTrack(src, remap) {
|
|
64
|
+
const isCubic = src.interpolator.mode === 'cubicspline';
|
|
65
|
+
const frameStride = isCubic ? 12 : 4;
|
|
66
|
+
const numFrames = src.interpolator.inputs.length;
|
|
67
|
+
const srcOutputs = src.interpolator.outputs;
|
|
68
|
+
const newOutputs = new Float32Array(srcOutputs.length);
|
|
69
|
+
const t = isCubic ? 4 : 0;
|
|
70
|
+
const q = new Quaternion();
|
|
71
|
+
for(let f = 0; f < numFrames; f++){
|
|
72
|
+
const base = f * frameStride;
|
|
73
|
+
q.setXYZW(srcOutputs[base + t], srcOutputs[base + t + 1], srcOutputs[base + t + 2], srcOutputs[base + t + 3]);
|
|
74
|
+
retargetRotation(q, remap, q);
|
|
75
|
+
if (isCubic) {
|
|
76
|
+
// Cubic quaternion tangents live in the same component space, so apply the
|
|
77
|
+
// same constant bind-pose transform without normalizing them.
|
|
78
|
+
q.setXYZW(srcOutputs[base], srcOutputs[base + 1], srcOutputs[base + 2], srcOutputs[base + 3]);
|
|
79
|
+
newOutputs.set(retargetRotationTangent(q, remap, q), base);
|
|
80
|
+
newOutputs.set(retargetRotation(new Quaternion(srcOutputs.subarray(base + 4, base + 8)), remap, q), base + 4);
|
|
81
|
+
q.setXYZW(srcOutputs[base + 8], srcOutputs[base + 9], srcOutputs[base + 10], srcOutputs[base + 11]);
|
|
82
|
+
newOutputs.set(retargetRotationTangent(q, remap, q), base + 8);
|
|
83
|
+
} else {
|
|
84
|
+
newOutputs.set(q, base);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return new NodeRotationTrack(new Interpolator(src.interpolator.mode, 'quat', new Float32Array(src.interpolator.inputs), newOutputs));
|
|
88
|
+
}
|
|
89
|
+
function retargetEulerToRotationTrack(src, remap) {
|
|
90
|
+
const srcInputs = src.interpolator.inputs;
|
|
91
|
+
const srcOutputs = src.interpolator.outputs;
|
|
92
|
+
const isCubic = src.interpolator.mode === 'cubicspline';
|
|
93
|
+
const frameStride = isCubic ? 9 : 3;
|
|
94
|
+
const t = isCubic ? 3 : 0;
|
|
95
|
+
const numFrames = srcInputs.length;
|
|
96
|
+
const newOutputs = new Float32Array(numFrames * 4);
|
|
97
|
+
const q = new Quaternion();
|
|
98
|
+
for(let f = 0; f < numFrames; f++){
|
|
99
|
+
const base = f * frameStride + t;
|
|
100
|
+
q.fromEulerAngle(srcOutputs[base], srcOutputs[base + 1], srcOutputs[base + 2]);
|
|
101
|
+
retargetRotation(q, remap, q);
|
|
102
|
+
newOutputs.set(q, f * 4);
|
|
103
|
+
}
|
|
104
|
+
return new NodeRotationTrack(new Interpolator(src.interpolator.mode === 'step' ? 'step' : 'linear', 'quat', new Float32Array(srcInputs), newOutputs));
|
|
105
|
+
}
|
|
106
|
+
function retargetTranslationTrack(src, remap) {
|
|
107
|
+
const isCubic = src.interpolator.mode === 'cubicspline';
|
|
108
|
+
const frameStride = isCubic ? 9 : 3;
|
|
109
|
+
const numFrames = src.interpolator.inputs.length;
|
|
110
|
+
const srcOutputs = src.interpolator.outputs;
|
|
111
|
+
const newOutputs = new Float32Array(srcOutputs.length);
|
|
112
|
+
const t = isCubic ? 3 : 0;
|
|
113
|
+
const v = new Vector3();
|
|
114
|
+
for(let f = 0; f < numFrames; f++){
|
|
115
|
+
const base = f * frameStride;
|
|
116
|
+
v.setXYZ(srcOutputs[base + t], srcOutputs[base + t + 1], srcOutputs[base + t + 2]);
|
|
117
|
+
retargetTranslationValue(v, remap, v);
|
|
118
|
+
if (isCubic) {
|
|
119
|
+
v.setXYZ(srcOutputs[base], srcOutputs[base + 1], srcOutputs[base + 2]);
|
|
120
|
+
newOutputs.set(retargetTranslationTangent(v, remap, v), base);
|
|
121
|
+
v.setXYZ(srcOutputs[base + 3], srcOutputs[base + 4], srcOutputs[base + 5]);
|
|
122
|
+
newOutputs.set(retargetTranslationValue(v, remap, v), base + 3);
|
|
123
|
+
v.setXYZ(srcOutputs[base + 6], srcOutputs[base + 7], srcOutputs[base + 8]);
|
|
124
|
+
newOutputs.set(retargetTranslationTangent(v, remap, v), base + 6);
|
|
125
|
+
} else {
|
|
126
|
+
newOutputs.set(v, base);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return new NodeTranslationTrack(new Interpolator(src.interpolator.mode, 'vec3', new Float32Array(src.interpolator.inputs), newOutputs));
|
|
130
|
+
}
|
|
131
|
+
function findRotationTrack(tracks) {
|
|
132
|
+
return tracks?.find((track)=>track instanceof NodeRotationTrack || track instanceof NodeEulerRotationTrack) ?? null;
|
|
133
|
+
}
|
|
134
|
+
function collectTrackTimes(track, times) {
|
|
135
|
+
if (track instanceof NodeRotationTrack || track instanceof NodeEulerRotationTrack) {
|
|
136
|
+
for (const time of track.interpolator.inputs){
|
|
137
|
+
times.add(time);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function sampleRotationTrack(track, time, fallback, out) {
|
|
142
|
+
if (!track) {
|
|
143
|
+
out.set(fallback);
|
|
144
|
+
return out;
|
|
145
|
+
}
|
|
146
|
+
const state = track.calculateState({}, time);
|
|
147
|
+
out.set(state);
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRootRotation, dstRootRotation, dstClip, remaps) {
|
|
151
|
+
const rotationTracksByRemap = new Map();
|
|
152
|
+
const times = new Set([
|
|
153
|
+
0,
|
|
154
|
+
sourceClip.timeDuration
|
|
155
|
+
]);
|
|
156
|
+
const remapsByDstNode = new Map();
|
|
157
|
+
const srcJointSet = new Set(srcSkeleton.joints);
|
|
158
|
+
const dstJointSet = new Set(dstSkeleton.joints);
|
|
159
|
+
const srcBindRotByNode = new Map();
|
|
160
|
+
const dstBindRotByNode = new Map();
|
|
161
|
+
const srcRotationTrackByNode = new Map();
|
|
162
|
+
for(let i = 0; i < srcSkeleton.joints.length; i++){
|
|
163
|
+
const joint = srcSkeleton.joints[i];
|
|
164
|
+
srcBindRotByNode.set(joint, srcSkeleton.bindPose[i].rotation);
|
|
165
|
+
const track = findRotationTrack(sourceClip.tracks.get(joint));
|
|
166
|
+
srcRotationTrackByNode.set(joint, track);
|
|
167
|
+
collectTrackTimes(track, times);
|
|
168
|
+
}
|
|
169
|
+
for(let i = 0; i < dstSkeleton.joints.length; i++){
|
|
170
|
+
dstBindRotByNode.set(dstSkeleton.joints[i], dstSkeleton.bindPose[i].rotation);
|
|
171
|
+
}
|
|
172
|
+
for (const remap of remaps){
|
|
173
|
+
const track = findRotationTrack(sourceClip.tracks.get(remap.srcNode));
|
|
174
|
+
rotationTracksByRemap.set(remap, track);
|
|
175
|
+
remapsByDstNode.set(remap.dstNode, remap);
|
|
176
|
+
}
|
|
177
|
+
const inputs = new Float32Array([
|
|
178
|
+
...times
|
|
179
|
+
].sort((a, b)=>a - b));
|
|
180
|
+
const srcBindWorldRots = new Map();
|
|
181
|
+
const dstBindWorldRots = new Map();
|
|
182
|
+
const srcAnimWorldRots = new Map();
|
|
183
|
+
const dstAnimWorldRots = new Map();
|
|
184
|
+
const outputsByRemap = new Map();
|
|
185
|
+
const tmpLocalRot = new Quaternion();
|
|
186
|
+
const tmpWorldDelta = new Quaternion();
|
|
187
|
+
const tmpParentInv = new Quaternion();
|
|
188
|
+
for (const remap of remaps){
|
|
189
|
+
outputsByRemap.set(remap, new Float32Array(inputs.length * 4));
|
|
190
|
+
}
|
|
191
|
+
function getSrcBindWorldRot(node) {
|
|
192
|
+
let rot = srcBindWorldRots.get(node);
|
|
193
|
+
if (!rot) {
|
|
194
|
+
rot = (srcBindRotByNode.get(node) ?? Quaternion.identity()).clone();
|
|
195
|
+
const parent = node.parent;
|
|
196
|
+
if (parent && srcJointSet.has(parent)) {
|
|
197
|
+
Quaternion.multiply(getSrcBindWorldRot(parent), rot, rot);
|
|
198
|
+
} else {
|
|
199
|
+
Quaternion.multiply(srcRootRotation, rot, rot);
|
|
200
|
+
}
|
|
201
|
+
srcBindWorldRots.set(node, rot);
|
|
202
|
+
}
|
|
203
|
+
return rot;
|
|
204
|
+
}
|
|
205
|
+
function getDstBindWorldRot(node) {
|
|
206
|
+
let rot = dstBindWorldRots.get(node);
|
|
207
|
+
if (!rot) {
|
|
208
|
+
rot = (dstBindRotByNode.get(node) ?? Quaternion.identity()).clone();
|
|
209
|
+
const parent = node.parent;
|
|
210
|
+
if (parent && dstJointSet.has(parent)) {
|
|
211
|
+
Quaternion.multiply(getDstBindWorldRot(parent), rot, rot);
|
|
212
|
+
} else {
|
|
213
|
+
Quaternion.multiply(dstRootRotation, rot, rot);
|
|
214
|
+
}
|
|
215
|
+
dstBindWorldRots.set(node, rot);
|
|
216
|
+
}
|
|
217
|
+
return rot;
|
|
218
|
+
}
|
|
219
|
+
function getSrcAnimWorldRot(node, time) {
|
|
220
|
+
let rot = srcAnimWorldRots.get(node);
|
|
221
|
+
if (!rot) {
|
|
222
|
+
rot = new Quaternion();
|
|
223
|
+
srcAnimWorldRots.set(node, rot);
|
|
224
|
+
}
|
|
225
|
+
const parent = node.parent;
|
|
226
|
+
const parentWorldRot = parent && srcJointSet.has(parent) ? getSrcAnimWorldRot(parent, time) : null;
|
|
227
|
+
sampleRotationTrack(srcRotationTrackByNode.get(node) ?? null, time, srcBindRotByNode.get(node) ?? Quaternion.identity(), tmpLocalRot);
|
|
228
|
+
if (parentWorldRot) {
|
|
229
|
+
Quaternion.multiply(parentWorldRot, tmpLocalRot, rot);
|
|
230
|
+
} else {
|
|
231
|
+
Quaternion.multiply(srcRootRotation, tmpLocalRot, rot);
|
|
232
|
+
}
|
|
233
|
+
return rot;
|
|
234
|
+
}
|
|
235
|
+
function getDstAnimWorldRot(remap, time) {
|
|
236
|
+
let rot = dstAnimWorldRots.get(remap.dstNode);
|
|
237
|
+
if (!rot) {
|
|
238
|
+
rot = new Quaternion();
|
|
239
|
+
dstAnimWorldRots.set(remap.dstNode, rot);
|
|
240
|
+
}
|
|
241
|
+
const srcBindWorldRot = getSrcBindWorldRot(remap.srcNode);
|
|
242
|
+
const srcAnimWorldRot = getSrcAnimWorldRot(remap.srcNode, time);
|
|
243
|
+
Quaternion.multiply(srcAnimWorldRot, Quaternion.inverse(srcBindWorldRot, tmpWorldDelta), tmpWorldDelta);
|
|
244
|
+
Quaternion.multiply(tmpWorldDelta, getDstBindWorldRot(remap.dstNode), rot);
|
|
245
|
+
return rot;
|
|
246
|
+
}
|
|
247
|
+
function getDstParentAnimWorldRot(node, time) {
|
|
248
|
+
const parent = node.parent;
|
|
249
|
+
if (!parent || !dstJointSet.has(parent)) {
|
|
250
|
+
return dstRootRotation;
|
|
251
|
+
}
|
|
252
|
+
const mappedParent = remapsByDstNode.get(parent);
|
|
253
|
+
if (mappedParent) {
|
|
254
|
+
return getDstAnimWorldRot(mappedParent, time);
|
|
255
|
+
}
|
|
256
|
+
let rot = dstAnimWorldRots.get(parent);
|
|
257
|
+
if (!rot) {
|
|
258
|
+
rot = (dstBindRotByNode.get(parent) ?? Quaternion.identity()).clone();
|
|
259
|
+
const parentWorldRot = getDstParentAnimWorldRot(parent, time);
|
|
260
|
+
if (parentWorldRot) {
|
|
261
|
+
Quaternion.multiply(parentWorldRot, rot, rot);
|
|
262
|
+
}
|
|
263
|
+
dstAnimWorldRots.set(parent, rot);
|
|
264
|
+
}
|
|
265
|
+
return rot;
|
|
266
|
+
}
|
|
267
|
+
for(let i = 0; i < inputs.length; i++){
|
|
268
|
+
const time = inputs[i];
|
|
269
|
+
srcAnimWorldRots.clear();
|
|
270
|
+
dstAnimWorldRots.clear();
|
|
271
|
+
for (const remap of remaps){
|
|
272
|
+
const dstAnimWorldRot = getDstAnimWorldRot(remap, time);
|
|
273
|
+
const parentWorldRot = getDstParentAnimWorldRot(remap.dstNode, time);
|
|
274
|
+
if (parentWorldRot) {
|
|
275
|
+
Quaternion.multiply(Quaternion.inverse(parentWorldRot, tmpParentInv), dstAnimWorldRot, tmpLocalRot);
|
|
276
|
+
} else {
|
|
277
|
+
tmpLocalRot.set(dstAnimWorldRot);
|
|
278
|
+
}
|
|
279
|
+
tmpLocalRot.inplaceNormalize();
|
|
280
|
+
outputsByRemap.get(remap).set(tmpLocalRot, i * 4);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
for (const remap of remaps){
|
|
284
|
+
if (!rotationTracksByRemap.get(remap)) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
const outputs = new Float32Array(outputsByRemap.get(remap));
|
|
288
|
+
const track = new NodeRotationTrack(new Interpolator('linear', 'quat', new Float32Array(inputs), outputs));
|
|
289
|
+
track.name = 'rotation';
|
|
290
|
+
track.target = remap.dstNode.persistentId;
|
|
291
|
+
track.jointIndex = remap.dstJointIndex;
|
|
292
|
+
dstClip.addTrack(remap.dstNode, track);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
9
295
|
/**
|
|
10
296
|
* Animation set
|
|
11
297
|
*
|
|
@@ -332,6 +618,185 @@ import { Skeleton } from './skeleton.js';
|
|
|
332
618
|
}
|
|
333
619
|
}
|
|
334
620
|
/**
|
|
621
|
+
* Copy a humanoid animation clip from another AnimationSet into this one via humanoid rig mapping.
|
|
622
|
+
*
|
|
623
|
+
* Prerequisites:
|
|
624
|
+
* - Both source and destination skeletons must have a non-null `humanoidJointMapping`.
|
|
625
|
+
* - Joints are matched by shared `HumanoidBodyRig` / `HumanoidHandRig` keys instead of joint names.
|
|
626
|
+
* - The source clip must exist in `sourceSet` and must be driven by exactly one skeleton.
|
|
627
|
+
*
|
|
628
|
+
* @param sourceSet - The AnimationSet to copy from.
|
|
629
|
+
* @param animationName - Name of the clip to copy.
|
|
630
|
+
* @param targetName - Name for the new clip in this set. Defaults to `animationName`.
|
|
631
|
+
* @returns The newly created AnimationClip, or null on failure.
|
|
632
|
+
*/ copyHumanoidAnimationFrom(sourceSet, animationName, targetName) {
|
|
633
|
+
const destName = targetName ?? animationName;
|
|
634
|
+
const sourceClip = sourceSet.get(animationName);
|
|
635
|
+
if (!sourceClip) {
|
|
636
|
+
console.error(`copyHumanoidAnimationFrom: animation '${animationName}' not found in source set`);
|
|
637
|
+
return null;
|
|
638
|
+
}
|
|
639
|
+
if (this._animations[destName]) {
|
|
640
|
+
console.error(`copyHumanoidAnimationFrom: animation '${destName}' already exists in target set`);
|
|
641
|
+
return null;
|
|
642
|
+
}
|
|
643
|
+
if (sourceClip.skeletons.size !== 1) {
|
|
644
|
+
console.error(`copyHumanoidAnimationFrom: source animation clip must be affected by exactly one skeleton`);
|
|
645
|
+
return null;
|
|
646
|
+
}
|
|
647
|
+
const srcSkeletonId = [
|
|
648
|
+
...sourceClip.skeletons
|
|
649
|
+
][0];
|
|
650
|
+
const srcSkeleton = Skeleton.findSkeletonById(srcSkeletonId);
|
|
651
|
+
if (!srcSkeleton) {
|
|
652
|
+
console.error(`copyHumanoidAnimationFrom: source skeleton '${srcSkeletonId}' not found`);
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
// Check that source skeleton has humanoid mapping
|
|
656
|
+
const srcHumanoidMapping = srcSkeleton.humanoidJointMapping;
|
|
657
|
+
if (!srcHumanoidMapping) {
|
|
658
|
+
console.error(`copyHumanoidAnimationFrom: source skeleton does not have a humanoid joint mapping`);
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
const nodeMap = new Map();
|
|
662
|
+
const jointRemapBySrcNode = new Map();
|
|
663
|
+
// Find a destination skeleton that has a humanoid mapping and share at least the body rig keys
|
|
664
|
+
let srcJointsFiltered = [];
|
|
665
|
+
let dstJointsFiltered = [];
|
|
666
|
+
const dstSkeleton = this._skeletons.map((ref)=>ref.get()).find((sk)=>{
|
|
667
|
+
if (!sk) {
|
|
668
|
+
return false;
|
|
669
|
+
}
|
|
670
|
+
// Check that destination skeleton has humanoid mapping
|
|
671
|
+
const dstHumanoidMapping = sk.humanoidJointMapping;
|
|
672
|
+
if (!dstHumanoidMapping) {
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
675
|
+
// Collect matched (srcJoint, dstJoint) pairs via shared humanoid rig keys
|
|
676
|
+
const srcMatched = [];
|
|
677
|
+
const dstMatched = [];
|
|
678
|
+
// Match body rig joints
|
|
679
|
+
for (const key of Object.keys(srcHumanoidMapping.body)){
|
|
680
|
+
const srcJoint = srcHumanoidMapping.body[key];
|
|
681
|
+
const dstJoint = dstHumanoidMapping.body[key];
|
|
682
|
+
if (srcJoint && dstJoint) {
|
|
683
|
+
srcMatched.push(srcJoint);
|
|
684
|
+
dstMatched.push(dstJoint);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
// Match left hand rig joints only when both sides define them; skip silently if either is absent
|
|
688
|
+
if (srcHumanoidMapping.leftHand && dstHumanoidMapping.leftHand) {
|
|
689
|
+
for (const key of Object.keys(srcHumanoidMapping.leftHand)){
|
|
690
|
+
const srcJoint = srcHumanoidMapping.leftHand[key];
|
|
691
|
+
const dstJoint = dstHumanoidMapping.leftHand[key];
|
|
692
|
+
if (srcJoint && dstJoint) {
|
|
693
|
+
srcMatched.push(srcJoint);
|
|
694
|
+
dstMatched.push(dstJoint);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
// Match right hand rig joints only when both sides define them; skip silently if either is absent
|
|
699
|
+
if (srcHumanoidMapping.rightHand && dstHumanoidMapping.rightHand) {
|
|
700
|
+
for (const key of Object.keys(srcHumanoidMapping.rightHand)){
|
|
701
|
+
const srcJoint = srcHumanoidMapping.rightHand[key];
|
|
702
|
+
const dstJoint = dstHumanoidMapping.rightHand[key];
|
|
703
|
+
if (srcJoint && dstJoint) {
|
|
704
|
+
srcMatched.push(srcJoint);
|
|
705
|
+
dstMatched.push(dstJoint);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
if (srcMatched.length === 0) {
|
|
710
|
+
return false;
|
|
711
|
+
}
|
|
712
|
+
srcJointsFiltered = srcMatched;
|
|
713
|
+
dstJointsFiltered = dstMatched;
|
|
714
|
+
return true;
|
|
715
|
+
});
|
|
716
|
+
if (!dstSkeleton) {
|
|
717
|
+
console.error(`copyHumanoidAnimationFrom: no matching humanoid skeleton in target set for '${srcSkeletonId}'`);
|
|
718
|
+
return null;
|
|
719
|
+
}
|
|
720
|
+
// Compute the world-space rotation of the parent chain above the Hips joint,
|
|
721
|
+
// walking ALL ancestor nodes up to (but not including) the model root.
|
|
722
|
+
// This must include non-joint nodes such as "Armature" in Mixamo rigs, which
|
|
723
|
+
// carry a 90° X rotation that is NOT captured by humanoidRootRotation (which
|
|
724
|
+
// only traverses nodes inside the skeleton joints list).
|
|
725
|
+
function computeHipsParentChainRotation(hipsNode, modelRoot, skeleton) {
|
|
726
|
+
const result = Quaternion.identity();
|
|
727
|
+
const jointSet = new Set(skeleton.joints);
|
|
728
|
+
let p = hipsNode.parent;
|
|
729
|
+
while(p && p !== modelRoot){
|
|
730
|
+
if (!jointSet.has(p)) {
|
|
731
|
+
Quaternion.multiply(p.rotation, result, result);
|
|
732
|
+
}
|
|
733
|
+
p = p.parent;
|
|
734
|
+
}
|
|
735
|
+
return result;
|
|
736
|
+
}
|
|
737
|
+
const srcHipsNode = srcSkeleton.humanoidJointMapping.body[HumanoidBodyRig.Hips];
|
|
738
|
+
const dstHipsNode = dstSkeleton.humanoidJointMapping.body[HumanoidBodyRig.Hips];
|
|
739
|
+
const srcRootRot = computeHipsParentChainRotation(srcHipsNode, sourceSet.model, srcSkeleton);
|
|
740
|
+
const dstRootRot = computeHipsParentChainRotation(dstHipsNode, this._model, dstSkeleton);
|
|
741
|
+
const hipsTranslationRotation = Quaternion.multiply(Quaternion.inverse(dstRootRot), srcRootRot);
|
|
742
|
+
const jointRemaps = [];
|
|
743
|
+
const mappedSrcNodes = new Set();
|
|
744
|
+
const mappedDstNodes = new Set();
|
|
745
|
+
// Build remap for matched joint pairs
|
|
746
|
+
for(let fi = 0; fi < srcJointsFiltered.length; fi++){
|
|
747
|
+
const srcJoint = srcJointsFiltered[fi];
|
|
748
|
+
const dstJoint = dstJointsFiltered[fi];
|
|
749
|
+
if (mappedSrcNodes.has(srcJoint) || mappedDstNodes.has(dstJoint)) {
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
mappedSrcNodes.add(srcJoint);
|
|
753
|
+
mappedDstNodes.add(dstJoint);
|
|
754
|
+
const isHipsBone = srcJoint === srcHipsNode;
|
|
755
|
+
nodeMap.set(srcJoint, dstJoint);
|
|
756
|
+
const remap = createJointRetargetRemap(srcSkeleton, dstSkeleton, srcJoint, dstJoint, isHipsBone ? hipsTranslationRotation : undefined);
|
|
757
|
+
jointRemaps.push(remap);
|
|
758
|
+
jointRemapBySrcNode.set(srcJoint, remap);
|
|
759
|
+
}
|
|
760
|
+
const dstClip = this.createAnimation(destName);
|
|
761
|
+
if (!dstClip) {
|
|
762
|
+
return null;
|
|
763
|
+
}
|
|
764
|
+
dstClip.timeDuration = sourceClip.timeDuration;
|
|
765
|
+
dstClip.weight = sourceClip.weight;
|
|
766
|
+
dstClip.autoPlay = sourceClip.autoPlay;
|
|
767
|
+
// Register destination skeleton
|
|
768
|
+
dstClip.addSkeleton(dstSkeleton.persistentId);
|
|
769
|
+
bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRootRot, dstRootRot, dstClip, jointRemaps);
|
|
770
|
+
for (const srcNode of srcJointsFiltered){
|
|
771
|
+
const srcTracks = sourceClip.tracks.get(srcNode);
|
|
772
|
+
if (!srcTracks) {
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
const dstNode = nodeMap.get(srcNode);
|
|
776
|
+
const remap = jointRemapBySrcNode.get(srcNode);
|
|
777
|
+
for (const srcTrack of srcTracks){
|
|
778
|
+
let dstTrack;
|
|
779
|
+
if (srcTrack instanceof NodeRotationTrack) {
|
|
780
|
+
continue;
|
|
781
|
+
} else if (srcTrack instanceof NodeEulerRotationTrack) {
|
|
782
|
+
continue;
|
|
783
|
+
} else if (srcTrack instanceof NodeTranslationTrack) {
|
|
784
|
+
dstTrack = retargetTranslationTrack(srcTrack, remap);
|
|
785
|
+
} else if (srcTrack instanceof NodeScaleTrack) {
|
|
786
|
+
dstTrack = new NodeScaleTrack(cloneInterpolator(srcTrack.interpolator));
|
|
787
|
+
} else {
|
|
788
|
+
console.warn(`copyHumanoidAnimationFrom: unsupported track type '${srcTrack.constructor.name}', skipping`);
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
dstTrack.name = srcTrack.name;
|
|
792
|
+
dstTrack.target = dstNode.persistentId;
|
|
793
|
+
dstTrack.jointIndex = remap.dstJointIndex;
|
|
794
|
+
dstClip.addTrack(dstNode, dstTrack);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return dstClip;
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
335
800
|
* Copy an animation clip from another AnimationSet into this one.
|
|
336
801
|
*
|
|
337
802
|
* Prerequisites:
|
|
@@ -409,18 +874,8 @@ import { Skeleton } from './skeleton.js';
|
|
|
409
874
|
for(let fi = 0; fi < srcJointsFiltered.length; fi++){
|
|
410
875
|
const srcJoint = srcJointsFiltered[fi];
|
|
411
876
|
const dstJoint = dstJointsFiltered[fi];
|
|
412
|
-
const si = srcSkeleton.joints.indexOf(srcJoint);
|
|
413
|
-
const di = dstSkeleton.joints.indexOf(dstJoint);
|
|
414
|
-
const srcLen = srcSkeleton.bindPose[si].position.magnitude;
|
|
415
|
-
const dstLen = dstSkeleton.bindPose[di].position.magnitude;
|
|
416
|
-
const translationScale = srcLen > 1e-6 ? dstLen / srcLen : 1;
|
|
417
877
|
nodeMap.set(srcJoint, dstJoint);
|
|
418
|
-
jointRemapBySrcNode.set(srcJoint,
|
|
419
|
-
dstNode: dstJoint,
|
|
420
|
-
srcBindRot: srcSkeleton.bindPose[si].rotation,
|
|
421
|
-
dstBindRot: dstSkeleton.bindPose[di].rotation,
|
|
422
|
-
translationScale
|
|
423
|
-
});
|
|
878
|
+
jointRemapBySrcNode.set(srcJoint, createJointRetargetRemap(srcSkeleton, dstSkeleton, srcJoint, dstJoint));
|
|
424
879
|
}
|
|
425
880
|
const dstClip = this.createAnimation(destName);
|
|
426
881
|
if (!dstClip) {
|
|
@@ -438,13 +893,13 @@ import { Skeleton } from './skeleton.js';
|
|
|
438
893
|
return null;
|
|
439
894
|
}
|
|
440
895
|
const dstNode = nodeMap.get(srcNode);
|
|
441
|
-
const remap = jointRemapBySrcNode.get(srcNode)
|
|
896
|
+
const remap = jointRemapBySrcNode.get(srcNode);
|
|
442
897
|
for (const srcTrack of srcTracks){
|
|
443
898
|
let dstTrack;
|
|
444
899
|
if (srcTrack instanceof NodeRotationTrack) {
|
|
445
|
-
dstTrack = retargetRotationTrack(srcTrack);
|
|
900
|
+
dstTrack = retargetRotationTrack(srcTrack, remap);
|
|
446
901
|
} else if (srcTrack instanceof NodeEulerRotationTrack) {
|
|
447
|
-
dstTrack = retargetEulerToRotationTrack(srcTrack);
|
|
902
|
+
dstTrack = retargetEulerToRotationTrack(srcTrack, remap);
|
|
448
903
|
} else if (srcTrack instanceof NodeTranslationTrack) {
|
|
449
904
|
dstTrack = retargetTranslationTrack(srcTrack, remap);
|
|
450
905
|
} else if (srcTrack instanceof NodeScaleTrack) {
|
|
@@ -454,8 +909,8 @@ import { Skeleton } from './skeleton.js';
|
|
|
454
909
|
continue;
|
|
455
910
|
}
|
|
456
911
|
dstTrack.name = srcTrack.name;
|
|
457
|
-
dstTrack.target =
|
|
458
|
-
dstTrack.jointIndex =
|
|
912
|
+
dstTrack.target = dstNode.persistentId;
|
|
913
|
+
dstTrack.jointIndex = remap.dstJointIndex;
|
|
459
914
|
dstClip.addTrack(dstNode, dstTrack);
|
|
460
915
|
}
|
|
461
916
|
}
|
|
@@ -502,48 +957,6 @@ import { Skeleton } from './skeleton.js';
|
|
|
502
957
|
}
|
|
503
958
|
return ordered;
|
|
504
959
|
}
|
|
505
|
-
function retargetTranslationTrack(src, remap) {
|
|
506
|
-
if (!remap || Math.abs(remap.translationScale - 1) < 1e-6) {
|
|
507
|
-
return new NodeTranslationTrack(cloneInterpolator(src.interpolator));
|
|
508
|
-
}
|
|
509
|
-
const scale = remap.translationScale;
|
|
510
|
-
const srcOutputs = src.interpolator.outputs;
|
|
511
|
-
const newOutputs = new Float32Array(srcOutputs.length);
|
|
512
|
-
for(let i = 0; i < newOutputs.length; i++){
|
|
513
|
-
newOutputs[i] = srcOutputs[i] * scale;
|
|
514
|
-
}
|
|
515
|
-
return new NodeTranslationTrack(new Interpolator(src.interpolator.mode, 'vec3', new Float32Array(src.interpolator.inputs), newOutputs));
|
|
516
|
-
}
|
|
517
|
-
function cloneInterpolator(src) {
|
|
518
|
-
return new Interpolator(src.mode, src.target, src.inputs instanceof Float32Array ? new Float32Array(src.inputs) : [
|
|
519
|
-
...src.inputs
|
|
520
|
-
], src.outputs instanceof Float32Array ? new Float32Array(src.outputs) : [
|
|
521
|
-
...src.outputs
|
|
522
|
-
]);
|
|
523
|
-
}
|
|
524
|
-
function retargetRotationTrack(src) {
|
|
525
|
-
const isCubic = src.interpolator.mode === 'cubicspline';
|
|
526
|
-
const frameStride = isCubic ? 12 : 4;
|
|
527
|
-
const numFrames = src.interpolator.inputs.length;
|
|
528
|
-
const srcOutputs = src.interpolator.outputs;
|
|
529
|
-
const newOutputs = new Float32Array(srcOutputs.length);
|
|
530
|
-
for(let f = 0; f < numFrames; f++){
|
|
531
|
-
const base = f * frameStride;
|
|
532
|
-
newOutputs.set(srcOutputs.subarray(base, base + (isCubic ? 12 : 4)), base);
|
|
533
|
-
}
|
|
534
|
-
return new NodeRotationTrack(new Interpolator(src.interpolator.mode, 'quat', new Float32Array(src.interpolator.inputs), newOutputs));
|
|
535
|
-
}
|
|
536
|
-
function retargetEulerToRotationTrack(src) {
|
|
537
|
-
const srcInputs = src.interpolator.inputs;
|
|
538
|
-
const srcOutputs = src.interpolator.outputs;
|
|
539
|
-
const numFrames = srcInputs.length;
|
|
540
|
-
const newOutputs = new Float32Array(numFrames * 3);
|
|
541
|
-
for(let f = 0; f < numFrames; f++){
|
|
542
|
-
const base = f * 3;
|
|
543
|
-
newOutputs.set(srcOutputs.subarray(base, base + 3), base);
|
|
544
|
-
}
|
|
545
|
-
return new NodeRotationTrack(new Interpolator('linear', 'quat', new Float32Array(srcInputs), newOutputs));
|
|
546
|
-
}
|
|
547
960
|
}
|
|
548
961
|
/**
|
|
549
962
|
* Dispose the animation set and release owned resources.
|