Magnum::Animation::Easing namespace

Easing functions.

Contents

A collection of predefined easing / tweening functions for adding life to animation interpolation.

The easing function is meant to be used to modify the interpolation factor, such as:

Vector3 result = Math::lerp(a, b, Animation::Easing::quadraticInOut(t));

The Animation library also provides the ease() utility that combines the interpolator together with the easing function:

auto lerpQuadraticInOut =
    Animation::ease<Vector3, Math::lerp, Animation::Easing::quadraticInOut>();

Vector3 result = lerpQuadraticInOut(a, b, t);

Equations

Every function documentation shows a plot of its behavior, together with a direction in which it extrapolates. Green color means the extrapolation goes in a reasonable monotonic direction outside of the range (also denoted by E in the above list), red color means the extrapolation is defined, but behaves in a probably unwanted or non-monotonic way (denoted by E in the above list). If neither is present, it means the function is not defined outside of the $ [ 0; 1 ] $ range and produces a NaN. You may want to ensure the factor stays in bounds, using either Math::clamp() or the easeClamped() function — the following two expressions are equivalent:

auto lerpCircularOutClamped = Animation::easeClamped<
    Vector3, Math::lerp, Animation::Easing::quadraticInOut>();

Vector3 result1 = Math::lerp(a, b,
    Math::clamp(0.0f, 1.0f, Animation::Easing::circularOut(t)));
Vector3 result2 = lerpCircularOutClamped(a, b, t);

Out-function $ f_\text{out} $ for a corresponding in-function $ f_\text{in} $ is defined as the following, the equations in the docs usually just show the final derived form. Similarly goes for combined in-/out-function $ f_\text{inout} $ :

\[ \begin{array}{rcl} f_\text{out}(x) & = & 1 - f_\text{in}(1 - x) \\[5pt] f_\text{inout}(x) & = & \left. \begin{cases} \frac{1}{2} f_\text{in}(2x), & x < 0.5 \\ \frac{1}{2} (1 + f_\text{out}(2x - 1)), & x \ge 0.5 \end{cases} \right\} = \begin{cases} \frac{1}{2} f_\text{in}(2x), & x < 0.5 \\ 1 - \frac{1}{2} f_\text{in}(2 - 2x), & x \ge 0.5 \end{cases} \end{array} \]

Easing functions defined by simple polynomials can have an exact (denoted by B in the above list) or approximate (denoted by B in the above list) cubic Math::Bezier curve representation (and thus, in turn, convertible to Cubic Hermite splines using Math::CubicHermite::fromBezier()). If that's the case, given function documentation also lists the corresponding Bézier representation and plots it with a thin blue line. The curve is always normalized to go from $ (0, 0)^T $ to $ (1, 1)^T $ , apply arbitrary transformation to each point as needed:

Matrix3 transformation;
CubicBezier2D easing;
CubicBezier2D transformed{
    transformation.transformPoint(easing[0]),
    transformation.transformPoint(easing[1]),
    transformation.transformPoint(easing[2]),
    transformation.transformPoint(easing[3])};

References

Functions follow the common naming from Robert Penner's Easing functions, http://robertpenner.com/easing/. Implementation based on and inspired by https://easings.net/, https://github.com/warrenm/AHEasing, https://github.com/bkaradzic/bx, https://blog.demofox.org/2014/08/28/one-dimensional-bezier-curves/.

Functions

auto linear(Float t) -> Float
Linear.
auto step(Float t) -> Float
Step.
auto smoothstep(Float t) -> Float
Smoothstep.
auto smootherstep(Float t) -> Float
Smootherstep.
auto quadraticIn(Float t) -> Float
Quadratic in.
auto quadraticOut(Float t) -> Float
Quadratic out.
auto quadraticInOut(Float t) -> Float
Quadratic in and out.
auto cubicIn(Float t) -> Float
Cubic in.
auto cubicOut(Float t) -> Float
Cubic out.
auto cubicInOut(Float t) -> Float
Cubic in and out.
auto quarticIn(Float t) -> Float
Quartic in.
auto quarticOut(Float t) -> Float
Quartic out.
auto quarticInOut(Float t) -> Float
Quartic in and out.
auto quinticIn(Float t) -> Float
Quintic in.
auto quinticOut(Float t) -> Float
Quintic out.
auto quinticInOut(Float t) -> Float
Quintic in and out.
auto sineIn(Float t) -> Float
Sine in.
auto sineOut(Float t) -> Float
Sine out.
auto sineInOut(Float t) -> Float
Sine in and out.
auto circularIn(Float t) -> Float
Circular in.
auto circularOut(Float t) -> Float
Circular out.
auto circularInOut(Float t) -> Float
Circular in and out.
auto exponentialIn(Float t) -> Float
Exponential in.
auto exponentialOut(Float t) -> Float
Exponential out.
auto exponentialInOut(Float t) -> Float
Exponential in and out.
auto elasticIn(Float t) -> Float
Elastic in.
auto elasticOut(Float t) -> Float
Elastic out.
auto elasticInOut(Float t) -> Float
Elastic in and out.
auto backIn(Float t) -> Float
Back in.
auto backOut(Float t) -> Float
Back out.
auto backInOut(Float t) -> Float
Back in and out.
auto bounceIn(Float t) -> Float
Bounce in.
auto bounceOut(Float t) -> Float
Bounce out.
auto bounceInOut(Float t) -> Float
Bounce in and out.

