glTF-Transform
glTF-Transform copied to clipboard
Broken animation after resampling
Describe the bug
After resampling, the animation sequence in this example is broken.
To Reproduce
Steps to reproduce the behavior:
-
gltf-transform resample Arm.glb Arm-resampled.glb
Decreasing tolerance will fix the issue, but also prevents resampling from reducing the size very much. My hunch is that the current implementation of `resample() does not handle quaternion keyframe tracks properly.
Expected behavior
Animation should appear visually identical, within some small tolerance.
Related
- https://github.com/donmccurdy/glTF-Transform/pull/492
- https://github.com/donmccurdy/glTF-Transform/issues/489
Sub-issues:
- [ ]
resample()
should remove channels that have no effect - [ ]
resample()
must slerp, not lerp, quaternion tracks - [ ]
resample()
must not collapse keyframes A-B-C if A and C are >180º apart
Digging into the file a bit more, there are lots of junk keyframe tracks that aren't contributing anything to the final animation. Some are small (2 keyframes, both identical) and others are large (50,627 keyframes, all containing scale=1,1,1
). The resample
command deals with the duplicate keyframes but doesn't currently prune no-op tracks. That — along with an automatic dedup
step — would probably be reasonable additions to the function.
![Screen Shot 2022-02-16 at 11 03 06 AM](https://user-images.githubusercontent.com/1848368/154305910-f63a364a-7015-435f-b4f2-c54a618b3378.png)
To chime in here regarding the file - everything with two keyframes is there because the "animation pose" is different to the "non-animated pose" for this model. The rest pose could be anything (e.g. stretched out) but if during the entire animation clip a part of the model would be rotated differently, then there's a start and end keyframe for that but no actual animation inbetween. So, these tracks aren't always "no-op tracks", they can also be "pose tracks" without any animation/movement happening.
There might of course be some cases where the keyframes can be stripped (I thought I do that on export already though) when those two poses match.
Somehow gltfpack manages to reduce this file to just 6 animation channels – I guess that must (at least in part) mean it's baking the animated pose to the rest pose? Does gltfpack's output work for your use cases, or is that something you'd want to be opt-in if it happens at all?
In either case, the track containing only scale=1,1,1
could probably be removed by resample()
... 😅
Manually set the tolerance
to 1.1920928955078125e-7
(the epsilon for float32) would help.
await document.transform(
// Losslessly resample animation frames.
resample({tolerance: 1.1920928955078125e-7}),
// Remove duplicate vertex or texture data, if any.
dedup(),
// Remove unused nodes, textures, or other data.
prune(),
);
This issue will be fixed in https://github.com/donmccurdy/glTF-Transform/pull/760. The main thing was using slerp() to compare quaternion keyframes. I've left the two-keyframe "animation pose" channels alone, as I think removing those would probably be unexpected behavior for the resample() function here.