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; } |