-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Implement TryStableInterpolate.
#21633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
56ac25f
d5d866c
232e582
6922c60
5333236
72bc0c7
e167cbe
d8987c3
79d7874
5375fb0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -396,7 +396,7 @@ impl NormedVectorSpace for f64 { | |
| /// ```text | ||
| /// top curve = u.interpolate_stable(v, t) | ||
| /// | ||
| /// t0 => p t1 => q | ||
| /// t0 => p t1 => q | ||
| /// |-------------|---------|-------------| | ||
| /// 0 => u / \ 1 => v | ||
| /// / \ | ||
|
|
@@ -538,6 +538,68 @@ all_tuples_enumerated!( | |
| T | ||
| ); | ||
|
|
||
| /// Why the interpolation failed. | ||
| #[derive(Clone, Debug)] | ||
| pub enum InterpolationError { | ||
| /// The values to be interpolated are not in the same units. | ||
| MismatchedUnits, | ||
| /// Data type cannot be interpolated because it is not contiguous | ||
| NonContiguous, | ||
| } | ||
|
|
||
| /// A trait that indicates that a value _may_ be interpolable via [`StableInterpolate`]. An | ||
| /// interpolation may fail if the values have different units - for example, attempting to | ||
| /// interpolate between [`Val::Px`] and [`Val::Percent`] will fail, | ||
| /// even though they are the same Rust type. | ||
| /// | ||
| /// The motivating case for this trait is animating UI entities with [`Val`] | ||
| /// properties, which, because they are enums, cannot be interpolated in the normal way. This same | ||
| /// concept can be extended to other types as well. | ||
| /// | ||
viridia marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// Fallible interpolation can be used for animated transitions, which can be set up to fail | ||
| /// gracefully if there's a mismatch of units. For example, the a transition could smoothly | ||
| /// go from `Val::Px(10)` to `Val::Px(20)`, but if the user attempts to go from `Val::Px(10)` to | ||
| /// `Val::Percent(10)`, the animation player can detect the failure and simply snap to the new | ||
| /// value without interpolating. | ||
| /// | ||
| /// An animation clip system can incorporate fallible interpolation to support a broad set of | ||
| /// sequenced parameter values. This can include numeric types, which always interpolate, | ||
| /// enum types, which may or may not interpolate depending on the units, and non-interpolable | ||
| /// types, which always jump immediately to the new value without interpolation. This meaas, for | ||
| /// example, that you can have an animation track whose value type is a boolean or a string. | ||
| /// | ||
| /// Interpolation for simple number and coordinate types will always succeed, as will any type | ||
| /// that implements [`StableInterpolate`]. Types which have different variants such as | ||
| /// [`Val`] and [`Color`] will only fail if the units are different. | ||
| /// Note that [`Color`] has its own, non-fallible mixing methods, but those entail | ||
| /// automatically converting between different color spaces, and is both expensive and complex. | ||
| /// [`TryStableInterpolate`] is more conservative, and doesn't automatically convert between | ||
| /// color spaces. This produces a color interpolation that is has more predictable performance. | ||
viridia marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// | ||
| /// [`Val::Px`]: https://docs.rs/bevy/latest/bevy/ui/enum.Val.html | ||
| /// [`Val::Percent`]: https://docs.rs/bevy/latest/bevy/ui/enum.Val.html | ||
| /// [`Val`]: https://docs.rs/bevy/latest/bevy/ui/struct.enum.html | ||
viridia marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// [`Color`]: https://docs.rs/bevy/latest/bevy/color/enum.Color.html | ||
| pub trait TryStableInterpolate: Clone { | ||
| /// Attempt to interpolate the value. This may fail if the two interpolation values have | ||
| /// different units, or if the type is not interpolable. | ||
| fn try_interpolate_stable(&self, other: &Self, t: f32) -> Result<Self, InterpolationError>; | ||
| } | ||
viridia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| impl<T: StableInterpolate> TryStableInterpolate for T { | ||
| fn try_interpolate_stable(&self, other: &Self, t: f32) -> Result<Self, InterpolationError> { | ||
| Ok(self.interpolate_stable(other, t)) | ||
| } | ||
| } | ||
|
Comment on lines
586
to
591
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Huh, so this ended up working? I'm curious what was different about how you initially tested it, that caused the error you were reporting. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it has to do with the fact that the impls are in the same module as the target types instead of being in the same module as the trait definition. But to be honest, I'm not really sure why it works. |
||
|
|
||
| /// Boolean values can never be interpolated, but they can be animatable parameters (for things | ||
| /// like enabling and disabling lighting). | ||
| impl TryStableInterpolate for bool { | ||
| fn try_interpolate_stable(&self, _other: &Self, _t: f32) -> Result<Self, InterpolationError> { | ||
| Err(InterpolationError::NonContiguous) | ||
| } | ||
| } | ||
viridia marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// A type that has tangents. | ||
| pub trait HasTangent { | ||
| /// The tangent type. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| --- | ||
| title: Fallible Interpolation | ||
| authors: ["@viridia"] | ||
| pull_requests: [21633] | ||
| --- | ||
|
|
||
| ## Fallible Interpolation | ||
|
|
||
| The `StableInterpolate` trait is great, but sadly there's one important type that it doesn't work | ||
| with: The `Val` type from `bevy_ui`. The reason is that `Val` is an enum, representing different | ||
| length units such as pixels and percentages, and it's not generally possible or even meaningful to | ||
| try and interpolate between different units. | ||
|
|
||
| However, the use cases for wanting to animate `Val` don't require mixing units: often we just want | ||
| to slide or stretch the length of a widget such as a toggle switch. We can do this so long as we | ||
| check at runtime that both interpolation control points are in the same units. | ||
|
|
||
| The new `TryStableInterpolate` trait introduces the idea of interpolation that can fail, by returning | ||
| a `Result`. Note that "failure" in this case is not necessarily bad: it just means that the | ||
| animation player will need to modify the parameter in some other way, such as "snapping" or | ||
| "jumping" to the new keyframe without smoothly interpolating. This lets us create complex animations | ||
| that incorporate both kinds of parameters: ones that interpolate, and ones that don't. | ||
|
|
||
| There's a blanket implementation of `TryStableInterpolate` for all types that impl | ||
| `StableInterpolate`, and these can never fail. There are additional impls for `Color` and `Val` | ||
| which can fail if the control points are not in the same units / color space. |
Uh oh!
There was an error while loading. Please reload this page.