Notifications
Article
Interpolation - Part 4
Updated a year ago
2.0 K
0

Interpolation - Time and Delta

This is a multi-part series:
  1. Introduction - what is Lerp/Interpolation
  2. Curves and Graphs - how to visualize interpolation
  3. Creating Curves - how to use curves in unity
  4. Time - expanding on the concept of delta
  5. Code - examples and use cases

Recap

In Part 3, we had a look at actually creating some Unity scripts that did some interpolation. We exposed that interpolation in the form of a slider, manually moving between the values 0 and 1 to get from the start to the end of our interpolation. We ended with the question:
What exactly is that 0-1 value we have been calling Time and how can we animate it?

Lifecycle

Before we get to that we have to ask a more fundamental question. How does Time work in unity? what even is the concept of time (in the context of unity, lets not go crazy!).
Most people understand Applications in the form of a Lifecycle. For example, every single app on your android phone runs through this exact lifecycle:
This is a pretty typical idea in software. Most applications follow a similar structure. At their core, regardless of how they are ran, most applications are in the form of some "activity","task", or "process" that runs through these steps.
It is no different for scripts you write in unity:
Yeesh. The unity one has a lot more steps, but the basic concept is the same:
  1. Something calls Start on your script
  2. An Update function gets called (a number of times?)
  3. Then at some stage a Quit or Disable is called.
That Update is what interests us. Once unity starts up our script, how often does unity call that update method? How do we know?

Update Loop

The unsatisfying answer to "how often does unity call update?" is... as often as it can.
Just like a games framerate; updates (unless capped), are basically only limited by the hardware. The better your machine, the more updates you get.
This leads to a big problem for us as designers. If time is not constant, we cannot rely on it.
Let's take a really simple pseudocode example:
void Update(){ var stepSize = 1; StepForwardBy(stepSize); }
If I am running my game at a nice healthy 60 FPS (Frames per second), every second my character will move 60 steps.
On a more powerful machine at 200 FPS , my character instead moves 200 steps a second. If that wasn't bad enough, framerate is not even constant!
Imagine you are walking forward through a cave, then suddenly you exit the cave and look at a sprawling city. That city will take a lot longer to draw than the few walls of a cave. All of a sudden instead of the 60 steps a second you were taking, you are now taking 40!
... but if you look at your feet, it doesn't draw the city. Now you are back to 60!
Clearly this is not the way to go.

DeltaTime

In order to make sure we are moving at a proper rate, we need to vary our step size by how many frames are running, or to be more accurate, how much time has passed between frames.
Let's take a look at that 60 FPS example again. Unity gives us access to a handy little value: Time.deltaTime.
In their own words:
The time in seconds it took to complete the last frame. Use this function to make your game frame rate independent.
If our game is running at 60 Frames per second then each frame will take:
1 / 60 = 0.0166
It will take 0.0166 seconds to run that single update. That is exactly what Time.deltaTime returns.
If we were running at 120 FPS it would be:
1 / 120 = 0.008333
With that in mind let's revisit our code example:
void Update(){ var stepSize = Time.deltaTime; StepForwardBy(stepSize); }
At 60 FPS: we are moving by 0.0166 every update; after 60 updates (1 Second) we have moved 1 STEP.
At 120 FPS: we are moving by 0.008333 every update, after 120 updates (1 Second) we have moved 1 STEP
Now our updates are FRAMERATE INDEPENDENT. We can happily work in Seconds instead of in random update frames.
Let's return to our interpolation example:

Interpolation Time

Up until now I have been referring to Delta as the axis across from time in our Curve.
In math terms, a Delta is:
a finite increment.
Or:
variation of a variable or value
I personally like to call it an AMOUNT OF CHANGE.
In our interpolation, the Delta is the amount of change our interpolation is at from 0 to 1. Effectively what percentage along our transition we are at. In Time.deltaTime, it is the amount of change from update frame to update frame.
Let's take a look at another simple code example:
float percentage = 0; public void Update() { result = Mathf.Lerp(0,1,percentage); }
In this example... nothing happens. No matter how many times we update, percentage never changes and the result will always be 0.
What happens if we do this?
float percentage = 0; public void Update() { percentage += Time.deltaTime; // add deltatime to percentage every update result = Mathf.Lerp(0,1,percentage); }
Regardless of the framerate, if we keep adding deltaTime up, it will increase by 1 every 1 second.
That means when we run this update, it will be at 0 at the start, but after 1 second it will be 1. We now have an interpolation that can happen independently over a period of time.
This is still only occurring over 1 second. Let's add another variable to give us more control:
public float DurationInSeconds = 4; float percentage = 0; public void Update() { percentage += Time.deltaTime / DurationInSeconds; result = Mathf.Lerp(0,1,percentage); }
Using deltaTime alone will take 1 second, dividing it by 4 means it takes 4 times longer and lasts 4 seconds.

Common Mistake

This brings me to a common misunderstanding of how lerp works:
public void Update() { result = Mathf.Lerp(result,1,Time.deltaTime); }
You can tell someone is doing something similar if the first value in their Lerp function is the same as the output result. Can you guess what it does?
Let's pretend the framerate is constant. We are at 60 FPS and so Time.deltaTime is always 0.0166.
  • Result starts at 0.
  • After one update, result is set to 0.0166% along the transition from 0 -> 1.
  • After another update, result is now 0.0166, so the Lerp is from 0.0166 -> 1. Again, it moves 0.0166% of the transition from one to the other.
In short, it will move from 0 to 1, though never actually really USE the Lerp. It won't sample the values of percent, but just go a set amount (the current frame rate) every frame and move the start position. It is a weird way to use a Lerp.
A fun side effect of this approach is that it will also never actually reach its target. it will get REALLY close, but it is always interpolating by 0.0166% the value between two values.

What Next

Well that was a big one. A lot of information covered. We now have a value that we can control over time, change it based on a curve, AND control over how many seconds it runs.
What we are missing though is Playback Controls. Some way to start and stop an interpolation.
From here on out though you can probably figure that stuff out by yourself. It is not specific to interpolation. It is state management, a very different topic; though for the sake of completion, we will add one more part to this series.
We will have a look at some of the cool things you can do with this new information, where it can help you in designing systems and animating variables.
Let's put together some simple scripts that show some real world examples of how Lerping can make your game better.
Continues in Part 5
Tags:
Jason Storey
Software Developer and Contractor - Programmer
7
Comments