Using Lerp properly

LERPWhat is Lerp?

Lerp is the term for Linear Interpolation.

In short, Lerp, in Unity, is for finding a desired value between two known values.

As of the time of publishing this article, Lerp is horribly abused and terribly documented, and I would like to redress this, if at all possible.

Unity’s Lerp function can be found in the documentation.

When searching for “Lerp”, we will find that Lerp is implemented in many classes, including Vectors 2, 3 & 4, Color, Quaternion and more. There is also a related “Slerp”, which is “Spherical Linear Interpolation“. We are going to concentrate, however, on Mathf.Lerp, for now

Now, just to be clear, we are not talking about the iconic character, Lerpz, from Unity’s past:

Lerpz

Lerpz was the iconic character Unity used for it’s first tutorials in versions 1.x and 2.x

When looking at the documentation, at the time of publishing this article, the description is very thin, and the code example for Lerp is thoroughly confusing.

I’ve been trying for years to get this page updated, but to no avail!

So here goes my explanation:

We use Lerp when we want to find a new value between a starting value and an ending value.

A common case for using Lerp would be moving or animating something between two points over time, in a linear fashion. In this case we have a known start point (from), a known end point (to), and we have control over our time value (t).

When we move something using Lerp, we simply send Mathf.Lerp our start position, our end position and the time that has elapsed during the move process, usually modified by a speed value to control how fast the transition from start to finish happens. Lerp then gives us back where along that path between the start point and the end point our object is.

Let’s look at the signature:

static float Lerp (float from, float to, float t);

We can see that Lerp returns a float value. We give Lerp a “to”, a “from” and a “t”.

Note that “t” is clamped between 0 and 1.

Reading the description:

When t = 0 returns from.
When t = 1 return to.
When t = 0.5 returns the average of a and b.

… this means we can find any value we want between “from” and “to” based on the value of “t”, as long as “t” is between “o” and “1”. “o” is the start point, “1” is the end point, and any value between “0” and “1” corresponds to value between start and end.

Now the confusion begins.

The code example looks like this:

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
    public float minimum = 10.0F;
    public float maximum = 20.0F;
    void Update () {
        transform.position = new Vector3 (Mathf.Lerp (minimum, maximum, Time.time), 0, 0);
    }
}

Where this example fails, is in the use of raw Time.time.

When new users grab this code and try to use it, they see no change and the item is apparently slammed over at the “to” value immediately. This is mainly because Time.time goes from “0” to “1” in, well, 1 second. And it usually takes more than 1 second for the test scene to get up and running.

This also doesn’t make any sense as a proper use case. When would a Lerp calculation ever be used in a game or application starting on the very first frame? And not have the time of the calculation be modified?

To see a proper explanation of Lerp, we need to see a start time set and then see the incrementation of time over time, from start, through to finish, preferably with a speed value to modify it.

Understandably, this makes a more complicated example, but I would change the code to this:

using UnityEngine;
using System.Collections;

public class LerpTest : MonoBehaviour {
  public float start = 0.0F;
  public float end = 90.0F;
  public float transitionSpeed = 0.5f;
  public float startTime = 1.0f;

  void Update() {
    float lerpValue = Mathf.Lerp (start, end, (Time.time - startTime) * transitionSpeed);
    transform.eulerAngles = new Vector3 (lerpValue, 0, 0);
  }
}

By giving a “start time”, we can see the beginning of the transition. Just delaying the start, however, is not the most important part. The important part is that we can control when we do our Lerp. This shows us we can now initiate this with a key click, or a button, or an event; and it can be done at any time in the game.

By adding a “transition speed”, we can see that we have control over how fast the transition takes place. We can control the speed of our transition.

Misusing Lerp:

Lerp is commonly misused in one particular way.

This is often because of the original example code, which many people assumed was broken. To fix this supposedly broken example, people used Time.deltaTime in place of Time.time.

A common example would be:

using UnityEngine;
using System.Collections;

public class LerpTest : MonoBehaviour {
  public float destination;

  void Update() {
    float newPositionX = Mathf.Lerp (transform.position.x, destination, Time.deltaTime);
    transform.position = new Vector3 (newPositionX, 0, 0);
  }
}

This has some interesting effects. It makes a kind of “easing” or “dampening” effect on the object’s transition.

