A lot of Unity 3D tutorials online use Unity’s linear interpolation incorrectly, including the official video tutorials(!). However, it’s actually very easy to use, once you understand how it works.

The prototype for `Vector3.Lerp`

looks like this

static Vector3 Lerp(Vector3 start, Vector3 finish, float percentage)

What it does is simple: it returns a point between start and finish, based on the value of `percentage`

:

- At
`percentage = 0.0`

,`Lerp()`

returns`start`

- At
`percentage = 1.0`

,`Lerp()`

returns`finish`

- At
`0.0 < percentage < 1.0`

,`Lerp()`

returns a point between`start`

and`finish`

. - So at
`percentage = 0.5`

, it returns the point exactly halfway between`start`

and`finish`

. - And at
`percentage = 0.10`

, it returns a point very near to`start`

etc.

This explains why it’s called linear interpolation: It moves smoothly (interpolates) at a constant speed (linearly) between two points!

## How to use Lerp correctly

To use `Lerp()`

correctly, you simply have to make sure that you **pass the same start and finish values every frame** while moving percentage up from 0.0 to 1.0 each frame.

Here’s an example. When the spacebar is pressed, we’ll lerp our object 10 spaces forward over a period of 1 second.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | using UnityEngine; using System.Collections; public class LerpOnSpacebarScript : MonoBehaviour { /// <summary> /// The time taken to move from the start to finish positions /// </summary> public float timeTakenDuringLerp = 1f; /// <summary> /// How far the object should move when 'space' is pressed /// </summary> public float distanceToMove = 10; //Whether we are currently interpolating or not private bool _isLerping; //The start and finish positions for the interpolation private Vector3 _startPosition; private Vector3 _endPosition; //The Time.time value when we started the interpolation private float _timeStartedLerping; /// <summary> /// Called to begin the linear interpolation /// </summary> void StartLerping() { _isLerping = true; _timeStartedLerping = Time.time; //We set the start position to the current position, and the finish to 10 spaces in the 'forward' direction _startPosition = transform.position; _endPosition = transform.position + Vector3.forward*distanceToMove; } void Update() { //When the user hits the spacebar, we start lerping if(Input.GetKey(KeyCode.Space)) { StartLerping(); } } //We do the actual interpolation in FixedUpdate(), since we're dealing with a rigidbody void FixedUpdate() { if(_isLerping) { //We want percentage = 0.0 when Time.time = _timeStartedLerping //and percentage = 1.0 when Time.time = _timeStartedLerping + timeTakenDuringLerp //In other words, we want to know what percentage of "timeTakenDuringLerp" the value //"Time.time - _timeStartedLerping" is. float timeSinceStarted = Time.time - _timeStartedLerping; float percentageComplete = timeSinceStarted / timeTakenDuringLerp; //Perform the actual lerping. Notice that the first two parameters will always be the same //throughout a single lerp-processs (ie. they won't change until we hit the space-bar again //to start another lerp) transform.position = Vector3.Lerp (_startPosition, _endPosition, percentageComplete); //When we've completed the lerp, we set _isLerping to false if(percentageComplete >= 1.0f) { _isLerping = false; } } } } |

## How to use Lerp incorrectly

In our above example, we call `Vector3.Lerp()`

like this:

transform.position = Vector3.Lerp(_startPosition, _endPosition, percentageComplete);

However, the method for calling Lerp you see in many tutorials online looks like this:

transform.position = Vector3.Lerp(transform.position, _endPosition, speed*Time.deltaTime);

Before I explain what’s wrong with this, please take a moment and try to figure out for yourself what this code will do, and why it’s wrong

…

…

…Ready?

The issue with the above code is that **the first parameter to Lerp(), transform.position, changes every frame!** Additionally, the

`percentage`

parameter *(the third parameter)*does not increase from 0.0 to 1.0, but instead is set to the completely arbitrary value

`speed*Time.deltaTime`

.What this code actually does is move the object `speed*Time.deltaTime`

-percent closer to `_endPosition`

every frame.

There are several problems with this.

**It’s non-linear**ie. the speed is not constant. This is easy to see in the official video tutorial; the object moves quickly at first, and slows down as it nears its destination**The object’s speed varies with the user’s framerate.**The higher the user’s framerate, the faster the object will move. This defeats the purpose of using`FixedUpdate()`

to begin with, which is supposed to alleviate this problem.**The object never reaches its destination**since we only move a percentage closer each frame. Actually, due to floating-point rounding, it may or may not ever reach its destination. Additionally, because of problem 2, whether or not it ever reaches its destination depends on the user’s framerate.**Ouch!**

## The implementation of Lerp

As a final note, I’d like to share how `Lerp()`

is typically implemented. This section is not required, but mathematically-inclined readers will find it interesting.

Implementing `Lerp()`

is actually remarkably simple:

1 2 3 4 5 6 7 8 9 10 11 | public static Vector3 Lerp(Vector3 start, Vector3 finish, float percentage) { //Make sure percentage is in the range [0.0, 1.0] percentage = Mathf.Clamp01(percentage); //(finish-start) is the Vector3 drawn between 'start' and 'finish' Vector3 startToFinish = finish - start; //Multiply it by percentage and set its origin to 'start' return start + startToFinish * percentage; } |

*(Edit Oct 2016: A commenter correctly pointed out that this implementation of Lerp() has floating-point rounding issues. See his comment for a more accurate version)*

## 33 Comments

They’re not using it incorrectly. They’re using it to approximate exponential decay to the target position.

current = Lerp(current, target, T)

At each frame, the position is moved T percent toward target. Using Time.deltaTime in T makes the movement framerate independent.

Using it this way isn’t always appropriate, but it works well for smoothing out camera movements where responsiveness is still important. Also works well with Quaternion.Slerp for rotations in similar circumstances.

If you want exponential interpolation, you should be using an exponential interpolation function, not using a linear interpolation one incorrectly.

Not only does that convey the intent of the code better, but it also won’t have the frame-rate-dependency and floating-point rounding issues that I mentioned above. The way the video uses it is simply wrong.

Framerate-dependency is not an issue here because the code from the video is not using FixedUpdate() like your code. Using Lerp with deltaTime within Update(), like in the video, will produce framerate-independent results.

Nope, that is not true, the code in the video is still framerate-dependent. Moving 4% towards a destination 25 times a second is not the same as moving 2% towards it 50 times a second.

Oh man you are actually right, I never thought of it that way. Well I have been using Lerp like a fool for years now. Thanks for explaining this!

I found this very useful. Question though, did I miss it or you didnt talk about how to implement adjustable speed?

Speed is just distance / time. Using the variable names in my example-script, it’s

`speed = distanceToMove / timeTakenDuringLerp`

.So to increase the speed, either increase the distance or decrease the time.

If you have a specific speed you want to go at, set

`timeTakenDuringLerp = distanceToMove / speed`

Hi BlueRaja

Thanks for this, as a complete beginner coder was of great help. If one wanted to lerp smoothly so that initially it’s fast, then medium speed then slows down before destination, are there some easy modifications to this code to allow for this? Other tutorials seem to suggest there is..

Of course there’s a way! When we vary the third parameter,

`percentage`

, linearly each frame, we get a linear result. If we vary`percentage`

in a non-linear way, we get a non-linear result.So, we need to do some fancy math to

`percentage`

to change it in such a way that it increases quickly near the start and slowly near the end, but still starts at 0 and ends at 1.The simplest way I know of doing this is raising

`percentage`

to a power. For instance, if we pass in`Math.pow(percentage, 0.5)`

, the distance-over-time graph will look like this.So, the final call looks like this:

`Vector3.Lerp(start, finish, Math.pow(percentage, 0.5));`

I would probably pull that into a separate function called

`ExponentialInterp()`

or something. You can also play with the power,`0.5`

, to make it fit your needs.Thanks so much for this! I was just looking over some Lerp that I’ve been using for a long time. It had the similar Time.deltaTime * speed. I had never questioned it until tonight. How obviously silly a thing.

hey, very helpful post indeed. thanks a bunch!

also, could you please upload your monodevelop color scheme?

thx!

There are several things that I like about this script in the context of teaching somebody how and why a script is doing what it does.

For one, It works, which is always a big plus.

I appreciate the comments which are thorough but to the point. A lot of times I just get confused by people’s comments. Starting booleans with “_is” is a nice touch. I don’t know if that’s a common thing but it helped me follow the program flow so I might just have to adopt that one.

But what I absolutely love about this is that all the lerp parameters are broken down and captured by your variables, so you can track the lerp from start to finish through the code. Very useful and much improved from any other explanation I’ve come across.

Thanks for sharing this. It’s a big help. Now I’ll probably crash and burn when applying this approach to rotation but hey you never know.

Thank you, thank you, thank you!

I always wondered why my lerps were never working correctly. The examples in many tutorials really threw me off.

Thanks for sharing this, I have a question, is there any way to use update instead of FixedUpdate and make it frame-rate-dependency, am using this to move npc’s along a path after all i dont want them to slow down on slower devices.

I think you’re confused? If the code were framerate-

dependent, the npc’s would slow down on slower devices. However, since it’s framerate-independentalready, they will have the same speed regardless of device speed.yes that’s correct, but i noticed a drop on frame rate when i used the code in FixedUpdate to move a huge amount of npc’s, they all have rigidbuddy attached to them just for collision reporting, so i moved the code to the Update method and the problem disappeared, that’s why i want to be frame-rate-d, any advice ? thanks

You’re super duper off, man. What’s likely happening is that your Update() method is firing more than 60x /sec, so it looks like things are running smoothly. You want to either multiply every time affected variable by Time.deltaTime, or move things to FixedUpdate. If you have slowdown issues it’s not Update/FixedUpdate that’s the issue. It’s you’re code. You want everything, always, to be framerate dependent. Like really… always.

holy crap! can you please do more tutorials? your explaining is simple for slow learners like me.

short and to the point with pictures. plus you use names that makes sense for variables.

This is a great explanation of LERP and has just saved me a whole bunch of time trying to make my script work properly. I have noticed one item worth mentioning, if the Update event should re-occur during the FixedUpdate, then StartLerping() runs again and the _timeStartedLerping is reset to a new time, thus the Lerp overshoots the finish position.

Fix for this is to change the following within Update()

if(Input.GetKey(KeyCode.Space) && !_isLerping)

Works great how you explained.

For the 2 hours I searched online and through docs,(Unity docs and other0 I needed a slow movement of a transform from one position to another. This works good. Thanks.

This is the best explanation for LERP, make more tutorials , ur explanation is soo…good . Please make tutorials on Quaternion and Euler angles

Just want to thank you for writing this.

After a ton of googling this is the page that finally made me understand how to use Lerp.

Does the same apply to Quaternion.Lerp()?

its quite helpful. appreciate it.

Useful tutorial! I just have one question. I have enemies that are spawning at a certain Transform objects position. The end points and start points that I had for my Lerp were Transform objects using empty game objects. How am I supposed to set my start and end points using Vector 3? I tried manually setting them and no lerp was working whatsoever.

I had a problem with a rough camera movement cause i was using Lerp the wrong way, Great explanation in why to use the correct way and thanks for this post! Definitely helpful! 🙂 Will surely recommend this to fellow devs 😀

You have magically saved my brain from melting! Thank you so much for this. I’ve been trying to understand why my lerps never work the way they are supposed to and Finally I get it.

Updating the start position with transform.position made sense until I understood that it’s not T… but P for percentage of time.

Holy crap its so simple it is almost embarrassing that I never saw it.

THANK YOU!

Thanks a lot! Helped get the right experience in the game, which wasn’t possible with the more common way lerp is used in tutorials.

Thanks man! Nice explaination.

The demonstration Lerp() function you have is likely not numerically stable because it amplifies floating point representation error. Try val = (1-t)*v0 + t* v1; for a better interpolation from v0 to v1 when t moves from 0.0 to 1.0.

Good point! I won’t change the code

(as it’s really meant to be educational anyways), but I’ll mention this comment in the post. Thanks!Hi I was just wondering if you could explain why this needs to be done a little bit more mundanely, and maybe implemented in the code in the article also?

Thank you this is an amazing article!