// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik // using System; using static UnityEngine.Mathf; using NormalizedDelegate = System.Func; namespace Animancer { /// A set of common easing functions. /// /// There are several different types of functions: /// /// In: accelerating from zero velocity. /// Out: decelerating to zero velocity. /// InOut: uses the corresponding In function until halfway, then the Out function after that. /// Normalized: methods with a single parameter ( value) expect values from 0 to 1. /// Ranged: methods with 3 parameters ( start, end, /// value) use the specified range instead ot 0 to 1. /// Derivative: calculates the gradient of their corresponding non-derivative function. /// The more complex derivative functions were made with 'https://www.derivative-calculator.net'. /// /// /// https://kybernetik.com.au/animancer/api/Animancer/Easing /// public static class Easing { /************************************************************************************************************************/ #region Delegates /************************************************************************************************************************/ /// The natural log of 2. public const float Ln2 = 0.693147180559945f; /************************************************************************************************************************/ /// A variant of a with a custom range instead of 0 to 1. public delegate float RangedDelegate(float start, float end, float value); /************************************************************************************************************************/ /// The name of an easing function. /// The class contains various extension methods for this enum. /// https://kybernetik.com.au/animancer/api/Animancer/Function /// public enum Function { /// Linear, /// QuadraticIn, /// QuadraticOut, /// QuadraticInOut, /// CubicIn, /// CubicOut, /// CubicInOut, /// QuarticIn, /// QuarticOut, /// QuarticInOut, /// QuinticIn, /// QuinticOut, /// QuinticInOut, /// SineIn, /// SineOut, /// SineInOut, /// ExponentialIn, /// ExponentialOut, /// ExponentialInOut, /// CircularIn, /// CircularOut, /// CircularInOut, /// BackIn, /// BackOut, /// BackInOut, /// BounceIn, /// BounceOut, /// BounceInOut, /// ElasticIn, /// ElasticOut, /// ElasticInOut, } /// The total number of values. public const int FunctionCount = (int)Function.ElasticInOut + 1; /************************************************************************************************************************/ private static NormalizedDelegate[] _FunctionDelegates; /// [Animancer Extension] /// Returns a cached delegate representing the specified `function` with a normalized range. /// public static NormalizedDelegate GetDelegate(this Function function) { var i = (int)function; if (_FunctionDelegates == null) { _FunctionDelegates = new NormalizedDelegate[FunctionCount]; } else { var del = _FunctionDelegates[i]; if (del != null) return del; } return _FunctionDelegates[i] = function switch { Function.Linear => Linear, Function.QuadraticIn => Quadratic.In, Function.QuadraticOut => Quadratic.Out, Function.QuadraticInOut => Quadratic.InOut, Function.CubicIn => Cubic.In, Function.CubicOut => Cubic.Out, Function.CubicInOut => Cubic.InOut, Function.QuarticIn => Quartic.In, Function.QuarticOut => Quartic.Out, Function.QuarticInOut => Quartic.InOut, Function.QuinticIn => Quintic.In, Function.QuinticOut => Quintic.Out, Function.QuinticInOut => Quintic.InOut, Function.SineIn => Sine.In, Function.SineOut => Sine.Out, Function.SineInOut => Sine.InOut, Function.ExponentialIn => Exponential.In, Function.ExponentialOut => Exponential.Out, Function.ExponentialInOut => Exponential.InOut, Function.CircularIn => Circular.In, Function.CircularOut => Circular.Out, Function.CircularInOut => Circular.InOut, Function.BackIn => Back.In, Function.BackOut => Back.Out, Function.BackInOut => Back.InOut, Function.BounceIn => Bounce.In, Function.BounceOut => Bounce.Out, Function.BounceInOut => Bounce.InOut, Function.ElasticIn => Elastic.In, Function.ElasticOut => Elastic.Out, Function.ElasticInOut => Elastic.InOut, _ => throw new ArgumentOutOfRangeException(nameof(function)), }; } /************************************************************************************************************************/ private static NormalizedDelegate[] _DerivativeDelegates; /// [Animancer Extension] /// Returns a cached delegate representing the derivative of the specified `function` with a normalized range. /// public static NormalizedDelegate GetDerivativeDelegate(this Function function) { var i = (int)function; if (_DerivativeDelegates == null) { _DerivativeDelegates = new NormalizedDelegate[FunctionCount]; } else { var del = _DerivativeDelegates[i]; if (del != null) return del; } return _DerivativeDelegates[i] = function switch { Function.Linear => LinearDerivative, Function.QuadraticIn => Quadratic.InDerivative, Function.QuadraticOut => Quadratic.OutDerivative, Function.QuadraticInOut => Quadratic.InOutDerivative, Function.CubicIn => Cubic.InDerivative, Function.CubicOut => Cubic.OutDerivative, Function.CubicInOut => Cubic.InOutDerivative, Function.QuarticIn => Quartic.InDerivative, Function.QuarticOut => Quartic.OutDerivative, Function.QuarticInOut => Quartic.InOutDerivative, Function.QuinticIn => Quintic.InDerivative, Function.QuinticOut => Quintic.OutDerivative, Function.QuinticInOut => Quintic.InOutDerivative, Function.SineIn => Sine.InDerivative, Function.SineOut => Sine.OutDerivative, Function.SineInOut => Sine.InOutDerivative, Function.ExponentialIn => Exponential.InDerivative, Function.ExponentialOut => Exponential.OutDerivative, Function.ExponentialInOut => Exponential.InOutDerivative, Function.CircularIn => Circular.InDerivative, Function.CircularOut => Circular.OutDerivative, Function.CircularInOut => Circular.InOutDerivative, Function.BackIn => Back.InDerivative, Function.BackOut => Back.OutDerivative, Function.BackInOut => Back.InOutDerivative, Function.BounceIn => Bounce.InDerivative, Function.BounceOut => Bounce.OutDerivative, Function.BounceInOut => Bounce.InOutDerivative, Function.ElasticIn => Elastic.InDerivative, Function.ElasticOut => Elastic.OutDerivative, Function.ElasticInOut => Elastic.InOutDerivative, _ => throw new ArgumentOutOfRangeException(nameof(function)), }; } /************************************************************************************************************************/ private static RangedDelegate[] _RangedFunctionDelegates; /// [Animancer Extension] /// Returns a cached delegate representing the specified `function` with a custom range. /// public static RangedDelegate GetRangedDelegate(this Function function) { var i = (int)function; if (_RangedFunctionDelegates == null) { _RangedFunctionDelegates = new RangedDelegate[FunctionCount]; } else { var del = _RangedFunctionDelegates[i]; if (del != null) return del; } return _RangedFunctionDelegates[i] = function switch { Function.Linear => Linear, Function.QuadraticIn => Quadratic.In, Function.QuadraticOut => Quadratic.Out, Function.QuadraticInOut => Quadratic.InOut, Function.CubicIn => Cubic.In, Function.CubicOut => Cubic.Out, Function.CubicInOut => Cubic.InOut, Function.QuarticIn => Quartic.In, Function.QuarticOut => Quartic.Out, Function.QuarticInOut => Quartic.InOut, Function.QuinticIn => Quintic.In, Function.QuinticOut => Quintic.Out, Function.QuinticInOut => Quintic.InOut, Function.SineIn => Sine.In, Function.SineOut => Sine.Out, Function.SineInOut => Sine.InOut, Function.ExponentialIn => Exponential.In, Function.ExponentialOut => Exponential.Out, Function.ExponentialInOut => Exponential.InOut, Function.CircularIn => Circular.In, Function.CircularOut => Circular.Out, Function.CircularInOut => Circular.InOut, Function.BackIn => Back.In, Function.BackOut => Back.Out, Function.BackInOut => Back.InOut, Function.BounceIn => Bounce.In, Function.BounceOut => Bounce.Out, Function.BounceInOut => Bounce.InOut, Function.ElasticIn => Elastic.In, Function.ElasticOut => Elastic.Out, Function.ElasticInOut => Elastic.InOut, _ => throw new ArgumentOutOfRangeException(nameof(function)), }; } /************************************************************************************************************************/ private static RangedDelegate[] _RangedDerivativeDelegates; /// [Animancer Extension] /// Returns a cached delegate representing the derivative of the specified `function` with a custom range. /// public static RangedDelegate GetRangedDerivativeDelegate(this Function function) { var i = (int)function; if (_RangedDerivativeDelegates == null) { _RangedDerivativeDelegates = new RangedDelegate[FunctionCount]; } else { var del = _RangedDerivativeDelegates[i]; if (del != null) return del; } return _RangedDerivativeDelegates[i] = function switch { Function.Linear => LinearDerivative, Function.QuadraticIn => Quadratic.InDerivative, Function.QuadraticOut => Quadratic.OutDerivative, Function.QuadraticInOut => Quadratic.InOutDerivative, Function.CubicIn => Cubic.InDerivative, Function.CubicOut => Cubic.OutDerivative, Function.CubicInOut => Cubic.InOutDerivative, Function.QuarticIn => Quartic.InDerivative, Function.QuarticOut => Quartic.OutDerivative, Function.QuarticInOut => Quartic.InOutDerivative, Function.QuinticIn => Quintic.InDerivative, Function.QuinticOut => Quintic.OutDerivative, Function.QuinticInOut => Quintic.InOutDerivative, Function.SineIn => Sine.InDerivative, Function.SineOut => Sine.OutDerivative, Function.SineInOut => Sine.InOutDerivative, Function.ExponentialIn => Exponential.InDerivative, Function.ExponentialOut => Exponential.OutDerivative, Function.ExponentialInOut => Exponential.InOutDerivative, Function.CircularIn => Circular.InDerivative, Function.CircularOut => Circular.OutDerivative, Function.CircularInOut => Circular.InOutDerivative, Function.BackIn => Back.InDerivative, Function.BackOut => Back.OutDerivative, Function.BackInOut => Back.InOutDerivative, Function.BounceIn => Bounce.InDerivative, Function.BounceOut => Bounce.OutDerivative, Function.BounceInOut => Bounce.InOutDerivative, Function.ElasticIn => Elastic.InDerivative, Function.ElasticOut => Elastic.OutDerivative, Function.ElasticInOut => Elastic.InOutDerivative, _ => throw new ArgumentOutOfRangeException(nameof(function)), }; } /************************************************************************************************************************/ /// Returns a linearly interpolated value between the `start` and `end` based on a normalized `value`. /// /// /// value = 0 returns start. /// value = 0.5 returns (start + end) / 2. /// value = 1 returns end. /// /// This method is identical to . /// public static float Lerp(float start, float end, float value) => start + (end - start) * value; /// Returns a normalized value indicating how far the `value` is between the `start` and `end`. /// /// /// value = start returns 0. /// value = (start + end) / 2 returns 0.5. /// value = end returns 1. /// start = end returns 0. /// /// This method is like except that it doesn't clamp the result between 0 and 1. /// public static float UnLerp(float start, float end, float value) => start == end ? 0 : (value - start) / (end - start); /************************************************************************************************************************/ /// Re-scales the result of the `function` to use a custom range instead of 0 to 1. public static float ReScale(float start, float end, float value, NormalizedDelegate function) => Lerp(start, end, function(UnLerp(start, end, value))); /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Linear /************************************************************************************************************************/ /// Directly returns the `value`. Interpolates the `value` based on the line y = x. public static float Linear(float value) => value; /************************************************************************************************************************/ /// Returns 1. The derivative of . public static float LinearDerivative(float value) => 1; /************************************************************************************************************************/ /// Directly returns the `value`. Interpolates the `value` based on the line y = x. public static float Linear(float start, float end, float value) => value; /************************************************************************************************************************/ /// Returns end - start. The derivative of . public static float LinearDerivative(float start, float end, float value) => end - start; /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Quadratic /************************************************************************************************************************/ /// Functions based on quadratic equations (x^2). /// https://kybernetik.com.au/animancer/api/Animancer/Quadratic /// public static class Quadratic { /************************************************************************************************************************/ /// Interpolates the `value` based on the line y = x^2. /// Easings.net has a graph of this function. public static float In(float value) => value * value; /// Interpolates the `value` based on the line y = 1 - (x - 1)^2. /// Easings.net has a graph of this function. public static float Out(float value) { value--; return -value * value + 1; } /// Interpolate using (0 to 0.5) or (0.5 to 1). /// Easings.net has a graph of this function. public static float InOut(float value) { value *= 2; if (value <= 1) { return 0.5f * value * value; } else { value -= 2; return 0.5f * (-value * value + 2); } } /************************************************************************************************************************/ /// Returns the derivative of (y = 2x). public static float InDerivative(float value) => 2 * value; /// Returns the derivative of (y = -2x + 2). public static float OutDerivative(float value) => 2 - 2 * value; /// Returns the derivative of . public static float InOutDerivative(float value) { value *= 2; if (value <= 1) { return 2 * value; } else { value--; return 2 - 2 * value; } } /************************************************************************************************************************/ // Ranged Variants. /************************************************************************************************************************/ /// A variant of with a custom range instead of 0 to 1. public static float In(float start, float end, float value) => Lerp(start, end, In(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float Out(float start, float end, float value) => Lerp(start, end, Out(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InOut(float start, float end, float value) => Lerp(start, end, InOut(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InDerivative(float start, float end, float value) => InDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float OutDerivative(float start, float end, float value) => OutDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float InOutDerivative(float start, float end, float value) => InOutDerivative(UnLerp(start, end, value)) * (end - start); /************************************************************************************************************************/ } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Cubic /************************************************************************************************************************/ /// Functions based on cubic equations (x^3). /// https://kybernetik.com.au/animancer/api/Animancer/Cubic /// public static class Cubic { /************************************************************************************************************************/ /// Interpolates the `value` based on the line y = x^3. /// Easings.net has a graph of this function. public static float In(float value) => value * value * value; /// Interpolates the `value` based on the line y = 1 + (x - 1)^3. /// Easings.net has a graph of this function. public static float Out(float value) { value--; return value * value * value + 1; } /// Interpolate using (0 to 0.5) or (0.5 to 1). /// Easings.net has a graph of this function. public static float InOut(float value) { value *= 2; if (value <= 1) { return 0.5f * value * value * value; } else { value -= 2; return 0.5f * (value * value * value + 2); } } /************************************************************************************************************************/ /// Returns the derivative of (y = 3x). public static float InDerivative(float value) => 3 * value * value; /// Returns the derivative of (y = 3 * (x - 1)). public static float OutDerivative(float value) { value--; return 3 * value * value; } /// Returns the derivative of . public static float InOutDerivative(float value) { value *= 2; if (value <= 1) { return 3 * value * value; } else { value -= 2; return 3 * value * value; } } /************************************************************************************************************************/ // Ranged Variants. /************************************************************************************************************************/ /// A variant of with a custom range instead of 0 to 1. public static float In(float start, float end, float value) => Lerp(start, end, In(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float Out(float start, float end, float value) => Lerp(start, end, Out(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InOut(float start, float end, float value) => Lerp(start, end, InOut(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InDerivative(float start, float end, float value) => InDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float OutDerivative(float start, float end, float value) => OutDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float InOutDerivative(float start, float end, float value) => InOutDerivative(UnLerp(start, end, value)) * (end - start); /************************************************************************************************************************/ } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Quartic /************************************************************************************************************************/ /// Functions based on quartic equations (x^4). /// https://kybernetik.com.au/animancer/api/Animancer/Quartic /// public static class Quartic { /************************************************************************************************************************/ /// Interpolates the `value` based on the line y = x^4. /// Easings.net has a graph of this function. public static float In(float value) => value * value * value * value; /// Interpolates the `value` based on the line y = 1 - (x - 1)^4. /// Easings.net has a graph of this function. public static float Out(float value) { value--; return -value * value * value * value + 1; } /// Interpolate using (0 to 0.5) or (0.5 to 1). /// Easings.net has a graph of this function. public static float InOut(float value) { value *= 2; if (value <= 1) { return 0.5f * value * value * value * value; } else { value -= 2; return 0.5f * (-value * value * value * value + 2); } } /************************************************************************************************************************/ /// Returns the derivative of (y = 4x). public static float InDerivative(float value) => 4 * value * value * value; /// Returns the derivative of (y = -4 * (x - 1)). public static float OutDerivative(float value) { value--; return -4 * value * value * value; } /// Returns the derivative of . public static float InOutDerivative(float value) { value *= 2; if (value <= 1) { return 4 * value * value * value; } else { value -= 2; return -4 * value * value * value; } } /************************************************************************************************************************/ // Ranged Variants. /************************************************************************************************************************/ /// A variant of with a custom range instead of 0 to 1. public static float In(float start, float end, float value) => Lerp(start, end, In(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float Out(float start, float end, float value) => Lerp(start, end, Out(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InOut(float start, float end, float value) => Lerp(start, end, InOut(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InDerivative(float start, float end, float value) => InDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float OutDerivative(float start, float end, float value) => OutDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float InOutDerivative(float start, float end, float value) => InOutDerivative(UnLerp(start, end, value)) * (end - start); /************************************************************************************************************************/ } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Quintic /************************************************************************************************************************/ /// Functions based on quintic equations (x^5). /// https://kybernetik.com.au/animancer/api/Animancer/Quintic /// public static class Quintic { /************************************************************************************************************************/ /// Interpolates the `value` based on the line y = x^5. /// Easings.net has a graph of this function. public static float In(float value) => value * value * value * value * value; /// Interpolates the `value` based on the line y = 1 + (x - 1)^5. /// Easings.net has a graph of this function. public static float Out(float value) { value--; return value * value * value * value * value + 1; } /// Interpolate using (0 to 0.5) or (0.5 to 1). /// Easings.net has a graph of this function. public static float InOut(float value) { value *= 2; if (value <= 1) { return 0.5f * value * value * value * value * value; } else { value -= 2; return 0.5f * (value * value * value * value * value + 2); } } /************************************************************************************************************************/ /// Returns the derivative of (y = 5x). public static float InDerivative(float value) => 5 * value * value * value * value; /// Returns the derivative of (y = -5 * (x - 1)). public static float OutDerivative(float value) { value--; return 5 * value * value * value * value; } /// Returns the derivative of . public static float InOutDerivative(float value) { value *= 2; if (value <= 1) { return 5 * value * value * value * value; } else { value -= 2; return 5 * value * value * value * value; } } /************************************************************************************************************************/ // Ranged Variants. /************************************************************************************************************************/ /// A variant of with a custom range instead of 0 to 1. public static float In(float start, float end, float value) => Lerp(start, end, In(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float Out(float start, float end, float value) => Lerp(start, end, Out(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InOut(float start, float end, float value) => Lerp(start, end, InOut(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InDerivative(float start, float end, float value) => InDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float OutDerivative(float start, float end, float value) => OutDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float InOutDerivative(float start, float end, float value) => InOutDerivative(UnLerp(start, end, value)) * (end - start); /************************************************************************************************************************/ } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Sine /************************************************************************************************************************/ /// Functions based on sinusoidal equations. /// https://kybernetik.com.au/animancer/api/Animancer/Sine /// public static class Sine { /************************************************************************************************************************/ /// Interpolates the `value` based on a quarter-cycle of a sine wave. /// Easings.net has a graph of this function. public static float In(float value) => -Cos(value * (PI * 0.5f)) + 1; /// Interpolates the `value` based on a quarter-cycle of a sine wave. /// Easings.net has a graph of this function. public static float Out(float value) => Sin(value * (PI * 0.5f)); /// Interpolate using (0 to 0.5) or (0.5 to 1). /// Easings.net has a graph of this function. public static float InOut(float value) => -0.5f * (Cos(PI * value) - 1); /************************************************************************************************************************/ /// Returns the derivative of . public static float InDerivative(float value) => 0.5f * PI * Sin(0.5f * PI * value); /// Returns the derivative of . public static float OutDerivative(float value) => PI * 0.5f * Cos(value * (PI * 0.5f)); /// Returns the derivative of . public static float InOutDerivative(float value) => 0.5f * PI * Sin(PI * value); /************************************************************************************************************************/ // Ranged Variants. /************************************************************************************************************************/ /// A variant of with a custom range instead of 0 to 1. public static float In(float start, float end, float value) => Lerp(start, end, In(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float Out(float start, float end, float value) => Lerp(start, end, Out(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InOut(float start, float end, float value) => Lerp(start, end, InOut(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InDerivative(float start, float end, float value) => InDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float OutDerivative(float start, float end, float value) => OutDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float InOutDerivative(float start, float end, float value) => InOutDerivative(UnLerp(start, end, value)) * (end - start); /************************************************************************************************************************/ } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Exponential /************************************************************************************************************************/ /// Functions based on exponential equations (2^(10(x))). /// https://kybernetik.com.au/animancer/api/Animancer/Exponential /// public static class Exponential { /************************************************************************************************************************/ /// Interpolates the `value` based on the line (y = 2^(10 * (x - 1))). /// Easings.net has a graph of this function. public static float In(float value) => Pow(2, 10 * (value - 1)); /// Interpolates the `value` based on the line (y = -2^(-10x) + 1). /// Easings.net has a graph of this function. public static float Out(float value) => -Pow(2, -10 * value) + 1; /// Interpolate using (0 to 0.5) or (0.5 to 1). /// Easings.net has a graph of this function. public static float InOut(float value) { value *= 2; if (value <= 1) { return 0.5f * Pow(2, 10 * (value - 1)); } else { value--; return 0.5f * (-Pow(2, -10 * value) + 2); } } /************************************************************************************************************************/ /// Returns the derivative of (y = 10 * ln(2) * 2^(10 * (x - 1))). public static float InDerivative(float value) => 10 * Ln2 * Pow(2, 10 * (value - 1)); /// Returns the derivative of (y = 5 * ln(2) * 2^(-10 * (x - 1) + 1)). public static float OutDerivative(float value) => 5 * Ln2 * Pow(2, 1 - 10 * value); /// Returns the derivative of . public static float InOutDerivative(float value) { value *= 2; if (value <= 1) { return 10 * Ln2 * Pow(2, 10 * (value - 1)); } else { value--; return 5 * Ln2 * Pow(2, 1 - 10 * value); } } /************************************************************************************************************************/ // Ranged Variants. /************************************************************************************************************************/ /// A variant of with a custom range instead of 0 to 1. public static float In(float start, float end, float value) => Lerp(start, end, In(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float Out(float start, float end, float value) => Lerp(start, end, Out(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InOut(float start, float end, float value) => Lerp(start, end, InOut(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InDerivative(float start, float end, float value) => InDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float OutDerivative(float start, float end, float value) => OutDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float InOutDerivative(float start, float end, float value) => InOutDerivative(UnLerp(start, end, value)) * (end - start); /************************************************************************************************************************/ } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Circular /************************************************************************************************************************/ /// Functions based on circular equations. /// https://kybernetik.com.au/animancer/api/Animancer/Circular /// public static class Circular { /************************************************************************************************************************/ /// Interpolates the `value` based on a shifted quadrant IV of a unit circle. /// Easings.net has a graph of this function. public static float In(float value) => -(Sqrt(1 - value * value) - 1); /// Interpolates the `value` based on a shifted quadrant II of a unit circle. /// Easings.net has a graph of this function. public static float Out(float value) { value--; return Sqrt(1 - value * value); } /// Interpolate using (0 to 0.5) or (0.5 to 1). /// Easings.net has a graph of this function. public static float InOut(float value) { value *= 2; if (value <= 1) { return -0.5f * (Sqrt(1 - value * value) - 1); } else { value -= 2; return 0.5f * (Sqrt(1 - value * value) + 1); } } /************************************************************************************************************************/ /// Returns the derivative of . public static float InDerivative(float value) => value / Sqrt(1 - value * value); /// Returns the derivative of . public static float OutDerivative(float value) { value--; return -value / Sqrt(1 - value * value); } /// Returns the derivative of . public static float InOutDerivative(float value) { value *= 2; if (value <= 1) { return value / (2 * Sqrt(1 - value * value)); } else { value -= 2; return -value / (2 * Sqrt(1 - value * value)); } } /************************************************************************************************************************/ // Ranged Variants. /************************************************************************************************************************/ /// A variant of with a custom range instead of 0 to 1. public static float In(float start, float end, float value) => Lerp(start, end, In(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float Out(float start, float end, float value) => Lerp(start, end, Out(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InOut(float start, float end, float value) => Lerp(start, end, InOut(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InDerivative(float start, float end, float value) => InDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float OutDerivative(float start, float end, float value) => OutDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float InOutDerivative(float start, float end, float value) => InOutDerivative(UnLerp(start, end, value)) * (end - start); /************************************************************************************************************************/ } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Back /************************************************************************************************************************/ /// Functions based on equations which go out of bounds then come back. /// https://kybernetik.com.au/animancer/api/Animancer/Back /// public static class Back { /************************************************************************************************************************/ private const float C = 1.758f; /************************************************************************************************************************/ /// Easings.net has a graph of this function. public static float In(float value) => value * value * ((C + 1) * value - C); /// Easings.net has a graph of this function. public static float Out(float value) { value -= 1; return value * value * ((C + 1) * value + C) + 1; } /// Interpolate using (0 to 0.5) or (0.5 to 1). /// Easings.net has a graph of this function. public static float InOut(float value) { value *= 2; if (value <= 1) { return 0.5f * value * value * ((C + 1) * value - C); } else { value -= 2; return 0.5f * (value * value * ((C + 1) * value + C) + 2); } } /************************************************************************************************************************/ /// Returns the derivative of . public static float InDerivative(float value) => 3 * (C + 1) * value * value - 2 * C * value; /// Returns the derivative of . public static float OutDerivative(float value) { value -= 1; return (C + 1) * value * value + 2 * value * ((C + 1) * value + C); } /// Returns the derivative of . public static float InOutDerivative(float value) { value *= 2; if (value <= 1) { return 3 * (C + 1) * value * value - 2 * C * value; } else { value -= 2; return (C + 1) * value * value + 2 * value * ((C + 1) * value + C); } } /************************************************************************************************************************/ // Ranged Variants. /************************************************************************************************************************/ /// A variant of with a custom range instead of 0 to 1. public static float In(float start, float end, float value) => Lerp(start, end, In(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float Out(float start, float end, float value) => Lerp(start, end, Out(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InOut(float start, float end, float value) => Lerp(start, end, InOut(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InDerivative(float start, float end, float value) => InDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float OutDerivative(float start, float end, float value) => OutDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float InOutDerivative(float start, float end, float value) => InOutDerivative(UnLerp(start, end, value)) * (end - start); /************************************************************************************************************************/ } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Bounce /************************************************************************************************************************/ /// Functions based on equations with sharp bounces. /// https://kybernetik.com.au/animancer/api/Animancer/Bounce /// public static class Bounce { /************************************************************************************************************************/ /// Easings.net has a graph of this function. public static float In(float value) { return 1 - Out(1 - value); } /// Easings.net has a graph of this function. public static float Out(float value) { switch (value) { case 0: return 0; case 1: return 1; } if (value < (1f / 2.75f)) { return 7.5625f * value * value; } else if (value < (2f / 2.75f)) { value -= 1.5f / 2.75f; return 7.5625f * value * value + 0.75f; } else if (value < (2.5f / 2.75f)) { value -= 2.25f / 2.75f; return 7.5625f * value * value + 0.9375f; } else { value -= 2.625f / 2.75f; return 7.5625f * value * value + 0.984375f; } } /// Interpolate using (0 to 0.5) or (0.5 to 1). /// Easings.net has a graph of this function. public static float InOut(float value) { if (value < 0.5f) return 0.5f * In(value * 2); else return 0.5f + 0.5f * Out(value * 2 - 1); } /************************************************************************************************************************/ /// Returns the derivative of . public static float InDerivative(float value) => OutDerivative(1 - value); /// Returns the derivative of . public static float OutDerivative(float value) { if (value < (1f / 2.75f)) { return 2 * 7.5625f * value; } else if (value < (2f / 2.75f)) { value -= 1.5f / 2.75f; return 2 * 7.5625f * value; } else if (value < (2.5f / 2.75f)) { value -= 2.25f / 2.75f; return 2 * 7.5625f * value; } else { value -= 2.625f / 2.75f; return 2 * 7.5625f * value; } } /// Returns the derivative of . public static float InOutDerivative(float value) { value *= 2; if (value <= 1) return OutDerivative(1 - value); else return OutDerivative(value - 1); } /************************************************************************************************************************/ // Ranged Variants. /************************************************************************************************************************/ /// A variant of with a custom range instead of 0 to 1. public static float In(float start, float end, float value) => Lerp(start, end, In(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float Out(float start, float end, float value) => Lerp(start, end, Out(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InOut(float start, float end, float value) => Lerp(start, end, InOut(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InDerivative(float start, float end, float value) => InDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float OutDerivative(float start, float end, float value) => OutDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float InOutDerivative(float start, float end, float value) => InOutDerivative(UnLerp(start, end, value)) * (end - start); /************************************************************************************************************************/ } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Elastic /************************************************************************************************************************/ /// Functions based on equations with soft bounces. /// https://kybernetik.com.au/animancer/api/Animancer/Elastic /// public static class Elastic { /************************************************************************************************************************/ /// 2 / 3 * pi public const float TwoThirdsPi = 2f / 3f * PI; /************************************************************************************************************************/ /// Easings.net has a graph of this function. public static float In(float value) { return value switch { 0 => 0, 1 => 1, _ => -Pow(2, 10 * value - 10) * Sin((value * 10 - 10.75f) * TwoThirdsPi), }; } /// Easings.net has a graph of this function. public static float Out(float value) { return value switch { 0 => 0, 1 => 1, _ => 1 + Pow(2, -10 * value) * Sin((value * -10 - 0.75f) * TwoThirdsPi), }; } /// Interpolate using (0 to 0.5) or (0.5 to 1). /// Easings.net has a graph of this function. public static float InOut(float value) { switch (value) { case 0: return 0; case 0.5f: return 0.5f; case 1: return 1; } value *= 2; if (value <= 1) { return 0.5f * (-Pow(2, 10 * value - 10) * Sin((value * 10 - 10.75f) * TwoThirdsPi)); } else { value--; return 0.5f + 0.5f * (1 + Pow(2, -10 * value) * Sin((value * -10 - 0.75f) * TwoThirdsPi)); } } /************************************************************************************************************************/ /// Returns the derivative of . public static float InDerivative(float value) { return -(5 * Pow(2, 10 * value - 9) * (3 * Ln2 * Sin(PI * (40 * value - 43) / 6) + 2 * PI * Cos(PI * (40 * value - 43) / 6))) / 3; } /// Returns the derivative of . public static float OutDerivative(float value) { return -(30 * Ln2 * Sin(2 * PI * (10 * value - 3f / 4f) / 3) - 20 * PI * Cos(2 * PI * (10 * value - 3f / 4f) / 3)) / (3 * Pow(2, 10 * value)); } /// Returns the derivative of . public static float InOutDerivative(float value) { value *= 2; if (value <= 1) return OutDerivative(1 - value); else return OutDerivative(value - 1); } /************************************************************************************************************************/ // Ranged Variants. /************************************************************************************************************************/ /// A variant of with a custom range instead of 0 to 1. public static float In(float start, float end, float value) => Lerp(start, end, In(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float Out(float start, float end, float value) => Lerp(start, end, Out(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InOut(float start, float end, float value) => Lerp(start, end, InOut(UnLerp(start, end, value))); /// A variant of with a custom range instead of 0 to 1. public static float InDerivative(float start, float end, float value) => InDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float OutDerivative(float start, float end, float value) => OutDerivative(UnLerp(start, end, value)) * (end - start); /// A variant of with a custom range instead of 0 to 1. public static float InOutDerivative(float start, float end, float value) => InOutDerivative(UnLerp(start, end, value)) * (end - start); /************************************************************************************************************************/ } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ } }