Skip to content

Instantly share code, notes, and snippets.

@FleshMobProductions
Created February 24, 2021 07:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FleshMobProductions/194a4f98f0b397e4fe8d9c79592c3a7f to your computer and use it in GitHub Desktop.
Save FleshMobProductions/194a4f98f0b397e4fe8d9c79592c3a7f to your computer and use it in GitHub Desktop.
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);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment