FMovieSceneSkeletalAnimationParams::MapTimeToAnimation returns the wrong value if InFrameRate is not the Tick Resolution

FMovieSceneSkeletalAnimationParams::MapTimeToAnimation takes in an FFrameTime and FFrameRate and is supposed to tell you which frame of animation that evaluates to, when accounting for looping, play rate, animation frame rate, section start time, and so on. But if InFrameRate is not the same as the tick resolution, the answer will be wrong.

This is because in the version where the UMovieSceneSection itself is passed in, it queries the section start and end frame from that, and those are always in the tick resolution’s frame rate. Presumably in the overload where start and end are passed in, they’re calculated the same way by the caller. This range is passed to FMovieSceneSkeletalAnimationParams::MakeTransform, which multiplies the sequence length in seconds by the original InFrameRate to get the anim sequence length in frames, but then it checks if the section range is greater than that length to decide if it’s looping the animation.

If we pass in 30 FPS (with a matching frame number), and the tick resolution is 24,000 FPS, a section the same length as the animation will appear here to loop it 800 times. When the FMovieSceneSequenceTransform produced in this function is evaluated back in MapTimeToAnimation, it will get the wrong anim frame number as the result.

I don’t think this function is being called with non-tick resolution frame rates, because it would have been noticed before now (or else I’m very wrong). But we noticed it because we used this function to determine the current animation frame at a given time, and we passed in a frame rate and number that matched the display resolution (30 FPS), but got clearly wrong answers. When using the tick resolution for both, which should have produced the same result, the answer was correct.

Solving this in the MapTimeToAnimation overload that takes the UMovieSceneSection is trivial, because we still have access to the tick resolution and can fix up the frame rate and number to match. However, in the overload without the section, as well as MakeTransform itself, that information is no longer accessible, so I was unsure what to do about it. I can work around our problem by making sure we convert first, but wanted to get your input on whether my assessment here seems correct and notify you so you might address it in future versions.

[Attachment Removed]

Hey there,

Yes, this is the case and is intended, but is poorly named. From the outset, whenever you are working in the C++ runtime or APIs, we expect tick resolution since that is what the data is stored and evaluated as. In UI and scripting APIs we follow a display rate due to who is typically looking at or using those APIs.

I’ve logged an issue for us to address it here: https://issues.unrealengine.com/issue/UE-361071 and it’s something that we’ll want to address soon.

Dustin

[Attachment Removed]