{{ message }}

Instantly share code, notes, and snippets.

# FleshMobProductions/PiecewiseLerp.cs

Created Feb 24, 2021
PiecewiseLerp for cheaply interpolating between cached results of more complex interpolation functions, based on https://www.alanzucconi.com/2021/01/24/piecewise-interpolation/
 // An additional implementation for piecewise interpolation described in this article: // https://www.alanzucconi.com/2021/01/24/linear-interpolation/ // It has the limitation that it requires the delta difference between 2 adjacent values of the input array to always be constant. // For example: inputs[2] - inputs[1] = 0.2f; inputs inputs[3] - inputs[2] = 0.2f; etc. public static float PiecewiseLerp (float[] inputs, float[] results, float desiredInput) { int n = inputs.Length; float inputMin = inputs[0]; float inputMax = inputs[n - 1]; // Don't support extrapolation: if (desiredInput < inputMin) return results[0]; if (desiredInput >= inputMax) return results[n - 1]; // Map to values that correspond to the array index progression float percent = Mathf.InverseLerp(inputMin, inputMax, desiredInput); float step = 1f / (n - 1); int matchedRangeStartIndex = (int) (percent / step); float matchedRangePct = (percent % step) / step; return Mathf.LerpUnclamped(results[matchedRangeStartIndex], results[matchedRangeStartIndex + 1], matchedRangePct); }
 // Demonstration of the PiecewiseLerp function. Can be ran on https://dotnetfiddle.net/ using System; public class Program { public static void Main() { TestPiecewiseLerp(); } private static void TestPiecewiseLerp() { float[] ranges = new float[]{ 0.05f, 0.1f, 0.15f, 0.2f, 0.25f}; float[] results = new float[] { 2.05f, 2.1f, 2.15f, 2.2f, 2.25f }; float[] interpolators = new float[] { -1f, 0f, 0.05f, 0.1f, 0.12f, 0.2f, 0.25f, 0.5f }; foreach (float interpolator in interpolators) { Console.WriteLine(string.Format("Result for {0} is {1}", interpolator, PiecewiseLerp(ranges, results, interpolator))); } } private static float PiecewiseLerp (float[] inputs, float[] results, float desiredInput) { int n = inputs.Length; float inputMin = inputs[0]; float inputMax = inputs[n - 1]; // Don't support extrapolation: if (desiredInput < inputMin) return results[0]; if (desiredInput >= inputMax) return results[n - 1]; // Map to values that correspond to the array index progression float percent = Mathf.InverseLerp(inputMin, inputMax, desiredInput); float step = 1f / (n - 1); int matchedRangeStartIndex = (int) (percent / step); float matchedRangePct = (percent % step) / step; return Mathf.LerpUnclamped(results[matchedRangeStartIndex], results[matchedRangeStartIndex + 1], matchedRangePct); } } public static class Mathf { public static float LerpUnclamped(float min, float max, float x) { return min + (max - min) * x; } public static float InverseLerp(float min, float max, float value) { if (min == max) return min; return (value - min) / (max - min); } }