airbnb / lottie-ios

An iOS library to natively render After Effects vector animations
http://airbnb.io/lottie/
Apache License 2.0
25.76k stars 3.75k forks source link

The Core Animation rendering engine partially supports time remapping keyframes #1648

Closed smolskyaleksey closed 9 months ago

smolskyaleksey commented 2 years ago

version 3.4.0 master branch

Lottie/AnimationView.swift:1003: Assertion failed: Encountered Core Animation compatibility issues while setting up animation: [Puke Splash_PRECOMP_02] The Core Animation rendering engine partially supports time remapping keyframes, but this is somewhat experimental and has some known issues. Since it doesn't work in all cases, we have to fall back to using the main thread engine when using RenderingEngineOption.automatic. [Puke Splash_PRECOMP_02] The Core Animation rendering engine partially supports time remapping keyframes, but this is somewhat experimental and has some known issues. Since it doesn't work in all cases, we have to fall back to using the main thread engine when using RenderingEngineOption.automatic.

This animation cannot be rendered correctly by the Core Animation engine. To resolve this issue, you can use RenderingEngineOption.automatic, which automatically falls back to the Main Thread rendering engine when necessary, or just use RenderingEngineOption.mainThread.

calda commented 2 years ago

The Core Animation rendering engine has a partial implementation of time remapping that works in some circumstances, but doesn't always work correctly. For now I'd suggest using LottieConfiguration(renderingEngine: .automatic), which will automatically fall back to using the main thread rendering engine for animations that use time remapping.

If you specifically want or need to use the Core Animation rendering engine for this animation, you can suppress this assertion by disabling the LottieLogger (either via LottieLogger.shared = .printToConsole or AnimationView(animation: myAnimation, logger: .printToConsole)).

smolskyaleksey commented 2 years ago

Ok, thx, but the performance is still worse than 2.5.3 version. Do you have any idea why?

calda commented 2 years ago

When using which rendering engine?

smolskyaleksey commented 2 years ago

When using which rendering engine?

Yes. Any rendering engine worse than 2.5.3

calda commented 2 years ago

Can you share your animation json?

smolskyaleksey commented 2 years ago

Can you share your animation json?

gemmic.zip

calda commented 2 years ago

Performance of these animations seems great when using the Core Animation engine (0% CPU utilization, and a high framerate), is there a specific issue you were encountering?

smolskyaleksey commented 2 years ago

Performance of these animations seems great when using the Core Animation engine (0% CPU utilization, and a high framerate), is there a specific issue you were encountering?

When you add all of this to vertical collectionView, one per cell and try to scroll up/down fps rate will be decrease

pejato commented 2 years ago

Hey @calda , our designers like to use time remapping, so this is something I'd be interested in getting support for and would be willing to work on if feasible.

Do you have more info on what the outstanding issues here are?

calda commented 2 years ago

We have an implementation of time remapping that sort of works, but only in simple cases.

Time remapping in Core Animation is complicated for a few reasons:

Every animation has keyframes with timing curves, which Core Animation uses to determine the current value of the property animated at any given time. You can think of these as an arbitrary function that takes the layer's current time value and outputs the value of the property at that time.

Time remapping is also a set of keyframes with timing curves. Time remapping is basically a function that takes a layer's current time value and outputs the remapped time value for its child layer.

To render this correctly, the time remapping of the parent has to be applied to the child every frame. The Core Animation engine doesn't currently operate on individual frames -- it only operates on the set of defined keyframes, and lets Core Animation itself interpolate the individual frames. But if we only apply the time remapping to the keyframes that we create, then the output is incorrect in complex cases. To fix this we would need to manually interpolate the keyframes so we know the value at each frame, and then apply the time remapping to each of those frames.

Another obstacle is the direction in which we have to apply the time remapping. Time remapping is specifically a function from the parent's "local time" to the child's "local time". An example of this -- say you want the child's animation to go twice as fast. When the parent layer is at frame 10, the child's frame is at time 20.

Because of the architecture of the Core Animation engine, I think we have to answer this question in reverse. In the same example of making the child's animation go twice as fast, when computing a value of the child layer at frame 20 we have to know that we should actually be using the value originally intended to be used at frame 10. This requires taking the inverse of the time remapping function, which I don't know how to do correctly (particularly when accounting for the timing curves).

pejato commented 2 years ago

Thanks for the informative reply Cal, it's very helpful 😄 Going to do a more thorough reading of Lottie's CA rendering code this weekend.

This requires taking the inverse of the time remapping function, which I don't know how to do correctly

I'm not sure this is even possible if the time remapping function isn't invertible, which is a possibility, e.g. if we reverse and replay some frames like the second animation here, right?

calda commented 9 months ago

Fixed in https://github.com/airbnb/lottie-ios/pull/2286!