Monthly Archives: February 2014

Using Vector3.Lerp() correctly in Unity

48
Filed under Uncategorized

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.

Linear Interpolation Example

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.

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.

  1. 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
  2. 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.
  3. 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:

(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)