rfcs
rfcs copied to clipboard
Animation Primitives
This RFC details the absolute bare minimum viable API for setting up a flexible and extendable property based animation system in Bevy... or at least part of it. This gets probably about 1/3 of the way there.
Ping @lassade; I'm very curious on your opinions on this if you have the time and interest.
a few notes
- Not sure how curves and sampling could be decoupled into to separated traits, to me they are the same;
- Sampling also involves how data should be interpolated: step, linear and catmul-row; I propose to have 3 different types of curves like in my original implementation;
- For Quaternions there is a difference between lerp vs slerp, other than that generally the type it self defines how interpolate between values. You will almost never will want to use slerp by the way;
- Color interpolation will be a nightmare If the Colors is defined as a enum that supports sRGB, LinSRGB, HSL and others, because each color space gives a different interpolation result; If you let the user choose the interpolation color space it might have a heavy performance cost, probably many times greater than using slerp;
- Sampling should include some form of cursor (cache locality, think a curve with many keyframes) and should and use binary search (faster keyframe search). But you should only use the latter to make a simpler initial implementation;
In the storage domain you should include how streamed data will be handled and at mention available animation formats namely ACL (https://github.com/nfrechette/acl) in the prior art.
Almost completely revised the RFC end to end:
- Removed the mention of animation graph and mixing entirely, going to have a separate RFC for this
- Dropped the idea of
Sample<T>, and instead opting for defining the base characteristics required for an animatable property instead, which will be the base for the composition API - Dove deeper into the implementation details and memory layout.
- Addressed review comments from @alice-i-cecile and @lassade
Still quite a few TODOs, namely discussing a strategy for implementing AnimationClip and it's serialization.
To respond to @lassade's comments (next time please leave them inline so I can address them 1-by-1 instead of a giant block like this).
- Not sure how curves and sampling could be decoupled into to separated traits, to me they are the same;
Good point, retracted that idea after discussing this with you on Discord and reading your Animator implementation. I've changed it now to instead have a trait on the sampled value named Animatable, which takes your Lerp and logically extends it one step further for allowing anyone to make their own blendable value. This will be used to blend sampled values from curves the next Animation Graph attempt I'm testing instead of relying on generic nodes as previously proposed. This should remove generics from everywhere except for the Curve<T> trait itself.
- Sampling also involves how data should be interpolated: step, linear and catmul-row; I propose to have 3 different types of curves like in my original implementation;
I'm tentatively addressing this by trying to use a newtype and implement Animatable on it instead. Having T be a generic parameter to Curve instead of an associated type actually allows us to have multiple Curve<T> implementations for a given type, and we can unwrap the newtype in a blanket impl if we need to. Having multiple curve types was originally always in the plan, just didn't have time to write down the full details, but if the underlying structure of the curve does not change fundamentally change, but the interpolation behavior changes, we can just newtype the value type instead. There's an argument to be made here about SoA vs AoS in wrapping values like this, which is why the CurveVariable in your implementation is the way it is, but I'm not sure if SoA is the answer here, particularly since we're not speed-iterating through the curve, but occasionally sampling a value from it, sometimes randomly.
- For Quaternions there is a difference between lerp vs slerp, other than that generally the type it self defines how interpolate between values. You will almost never will want to use slerp by the way;
This can be addressed by the newtype pattern that I mentioned above. Though I'm curious why we wouldn't want to use slerp other than performance.
- Color interpolation will be a nightmare If the Colors is defined as a enum that supports sRGB, LinSRGB, HSL and others, because each color space gives a different interpolation result; If you let the user choose the interpolation color space it might have a heavy performance cost, probably many times greater than using slerp;
Right, and that's sort of an implementation detail that we need to address, and is sort of separate from the design detailed here. I'm well aware this is an issue, but it's something we need to resolve in general, not just for animation.
- Sampling should include some form of cursor (cache locality, think a curve with many keyframes) and should and use binary search (faster keyframe search). But you should only use the latter to make a simpler initial implementation;
I added a section on this, though I'm not 100% sold on it. After reading your implementation, I get the distinct impression that this very heavily complicates the implementation as the cursor must be mutably saved somewhere, and you might have the same curve/clip being sampled in different locations by multiple entities (or even within the same entity). That's not to say I think we should definitely not add it in, but it does seem like an optimization we can add in after we deliver a MVP on this.
In the storage domain you should include how streamed data will be handled and at mention available animation formats namely ACL (https://github.com/nfrechette/acl) in the prior art.
Great point! Added that a mention of ACL in. I need to rewrite that section to mention the other efforts in the Rust community and other public literature about the approaches to this.
Looking at the curve system as explained in the RFC, it reminds me of how Godot does animations, specifically how Godot lets you animate literally everything including UI all using the same UI graph. I'm wondering, will the Curve<T> syntax work for everything, or only for certain things like skeletal animation?