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 = 0.0,
percentage = 1.0,
0.0 < percentage < 1.0,
Lerp()returns a point between
- So at
percentage = 0.5, it returns the point exactly halfway between
- And at
percentage = 0.10, it returns a point very near to
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
Lerp() correctly, you simply have to make sure that you pass the same
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.
public class LerpOnSpacebarScript : MonoBehaviour
/// The time taken to move from the start to finish positions
public float timeTakenDuringLerp = 1f;
/// How far the object should move when 'space' is pressed
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;
/// Called to begin the linear interpolation
_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;
//When the user hits the spacebar, we start lerping
//We do the actual interpolation in FixedUpdate(), since we're dealing with a rigidbody
//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
The issue with the above code is that the first parameter to
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
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.
Lerp() is actually remarkably simple:
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;