Linear Interpolation

This tutorial will explore one of the most used Mathematical tools in Game Development: linear interpolation! This first post will focus on its Mathematical definition and implementation. The following parts of this series will explore how to extend linear interpolation to non-linear mappings, and how to use them to correct colour curves.

You can find a link to download the C# scripts and the Unity package used at the end of this post.

Linear Interpolation

One of the most useful—and somewhat underrated—functions in Game Development is lerp. Shorthand for linear interpolation, you can imagine lerp as a way to “blend” or “move” between two objects, such as points, colours and even angles.

Virtually every software comes with a function to perform linear interpolation. Unity, for instance, has several; the most well-known being being Mathf.Lerp. It takes two numbers, namely a and b, and lerp them using another numbers t which value must be between 0 and 1.

The result is simple: when t=0, the result is a; when t=1, the result is b; when t=0.5, the result is the average between the two, \frac{a+b}{2}; and so on.

In a nutshell, the parameter t allows to move in the range between a and b. Mathematically, we can say that lerp is a function that maps the interval \left[0, 1\right] to the interval \left[a, b\right], and it can be expressed using the following equation:

(1)   \begin{equation*} c = a + \left(b-a\right)*t\end{equation*}

This equation might seem confusing at first, but it has a very simple geometrical interpretation, as seen in the diagram below. The value of t can range anywhere from 0 to 1. Once multiplied by b-a, it will range between 0 and b-a: exactly the size of the desired interval. Then, all that is needed is to shift it accordingly by a.

Inverse Lerp

Some libraries also feature a complementary function; Mathf.InverseLerp, in case of Unity. As the name suggests, inverse lerp does exactly the opposite of what lerp does: it remaps a number in the interval \left[a, b\right] to the interval \left[0, 1\right].

(2)   \begin{equation*} t = \frac{c - a}{b-a}\end{equation*}

A degenerate case can occur when a=b, as that would lead to a division by zero. In that case, it is not uncommon to assume t=0.5.

Even (2) can be interpreted geometrically. In this case, the exact same operations of lerp are preformed, but in reverse:

Linear Mapping

With these two functions, it is possible to remap any arbitrary value x \in \left[a, b\right] to any other integer interval \left[c, d\right].

(3)   \begin{equation*} y = c + \frac{d-c}{b-a} \left(x - a\right)\end{equation*}

which, once again, has a very immediate geometrical interpretation:

📚 An alternative derivation

Some libraries wrap those two functions into one; Arduino, for instance, calls this map. No equivalent function is present in Unity, but it can be easily implemented like this:

float y = Mathf.Lerp(c, d, Mathf.InverseLerp(x, a, b));

Or, slightly more efficiently, like this:

public static float Lerp (float x0, float x1, float y0, float y1, float x)
{
    float d = x1 - x0;
    if (d == 0)
        return (y0 + y1) / 2;

    return y0 + (x - x0) * (y1 - y0) / d;
}

Linear interpolation is indeed linear because it creates a linear relationships between between the input and output intervals. If we look at lerp as a mathematical function plotted in the cartesian plane (below), it is easy to see that it represents the equation of a line that passes between \left(a, c\right) and \left(b, d\right):

Lerping Everything…

For instance, lerping between two points means moving along the shortest path that connected them. On the other hand, lerping between two colours means blending

Points

So far, we only interpolated two numbers. But nothing stops us from interpolating two points. In this case, the easiest way to do so is to interpolate the individual X and Y coordinate:

Vector2 Lerp (Vector2 a, Vector2 b, float t)
{
    return new Vector2
    (
        Mathf.Lerp(a.x, b.x, t),
        Mathf.Lerp(a.y, b.y, t)
    );
}

Unity comes with both Vector2.Lerp and Vector3.Lerp which, as expected, allow to interpolate between points in 2D and 3D. Lerping between points, regardless of their dimension, is equivalent to moving along the line that connected them.

While lerp is inherently linear, it can actually be used to create curves. Successive interpolations on a series of points results in a family of shapes known as Bézier curves (pronounced: /ˈbɛz.i.eɪ/, BEH-zee-ay).