Function documentation

Float Magnum::Animation::Easing::linear(Float t)

Linear.

\[ y = x \]

One possible exact Bézier representation:

CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f},
              Vector2{2.0f/3.0f}, Vector2{1.0f}}

Float Magnum::Animation::Easing::step(Float t)

Step.

Similar to Math::select(), but does the step in the middle of the range instead of at the end. Implementation matching the GLSL step() function with edge = 0.5f.

\[ y = \begin{cases} 0, & x < 0.5 \\ 1, & x \ge 0.5 \end{cases} \]

Float Magnum::Animation::Easing::smoothstep(Float t)

Smoothstep.

Implementation matching the GLSL smoothstep() function. Combine with Math::lerp() to get the equivalent result:

Math::lerp(a, b, Animation::Easing::smoothstep(t));
\[ y = \begin{cases} 0, & x < 0 \\ 3x^2 - 2x^3, & x \in [0, 1] \\ 1, & x > 1 \end{cases} \]

Exact Bézier representation:

CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 0.0f},
              Vector2{2.0f/3.0f, 1.0f}, Vector2{1.0f}}

Float Magnum::Animation::Easing::smootherstep(Float t)

Smootherstep.

Improved version of smoothstep() by Ken Perlin.

\[ y = \begin{cases} 0, & x < 0 \\ 6x^5 - 15x^4 + 10x^3, & x \in [0, 1] \\ 1, & x > 1 \end{cases} \]

Float Magnum::Animation::Easing::quadraticIn(Float t)

Quadratic in.

\[ y = x^2 \]

Exact Bézier representation:

CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 0.0f},
              Vector2{2.0f/3.0f, 1.0f/3.0f}, Vector2{1.0f}}

Float Magnum::Animation::Easing::quadraticOut(Float t)

Quadratic out.

\[ y = 1 - (1 - x)^2 = (2 - x) x \]

Exact Bézier representation:

CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 2.0f/3.0f},
              Vector2{2.0f/3.0f, 1.0f}, Vector2{1.0f}}

Float Magnum::Animation::Easing::quadraticInOut(Float t)

Quadratic in and out.

Combination of quadraticIn() and quadraticOut().

\[ y = \begin{cases} 2 x^2, & x < 0.5 \\ 1 - 2 (1 - x)^2, & x \ge 0.5 \end{cases} \]

Approximate Bézier representation:

CubicBezier2D{Vector2{0.0f}, Vector2{0.455f, 0.0f},
              Vector2{0.545f, 1.0f}, Vector2{1.0f}}

Float Magnum::Animation::Easing::cubicIn(Float t)

Cubic in.

\[ y = x^3 \]

Exact Bézier representation:

CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 0.0f},
              Vector2{2.0f/3.0f, 0.0f}, Vector2{1.0f}}

Float Magnum::Animation::Easing::cubicOut(Float t)

Cubic out.

\[ y = 1 - (1 - x)^3 \]

Exact Bézier representation:

CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 1.0f},
              Vector2{2.0f/3.0f, 1.0f}, Vector2{1.0f}}

Float Magnum::Animation::Easing::cubicInOut(Float t)

Cubic in and out.

Combination of cubicIn() and cubicOut().

\[ y = \begin{cases} 4 x^3, & x < 0.5 \\ 1 - 4 (1 - x)^3, & x \ge 0.5 \end{cases} \]

Approximate Bézier representation:

CubicBezier2D{Vector2{0.0f}, Vector2{0.645f, 0.0f},
              Vector2{0.355f, 1.0f}, Vector2{1.0f}}

Float Magnum::Animation::Easing::quarticIn(Float t)

Quartic in.

\[ y = x^4 \]

Float Magnum::Animation::Easing::quarticOut(Float t)

Quartic out.

\[ y = 1 - (1 - x)^4 \]

Float Magnum::Animation::Easing::quarticInOut(Float t)

Quartic in and out.

Combination of quarticIn() and quarticOut().

\[ y = \begin{cases} 8 x^4, & x < 0.5 \\ 1 - 8 (1 - x)^4, & x \ge 0.5 \end{cases} \]

Float Magnum::Animation::Easing::quinticIn(Float t)

Quintic in.

\[ y = x^5 \]

Float Magnum::Animation::Easing::quinticOut(Float t)

Quintic out.

\[ y = 1 - (1 - x)^5 \]

Float Magnum::Animation::Easing::quinticInOut(Float t)

Quintic in and out.

Combination of quinticIn() and quinticOut().

\[ y = \begin{cases} 16 x^5, & x < 0.5 \\ 1 - 16 (1 - x)^5, & x \ge 0.5 \end{cases} \]

Float Magnum::Animation::Easing::sineIn(Float t)

Sine in.

\[ y = 1 + \sin(\frac{\pi}{2} (x - 1)) \]

Float Magnum::Animation::Easing::sineOut(Float t)

Sine out.

\[ y = \sin(\frac{\pi}{2} x) \]

Float Magnum::Animation::Easing::sineInOut(Float t)

Sine in and out.

Combination of sineIn() and sineOut().

\[ y = \frac{1}{2} (1 - \cos(\pi x)) \]

Float Magnum::Animation::Easing::circularIn(Float t)

Circular in.

\[ y = 1 - \sqrt{1 - x^2} \]

Float Magnum::Animation::Easing::circularOut(Float t)

Circular out.

\[ y = \sqrt{(2 - x) x} \]

Float Magnum::Animation::Easing::circularInOut(Float t)

Circular in and out.

Combination of circularIn() and circularOut().

\[ y = \begin{cases} \frac{1}{2} (1 - \sqrt{1 - (2x)^2}), & x < 0.5 \\ \frac{1}{2} (1 + \sqrt{1 - (2x - 2)^2}), & x \ge 0.5 \end{cases} \]

Float Magnum::Animation::Easing::exponentialIn(Float t)

Exponential in.

Contrary to Robert Penner's book but consistently with other implementations has a special case for $ x \le 0 $ , because $ 2^{-10} = 0.0009765625 $ otherwise.

\[ y = \begin{cases} 0, & x \le 0 \\ 2^{10(x - 1)}, & x \ne 0 \end{cases} \]

Float Magnum::Animation::Easing::exponentialOut(Float t)

Exponential out.

Contrary to Robert Penner's book but consistently with other implementations has a special case for $ x \ge 1 $ , because $ 2^{-10} = 0.0009765625 $ otherwise.

\[ y = \begin{cases} 2^{-10 x}, & x < 1 \\ 1, & x \ge 1 \end{cases} \]

Float Magnum::Animation::Easing::exponentialInOut(Float t)

Exponential in and out.

Combination of exponentialIn() and exponentialOut(). Contrary to Robert Penner's book but consistently with other implementations has a special case for $ x \notin \{0, 1\} $ , because $ 2^{-10} = 0.0009765625 $ otherwise.

\[ y = \begin{cases} 0, & x \le 0 \\ \frac{1}{2} 2^{20 x - 10}, & x \in (0, 0.5) \\ 1 - \frac{1}{2} 2^{10 - 20 x}, & x \in [0.5, 1) \\ 1, & x \ge 1 \end{cases} \]

Float Magnum::Animation::Easing::elasticIn(Float t)

Elastic in.

Combines sineIn() and exponentialIn().

\[ y = 2^{10 (p - 1)} \sin(13 \frac{\pi}{2} x) \]

Float Magnum::Animation::Easing::elasticOut(Float t)

Elastic out.

Combines sineOut() and exponentialOut().

\[ y = 1 - 2^{-10 x} \sin(13 \frac{\pi}{2} (x + 1)) \]

Float Magnum::Animation::Easing::elasticInOut(Float t)

Elastic in and out.

Combination of elasticIn() and elasticOut() (or sineInOut() and exponentialInOut()).

\[ y = \begin{cases} \frac{1}{2} 2^{10 (2x - 1)} \sin(13 \pi x), & x < 0.5 \\ 1 - \frac{1}{2} 2^{10 (1 - 2x)} \sin(13 \pi x), & x \ge 0.5 \end{cases} \]

Float Magnum::Animation::Easing::backIn(Float t)

Back in.

\[ y = x^3 - x \sin(\pi x) \]

Float Magnum::Animation::Easing::backOut(Float t)

Back out.

\[ y = 1 - ((1 - x)^3 - (1 - x) \sin(\pi (1 - x))) \]

Float Magnum::Animation::Easing::backInOut(Float t)

Back in and out.

Combination of backIn() and backOut().

\[ y = \begin{cases} \frac{1}{2} ((2x)^3 - 2x \sin(2 \pi x)), & x < 0.5 \\ 1 - \frac{1}{2} ((2 - 2x)^3 - (2 - 2x) \sin(\pi (2 - 2x)), & x \ge 0.5 \end{cases} \]

Float Magnum::Animation::Easing::bounceIn(Float t)

Bounce in.

Float Magnum::Animation::Easing::bounceOut(Float t)

Bounce out.

Float Magnum::Animation::Easing::bounceInOut(Float t)

Bounce in and out.

Combination of bounceIn() and bounceOut().