Skip to content

Instantly share code, notes, and snippets.

@nickworks
Last active May 29, 2021
Embed
What would you like to do?
A set of low-level functions for procedural animation.
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