Vector2 Bezier (Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
{
    // Lerp between the control points
    Vector2 a = Vector2.Lerp(p0, p1, t);
    Vector2 b = Vector2.Lerp(p1, p2, t);
    Vector2 c = Vector2.Lerp(p2, p3, t);
    
    // Lerp between the lerped points
    Vector2 d = Vector2.Lerp(a, b, t);
    Vector2 e = Vector2.Lerp(b, c, t);

    // Lerped between the lerped points (again!)
    return Vector2.Lerp(d, e, t);
}

The Ever so Lovely Bézier Curve by Shader Witch Freya Holmér is possibly the most accessible article on the topic (and the source of the animation above).

Colours

Another very common way in which lerp is used is to blend colours. Conceptually, you can imagine lerping between colours as mixing different amounts of paint. Lerping between red and blue with t=0.8, for instance, is a bit like filling a can with 20% of red paint and 80% of blue paint.

The easiest way to interpolate between colours is to interpolate the single red, green and blue components independently:

Color Lerp (Color a, Color b, float t)
{
    return new Color
    (
        Mathf.Lerp(a.r, b.r, t),
        Mathf.Lerp(a.g, b.g, t),
        Mathf.Lerp(a.b, b.b, t),
        Mathf.Lerp(a.a, b.a, t)
    );
}

That is exactly how Color.Lerp works in Unity. While this technically works, it often yields rather poor results. This is because the RGB colour space is good to store colours, but not so much to manipulate them in a way that makes sense, perceptually.

Learning how to properly interpolate between colours is a dark art, which is heavily discussed in The Secrets of Colour Interpolation. You can play with the swatches below to see for yourself what difference it makes to lerp between different colour spaces.

Rotations

The last aspect that this first post is going to discuss, is about angles and rotations. From what we covered so far, one might be tempted to lerp between angles in order to perform rotations. That is actually not going to work; or at least, not always, and not as you expect.

The reason is that angles are “looping”, and being able to take that into account requires a non-linear operator. Let’s make a simple example: lerping between 90° and 180° should work as intended, giving you a nice angle that goes from 90 to 180. However, lerping from 350° to 10° will not! There are two ways to reach 10 from 350: going up, or going down. The linear interpolation does not know that it is working with angles, and it will take the longer path, decreasing the angle from 350 to 10.

One way to fix this is to use quaternions instead. Quaternions are an alternative—and somewhat safer—way or representing and working with angles in 3D. But they are also incredibly counterintuitive and difficult to grasp.

Unity comes with its own way to lerp between quaternions, called Quaternion.Slerp. The term slerp stands for spherical linear interpolation. In a nutshell, slerp allows to lerp between any two points on a sphere, rather than a flat plane. A future series will delve into the absolute madness that are quaternions; luckily for you, this is not that series.

📰 Ad Break

What’s Next…

The second part of this series will see how the linear interpolation can be extended to non-linear functions.

Download Unity Package

Become a Patron!

The Standard package contains the script to perform piecewise linear interpolation. It uses extension methods which allows to easily interpolated numbers, vectors, colours and even quaternions! The Advanced package, instead, contains a test scene which also shows how to correct colour curves.

FeatureStandardAdvanced
Linear Interpolation
Piecewise Interpolation
Test scene
Colour Curve Correction

Comments

12 responses to “Linear Interpolation”

  1. […] some topics that have been covered extensively on this website; one of them is without any doubt Linear Interpolation. Linear interpolation provides a mathematical expression to calculate the positions of the line […]

  2. […] linear interpolation, and it has been explored in great details in several articles, including Linear Interpolation and The Secrets of Colour […]

  3. Not making games avatar
    Not making games

    Waiting for the quaternions series man. I found your site now and will read all the articles. Great stuff! Cheers man!

    Not making games.

    1. Thank you! 🙂
      I hope to publish the Quaternion series soon!

  4. great article! one tiny typo… “excepted” should be “expected” in one place.

    1. Thank you for spotting that!

  5. This is dope! I was looking into how to make AI movement patterns and this Linear Interpolation looks like a great way to accomplish some unique movement.

  6. You don’t need to use an exotic colour space like LCH to get quality lerping between colours, you just need to use a linear colour space. RGB is fine as long as it’s Linear RGB. If you’re not sure if your RGB colour space is Linear RGB, it almost certainly isn’t.

    If you’re using non-linear (“Gamma”) RGB and you want to do good quality linear interpolation, the easiest solution is to convert to Linear, do the interpolation, and then convert back to Gamma. A quick and dirty approximation to convert from Gamma to Linear is to normalize your RGB values to to range 0.0 – 1.0, and then take the square root. To convert back to Gamma you square each value (and multiply by 255 if needed). Depending on the actual colour space of your target device this conversion probably isn’t exactly right, but it’s still a lot better than interpolating in Gamma space.

    Unity has an option to use a Linear RGB colourspace, which you should turn on if you can to get much better quality lighting (but it isn’t supported on some target platforms). I don’t know if this affects the behaviour of Color.Lerp but that should be easy to check.

    1. I got the conversion between gamma and linear backwards but hopefully you get the gist.

    2. Also note HSV/HSL aren’t linear colourspaces either, which is why linear interpolation in HSV space still looks kind of muddy, although not usually as bad as Gamma RGB.

  7. […] Part 1: Linear Interpolation […]

  8. […] Part 1: Linear Interpolation […]

Leave a Reply

Your email address will not be published. Required fields are marked *