Last active
August 9, 2022 20:11
-
-
Save nickworks/94e7c11a2101e60c82826f797b7faaed to your computer and use it in GitHub Desktop.
A set of low-level functions for procedural animation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections; | |
| using System.Collections.Generic; | |
| using UnityEngine; | |
| /// <summary> | |
| /// A set of easy-to-implement animation functions. Compiled by Nick Pattison. | |
| /// </summary> | |
| public static class AnimMath { | |
| /// <summary> | |
| /// A function for lerping between 2 values. Yes, Unity has this Mathf.Lerp() and Vector3.Lerp(), | |
| /// but it's nice to have our own implementation as well. | |
| /// </summary> | |
| /// <param name="min">The minimum end of the output range. This value is returned when `p` is 0</param> | |
| /// <param name="max">The maximum end of the output range. This value is returned when `p` is 1</param> | |
| /// <param name="p">Percentage of the interpolation, typically from 0 to 1.</param> | |
| /// <param name="allowExtrapolation">Whether or not to extrapolate. If true, values outside of the range are possible (when `p` > 1 or `p` < 0). | |
| /// If false, the function will NOT output values outside of the range.</param> | |
| /// <returns>The interpolated value</returns> | |
| public static float Lerp(float min, float max, float p, bool allowExtrapolation = true) { | |
| if (!allowExtrapolation) { | |
| if (p < 0) return min; | |
| if (p > 1) return max; | |
| } | |
| return (max - min) * p + min; | |
| } | |
| // 3D version | |
| public static Vector3 Lerp(Vector3 min, Vector3 max, float p, bool allowExtrapolation = true) { | |
| if (!allowExtrapolation) { | |
| if (p < 0) return min; | |
| if (p > 1) return max; | |
| } | |
| return (max - min) * p + min; // the Vector3 class's overloaded operators allow us to do this | |
| } | |
| // 4D version (rotation) | |
| public static Quaternion Lerp(Quaternion min, Quaternion max, float p, bool allowExtrapolation = true) { | |
| if (!allowExtrapolation) { | |
| if (p < 0) return min; | |
| if (p > 1) return max; | |
| } | |
| return Quaternion.Lerp(min, max, p); // just use Unity's Quaternion.Lerp() | |
| } | |
| /// <summary> | |
| /// A function for asymptotic easing, aka the "exponential slide". This modified version is frame-rate independent, | |
| /// and is based on http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ | |
| /// </summary> | |
| /// <param name="current">The current value</param> | |
| /// <param name="target">The value to ease towards</param> | |
| /// <param name="percentLeftAfter1Second">How much is left after 1 second? Try small values, around or less than 1%.</param> | |
| /// <param name="dt">The current frame's delta-time. The function will use Time.deltaTime by default, but custom values can be passed in.</param> | |
| /// <returns>A new, eased value</returns> | |
| public static float Slide(float current, float target, float percentLeftAfter1Second = 0.01f, float dt = -1) { | |
| if (dt < 0) dt = Time.deltaTime; | |
| float p = 1 - Mathf.Pow(percentLeftAfter1Second, dt); | |
| return AnimMath.Lerp(current, target, p); | |
| } | |
| // 3D version | |
| public static Vector3 Slide(Vector3 current, Vector3 target, float percentLeftAfter1Second = 0.01f, float dt = -1) { | |
| if (dt < 0) dt = Time.deltaTime; | |
| float p = 1 - Mathf.Pow(percentLeftAfter1Second, dt); | |
| return AnimMath.Lerp(current, target, p); | |
| } | |
| // 4D version (rotation) | |
| public static Quaternion Slide(Quaternion current, Quaternion target, float percentLeftAfter1Second = 0.01f, float dt = -1) { | |
| if (dt < 0) dt = Time.deltaTime; | |
| float p = 1 - Mathf.Pow(percentLeftAfter1Second, dt); | |
| return AnimMath.Lerp(current, target, p); | |
| } | |
| /// <summary> | |
| /// A function for easy implementation of spring-like easing. This is frame-rate independent, | |
| /// and is based on http://allenchou.net/2015/04/game-math-precise-control-over-numeric-springing/ | |
| /// </summary> | |
| /// <param name="val">The current value of the spring. The function will modify the value.</param> | |
| /// <param name="vel">The current velocity of the spring. The function will modify the velocity.</param> | |
| /// <param name="target">The target value that the spring is easing towards.</param> | |
| /// <param name="damp">How much to dampen the "springiness".</param> | |
| /// <param name="freq">The oscillation-speed in radians/second. The default of 24 is close to 8*PI, which is 4 oscillations/second.</param> | |
| /// <param name="dt">The current frame's delta-time. The function will use Time.deltaTime by default, but custom values can be passed in.</param> | |
| public static void Spring(ref float val, ref float vel, float target, float damp = .23f, float freq = 24, float dt = -1) { | |
| if (dt < 0) dt = Time.deltaTime; | |
| float k = 1 + 2 * dt * damp * freq; | |
| float tff = dt * freq * freq; | |
| float ttff = dt * tff; | |
| val = (k * val + dt * vel + ttff * target) / (k + ttff); | |
| vel = (vel + tff * (target - val)) / (k + ttff); | |
| } | |
| // 3D version | |
| public static void Spring(ref Vector3 val, ref Vector3 vel, Vector3 target, float damp = .23f, float freq = 24, float dt = -1) { | |
| if (dt < 0) dt = Time.deltaTime; | |
| float k = 1 + 2 * dt * damp * freq; | |
| float tff = dt * freq * freq; | |
| float ttff = dt * tff; | |
| val = (k * val + dt * vel + ttff * target) / (k + ttff); | |
| vel = (vel + tff * (target - val)) / (k + ttff); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment