# You’re Using Lerp Wrong

Linear interpolation, or “lerp” for short, is a technique commonly used when programming things like games or GUIs. In principle, a lerp function “eases” the transition between two values over time, using some simple math. This could be used to slide a character between two coordinates, or to animate a change in size or opacity of a UI element. If you lerped between two colors, you’d get a gradient. The Unity game engine includes helper functions for Lerp in the Vector, Quaternion and floating point Math classes.

The use case I’ve been working with lately is smoothing player movement from coordinate to coordinate in network code. Since there are inherent latency and bandwidth limitations over the Internet, and you can only reasonably send so many packets per second, simply updating a player’s transform from one vector to another would result in very jerky movement. The solution: for every pair of packets that come in, in which the player will only move a few meters, you lerp between the vectors over a time roughly equal to the time between the packets. This slides the character smoothly, so it doesn’t stutter around.

In my Internet travels, I’ve noticed that a lot of examples in the Unity community–that’s the game engine I’m using–are *bad.* (And in the words of Zoidberg, perhaps they should feel bad.)

This is the very popular antipattern I see all over the place:

`public void Update() {`

// [...]

pos = Vector3.Lerp(**obj.transform.position**, targetPosition, **0.1f**);

obj.transform.position = pos;

}

This is a misuse of the `Lerp()`

function, and while it may *look* good enough at a glance, it’s mathematically bad and can lead to unexpected behavior. Unfortunately, in typical internet fashion, something that is wrong but mostly works will inevitably be cargo culted and spread like an invasive weed.

The Lerp function, in the Unity docs, is defined with the following signature:

`public static Vector3 Lerp(Vector3 a, Vector3 b, float t);`

As designed, **the ****a**** value and the ****b**** value should not change during the interpolation**. The only value that *should* change is `t`

, which is a percentage–expressed as a value from 0.0 to 1.0–of the distance between the two values.

- When
`t`

is 0.0, the function returns the value of`a`

. - When
`t`

is 1.0, it returns the value of`b`

. - When
`t`

is 0.5, the returned value is halfway between the two.

**The ****t**** value should absolutely not be a constant**, as it represents where, on the continuous line, the return value falls.

“But it works, doesn’t it? Why is it bad?” you may ask.

Well, the way that code snippet works, the `a`

vector is shortened every frame. So the model is moved 10% closer to its target, then on the next frame it’s moved 10% further along the *remaining* distance. This results in the value telescoping, eventually moving incredibly tiny distances toward the target. Depending on use case, this can cause weirdly slow movement near the end, excessive iterations, gradual drift from imprecision, or other undesirable behavior.

The Lerp function, mathematically, is defined as `lerp(a, b, t) = a + (b — a) * t`

. I’m using the single float version of this (from the Mathf class), since it’s simpler than the Vector3 version. For the algebra-averse, the English version is “the starting position, plus some percentage of the distance between the two values.”

If you add mental parentheses around the terms in the box, it should be easily understood: we’re just adding a variably-sized chunk of the distance between the start and end value onto the start value, moving us toward the destination.

Vectors are the same idea, only in more dimensions. Break the components apart and lerp them independently, then you can put the vector back together…and be thankful that Unity vectors just *give* you the components, instead of notating them as an angle and magnitude, like you run into in Physics.

To illustrate proper vs. bad lerping, I wrote up some quick and dirty Python code.

def lerp(a, b, t):

return a + (b-a) * tpos = 2

for i in range(0, 11):

t = i/10 #we want t to be 0.0 to 1.0

pos = lerp(2, 5, t)

print(f"t={t}: {pos}")

This shows the correct way to do it, linearly interpolating from 2 to 5 as our t value goes from 0.0 to 1.0.

`t=0.0: 2.0`

t=0.1: 2.3

t=0.2: 2.6

t=0.3: 2.9

t=0.4: 3.2

t=0.5: 3.5

t=0.6: 3.8

t=0.7: 4.1

t=0.8: 4.4

t=0.9: 4.7

t=1.0: 5.0

In contrast, this is an implementation of the “bad way” that keeps cropping up all over the Unity community. We’re still starting at 2 and moving to a target value of 5. However, this time the t value is a constant 10% and the `a`

value is being changed on every iteration.

def lerp(a, b, t):

return a + (b-a) * tpos = 2

for i in range(0, 20):

pos = lerp(pos, 5, 0.1)

print(f"Iteration {i}: {pos}")

The output is not at all what we expect…

`Iteration 0: 2.3`

Iteration 1: 2.57

Iteration 2: 2.8129999999999997

Iteration 3: 3.0317

Iteration 4: 3.2285299999999997

Iteration 5: 3.405677

Iteration 6: 3.5651093

Iteration 7: 3.70859837

Iteration 8: 3.837738533

Iteration 9: 3.9539646797

Iteration 10: 4.05856821173

Iteration 11: 4.152711390557

Iteration 12: 4.2374402515013

Iteration 13: 4.31369622635117

Iteration 14: 4.382326603716053

Iteration 15: 4.4440939433444475

Iteration 16: 4.499684549010003

Iteration 17: 4.5497160941090025

Iteration 18: 4.5947444846981025

Iteration 19: 4.635270036228293

Yikes. We ran that almost twice as many times, and it’s still not reaching the target value. It wouldn’t even after 1000 iterations. It would reach 4.999 repeating, but would never actually hit the target value.

So, from that initial example, you could be moving that game object every frame for a long time. Unless you did some voodoo coding and slapped in a conditional to make it stop when it’s less than 0.001 units off from the target, like many of those questionable implementations do. But that’s just sweeping dirt under the rug.

So, how do you correctly move a game object in Unity with lerp? The following isn’t a definitive answer–after all, every use case and implementation is different–but it’s on the right track:

Vector3 startPosition = gameObject.transform.position;

Vector3 targetPosition = ... ;int frames = 0;

int maxFrames = 90;public void Update() {

if (frames > 90) return;

float t = frames / maxFrames;

pos = Vector3.Lerp(startPosition, targetPosition, t);

obj.transform.position = pos;

frames++;

}

- The start and target positions are properties outside of the Update function, because they do not change. We don’t want the start position and the game object’s position to be the same at any time other than the very first iteration.
- The
`t`

value is calculated as a percentage. In this case, I’m just using a counter, so`t`

progresses from 0.0 to 1.0 over 3 seconds (30 frames per second).

This example moves the game object over 3 seconds (30 frames per second). There are more robust ways to do this, but it gets the point across. The important thing is that `t`

is calculated as the elapsed time over the desired duration of the movement, however you measure those.

Please, if you’re going to copy and paste something, steal that one.