Add most common interpolations (#15675)

# Objective

- Followup for #14788 
- Support most usual ease function

## Solution

- Use the crate
[`interpolation`](https://docs.rs/interpolation/0.3.0/interpolation/trait.Ease.html)
which has them all
- it's already used by bevy_easings, bevy_tweening, be_tween,
bevy_tweening_captured, bevy_enoki, kayak_ui in the Bevy ecosystem for
various easing/tweening/interpolation
This commit is contained in:
François Mockers 2024-10-07 17:56:06 +02:00 committed by GitHub
parent 0a150b0d22
commit 4357539e06
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 131 additions and 6 deletions

View file

@ -21,6 +21,7 @@ rand = { version = "0.8", features = [
], default-features = false, optional = true }
rand_distr = { version = "0.4.3", optional = true }
smallvec = { version = "1.11" }
interpolation = "0.3"
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
"glam",

View file

@ -5,6 +5,7 @@ use crate::{
ops::{self, FloatPow},
VectorSpace,
};
use interpolation::Ease;
use super::{Curve, FunctionCurve, Interval};
@ -84,6 +85,51 @@ where
}
impl EasingCurve<f32, FunctionCurve<f32, fn(f32) -> f32>> {
/// A [`Curve`] mapping the [unit interval] to itself.
///
/// [unit interval]: `Interval::UNIT`
pub fn ease(function: EaseFunction) -> Self {
Self {
start: 0.0,
end: 1.0,
easing: FunctionCurve::new(
Interval::UNIT,
match function {
EaseFunction::QuadraticIn => Ease::quadratic_in,
EaseFunction::QuadraticOut => Ease::quadratic_out,
EaseFunction::QuadraticInOut => Ease::quadratic_in_out,
EaseFunction::CubicIn => Ease::cubic_in,
EaseFunction::CubicOut => Ease::cubic_out,
EaseFunction::CubicInOut => Ease::cubic_in_out,
EaseFunction::QuarticIn => Ease::quartic_in,
EaseFunction::QuarticOut => Ease::quartic_out,
EaseFunction::QuarticInOut => Ease::quartic_in_out,
EaseFunction::QuinticIn => Ease::quintic_in,
EaseFunction::QuinticOut => Ease::quintic_out,
EaseFunction::QuinticInOut => Ease::quintic_in_out,
EaseFunction::SineIn => Ease::sine_in,
EaseFunction::SineOut => Ease::sine_out,
EaseFunction::SineInOut => Ease::sine_in_out,
EaseFunction::CircularIn => Ease::circular_in,
EaseFunction::CircularOut => Ease::circular_out,
EaseFunction::CircularInOut => Ease::circular_in_out,
EaseFunction::ExponentialIn => Ease::exponential_in,
EaseFunction::ExponentialOut => Ease::exponential_out,
EaseFunction::ExponentialInOut => Ease::exponential_in_out,
EaseFunction::ElasticIn => Ease::elastic_in,
EaseFunction::ElasticOut => Ease::elastic_out,
EaseFunction::ElasticInOut => Ease::elastic_in_out,
EaseFunction::BackIn => Ease::back_in,
EaseFunction::BackOut => Ease::back_out,
EaseFunction::BackInOut => Ease::back_in_out,
EaseFunction::BounceIn => Ease::bounce_in,
EaseFunction::BounceOut => Ease::bounce_out,
EaseFunction::BounceInOut => Ease::bounce_in_out,
},
),
}
}
/// A [`Curve`] mapping the [unit interval] to itself.
///
/// Quadratic easing functions can have exactly one critical point. This is a point on the function
@ -92,7 +138,7 @@ impl EasingCurve<f32, FunctionCurve<f32, fn(f32) -> f32>> {
///
/// It uses the function `f(t) = t²`
///
/// [unit domain]: `Interval::UNIT`
/// [unit interval]: `Interval::UNIT`
/// [`t = 1`]: `Self::quadratic_ease_out`
pub fn quadratic_ease_in() -> Self {
Self {
@ -110,7 +156,7 @@ impl EasingCurve<f32, FunctionCurve<f32, fn(f32) -> f32>> {
///
/// It uses the function `f(t) = 1 - (1 - t)²`
///
/// [unit domain]: `Interval::UNIT`
/// [unit interval]: `Interval::UNIT`
/// [`t = 0`]: `Self::quadratic_ease_in`
pub fn quadratic_ease_out() -> Self {
fn f(t: f32) -> f32 {
@ -132,7 +178,7 @@ impl EasingCurve<f32, FunctionCurve<f32, fn(f32) -> f32>> {
///
/// It uses the function `f(t) = t² * (3 - 2t)`
///
/// [unit domain]: `Interval::UNIT`
/// [unit interval]: `Interval::UNIT`
/// [sigmoid function]: https://en.wikipedia.org/wiki/Sigmoid_function
/// [smoothstep function]: https://en.wikipedia.org/wiki/Smoothstep
pub fn smoothstep() -> Self {
@ -150,7 +196,7 @@ impl EasingCurve<f32, FunctionCurve<f32, fn(f32) -> f32>> {
///
/// It uses the function `f(t) = t`
///
/// [unit domain]: `Interval::UNIT`
/// [unit interval]: `Interval::UNIT`
pub fn identity() -> Self {
Self {
start: 0.0,
@ -219,7 +265,7 @@ where
/// - for `n >= 2` the curve has a start segment and an end segment of length `1 / (2 * n)` and in
/// between there are `n - 1` segments of length `1 / n`
///
/// [unit domain]: `Interval::UNIT`
/// [unit interval]: `Interval::UNIT`
/// [`constant_curve(Interval::UNIT, 0.0)`]: `crate::curve::constant_curve`
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
@ -265,7 +311,7 @@ impl StepCurve {
///
/// parametrized by `omega`
///
/// [unit domain]: `Interval::UNIT`
/// [unit interval]: `Interval::UNIT`
/// [smoothstep function]: https://en.wikipedia.org/wiki/Smoothstep
/// [spring-mass-system]: https://notes.yvt.jp/Graphics/Easing-Functions/#elastic-easing
#[derive(Clone, Debug)]
@ -296,3 +342,81 @@ impl ElasticCurve {
Self { omega }
}
}
/// Curve functions over the [unit interval], commonly used for easing transitions.
///
/// [unit interval]: `Interval::UNIT`
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
pub enum EaseFunction {
/// `f(t) = t²`
QuadraticIn,
/// `f(t) = -(t * (t - 2.0))`
QuadraticOut,
/// Behaves as `EaseFunction::QuadraticIn` for t < 0.5 and as `EaseFunction::QuadraticOut` for t >= 0.5
QuadraticInOut,
/// `f(t) = t³`
CubicIn,
/// `f(t) = (t - 1.0)³ + 1.0`
CubicOut,
/// Behaves as `EaseFunction::CubicIn` for t < 0.5 and as `EaseFunction::CubicOut` for t >= 0.5
CubicInOut,
/// `f(t) = t⁴`
QuarticIn,
/// `f(t) = (t - 1.0)³ * (1.0 - t) + 1.0`
QuarticOut,
/// Behaves as `EaseFunction::QuarticIn` for t < 0.5 and as `EaseFunction::QuarticOut` for t >= 0.5
QuarticInOut,
/// `f(t) = t⁵`
QuinticIn,
/// `f(t) = (t - 1.0)⁵ + 1.0`
QuinticOut,
/// Behaves as `EaseFunction::QuinticIn` for t < 0.5 and as `EaseFunction::QuinticOut` for t >= 0.5
QuinticInOut,
/// `f(t) = sin((t - 1.0) * π / 2.0) + 1.0`
SineIn,
/// `f(t) = sin(t * π / 2.0)`
SineOut,
/// Behaves as `EaseFunction::SineIn` for t < 0.5 and as `EaseFunction::SineOut` for t >= 0.5
SineInOut,
/// `f(t) = 1.0 - sqrt(1.0 - t²)`
CircularIn,
/// `f(t) = sqrt((2.0 - t) * t)`
CircularOut,
/// Behaves as `EaseFunction::CircularIn` for t < 0.5 and as `EaseFunction::CircularOut` for t >= 0.5
CircularInOut,
/// `f(t) = 2.0.powf(10.0 * (t - 1.0))`
ExponentialIn,
/// `f(t) = 1.0 - 2.0.powf(-10.0 * t)`
ExponentialOut,
/// Behaves as `EaseFunction::ExponentialIn` for t < 0.5 and as `EaseFunction::ExponentialOut` for t >= 0.5
ExponentialInOut,
/// `f(t) = sin(13.0 * π / 2.0 * t) * 2.0.powf(10.0 * (t - 1.0))`
ElasticIn,
/// `f(t) = sin(-13.0 * π / 2.0 * (t + 1.0)) * 2.0.powf(-10.0 * t) + 1.0`
ElasticOut,
/// Behaves as `EaseFunction::ElasticIn` for t < 0.5 and as `EaseFunction::ElasticOut` for t >= 0.5
ElasticInOut,
/// `f(t) = t³ - t * sin(t * π)`
BackIn,
/// `f(t) = 1.0 - (1.0 - t)³ - t * sin((1.0 - t) * π))`
BackOut,
/// Behaves as `EaseFunction::BackIn` for t < 0.5 and as `EaseFunction::BackOut` for t >= 0.5
BackInOut,
/// bouncy at the start!
BounceIn,
/// bouncy at the end!
BounceOut,
/// Behaves as `EaseFunction::BounceIn` for t < 0.5 and as `EaseFunction::BounceOut` for t >= 0.5
BounceInOut,
}