The first thing to think about is Time.deltaTime. It doesn’t approach any number. It doesn’t go from 0 towards 1. It will be a fairly consistent value as long as the game is running at a consistent frame rate. This means each frame the value of Time.deltaTime will be “hovering” near the same value. If we weren’t feeding in the transform’s position each frame, the Lerp would not move towards any “to” value, but jiggle near a single value.

Try this:

using UnityEngine;
using System.Collections;

public class LerpTest : MonoBehaviour {
  public float start = 0;
  public float destination = 5;

  void Update() {
    float newPositionX = Mathf.Lerp (start, destination, Time.deltaTime);
    transform.position = new Vector3 (newPositionX, 0, 0);
  }
}

… and the test object will simply jiggle based on the current frame rate.

The first example of using Time.deltaTime works because during each frame the start point is reset to the transform’s current new position. This means that for each frame, the calculation is essentially restarted. The smoothing or dampening comes from the fact that destination doesn’t change, so each frame the test object will move some small incremental value towards the destination value. The danger of this is: The test object will never ever reach the destination value.

If that first example script were put on a test object and the transform were observed at run time, long after the GameObject had seemingly “stopped”, tiny incremental changes will still be visible in the transform’s position. It will continue to split these tiny values by increments until the limit to the float value is reached, all the time taking up performance.

Can I still use Lerp for smooth dampening?

Yes, we can, but we need to be aware of what we are doing.

We need to be aware that we are essentially mis-using Lerp to make a smooth-damp by using Time.deltaTime and resetting our start position.

Isn’t this the key to so many things in life? We can break the rules once we know why they are there?

To make that “misused” code work, we need to detect an “almost there” threshold, and then stop the Lerp.

Let’s do this with:

public float threshold = 0.1f;
   // and
if (newPositionX < threshold) {...

… let’s also contain the movement code with a simple check:
if (transform.position != destination) {...

The complete code would be:
using UnityEngine;
using System.Collections;

public class LerpTest : MonoBehaviour {
  public float start = 0;
  public float destination = 5;
  public float threshold = 0.1f;

  void Update() {
    if (transform.position.x != destination) {
      float newPositionX = Mathf.Lerp (start, destination, Time.deltaTime);
      if (newPositionX < threshold) {
        newPositionX = destination;
      }
      transform.position = new Vector3 (newPositionX, 0, 0);
    }
  }
}

I hope this helps in someway to explain Lerp a little better than it does in the docs.

6 Comments

Sudhir

about 2 years ago Reply

well explained, before reading this, i thought much different about lerp. I thought that lerp makes a value smoothly move towards another value and that 't' is the rate of doing so. But it was giving me some problems in my project therfore i searched and found your solution. Thanks once again

Adam

about 2 years ago Reply

Yes! Using Lerp to Smooth is one of the major misconceptions of using Lerp. It's simply meant to move between a and b by t like a slider where t is the position of the slider between a and b! Also, be aware of all of the helper functions built into Unity, like move towards, smooth damp, and others. Many of these are in the Mathf class.

good.enough

about 2 years ago Reply

Hi, I enjoy your contributions to the Unity Learn site, and you have helped me learn many interesting and useful things. I also use the Lerp function to do things other than move objects. For example, if I had a camera that I wanted to move between two positions based on the position of the mouse on the screen, I would do something like this: public Transform mainCamTransform; public Vector3 cameraPos_1, cameraPos_2; float mousePos = Input.mousePosition.x / Screen.width; mainCamTransform.position = Vector3.Lerp(cameraPos_1, cameraPos_2, mousePos); -good.enough

Adam

about 2 years ago Reply

That works! Value a, Value b and a Value t for interpolation!

Brandon

about 2 years ago Reply

I have a question about your Lerp. I tried to change color using lerp. But when I tried several times, lerp is getting faster ... So if I using Color.Lerp then how to reset the speed? For example, I want to change white -> red -> yellow -> blue something like this. Thank you.

Adam

about 2 years ago Reply

This is odd behaviour. Color.lerp should work the same way as Mathf.lerp. Color A, Color B and Value T for interpolation. To go from Color A to Color B, and then Color B to Color C, you should probably put the Color.lerp into a series or loop, but as long as your Value T is consistent and time based, it should be regular. Do you have code? You may want to join the forum on this site and give more details, or ask on the Unity forum if you are more comfortable.

Leave a Comment

Please be polite. We appreciate that. Your email address will not be published and the required fields are marked.