Closed timbotimbo closed 8 months ago
Looking at the retarget function, I think the issue is related to keyframe generation, specifically the last keyframe. When the converted tracks are pushed, they currently push without the final keyframe. This is because the times and positions are assigned at every numFrame, but numFrame does not account for a final keyframe with no interpolation afterwards, only keyframes followed by interpolation.
A solution could be: After the main loop, to add the final keyframe calculated a the exact duration
timestamp.
I would love to work on a PR for this if it is open to work on.
The fix in #25589 doesn't seem to work as intended. The final frame seems fuly broken now with the model seemingly exploded into a random shape.
I've got a new live example that shows some actual retargeting.
This applies the bvh loader pirouette.bvh
to the the fbx loader Samba Dancing.fbx
.
"three/addons/": "https://unpkg.com/three@0.150.1/examples/jsm/"
Now the animation looks good, but the retageted animation is 1 frame short, as in the original issue above."three/addons/": "https://unpkg.com/three@0.151.0/examples/jsm/"
Now the frame count is correct, but there will sometimes be a weird flash or glitch in the loop of the animation.// pause on the last frame
mixer.setTime(newClip.duration*0.99999);
mixer.timeScale = 0;
@timbotimbo this new PR should fix your issue.
But in your example you will still have to change the way you get the fps from
options.fps = 1 / result.clip.tracks[0].times[1];
to
options.fps = result.clip.tracks[ 0 ].times.length / result.clip.duration;
Otherwise you're getting 120.000047 fps instead of 120.20309 fps this small difference is what's causing the issue in the amount of frames being short by 1.
But your issue highlighted other issues while debugging that should be adressed by that PR #27653
Thanks for picking this up.
But in your example you will still have to change the way you get the fps from
options.fps = 1 / result.clip.tracks[0].times[1];
tooptions.fps = result.clip.tracks[ 0 ].times.length / result.clip.duration;
Maybe to to prevent errors like these the function should default to the fps of the clip. Right now it defaults to 30 and you need to explicitly define the correct value if your clip doesn't match 30. I would expect it to take the clip as default and only change it if you explicitly define a different fps.
Good point, it would make sense to default to the original FPS. If that's not considered as a breaking change I can add it to the PR.
[UPDATE] See my new comment below for an improved example.
Description
Any AnimationClip I use in the
SkeletonUtils
retargetClip
function will result in an output clip with a shorter duration, that is missing exactly 1 frame. The difference is hardly visible in animations with hundreds or thousands of frames, but it is still incorrect.The issue seems to come from the numFrames calculation.
numFrames = Math.round(clip.duration * ( options.fps / 1000 ) * 1000 )
Theoretical example
Lets take a clip with a duration of 3 seconds and 1 fps as example.
0 1 2 3
, duration: 3 secondsnumFrames
is calculated as3
, which is used in a< numFrames
for-loop.0 1 2
, duration: 2 secondsSolutions
If we can assume that any AnimationClip input will start at time 0, we can just add a
+ 1
to the numFrames definition. (This would get an index out of range for a clip with times1 2 3
, but i'm not sure that is possible)An alternative is to use
numFrames = clip.tracks[0].times.length
The function already seems to assume all tracks are the same length.Testing
There don't seem to be any examples or tests that use this function.
Reproduction steps
fps
property that matches the framerate of the animation.retargetClip
using the variables above as input.Code
Live example
This is basically the bvhLoader example pasted in jsfiddle, with the above code block pasted into the loader callback. The use of the retarget does not make sense here, as it doesn't load any other model, but this is enough to show the bug.
https://jsfiddle.net/sn58dp40/
Expected console output for the example:
Version
r148, dev
Device
Any
Browser
Any
OS
Any