Notifications
Article
Interpolation - Part3
Updated 6 months ago
399
0

Interpolation - Creating Curves

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 1 we discussed what interpolation is and how it works. In Part 2 we had a look at graphing delta changes over time. We looked at curves, but only the theory. It is time to start writing some code and see some of this in action.

Homemade

First we are going to do it all from scratch. Write our own interpolation methods. Write our own curves. Test some interpolation all by ourselves. After that we will turn to unity and see how we can use what unity provides to make our work simpler.
Let's get into It. first we need our Lerp function.
public class LerpTestOne : MonoBehaviour { public float Lerp(float start, float goal, float time) { var difference = goal-start; return start + difference * time; } }
Though to make things more interesting, we want to lerp more than single values. We want to lerp colours and positions. They are usually in the form of Vector3 values though. How do we lerp one of them?
A Vector3 has 3 values; x,y,z. you simply lerp the x's , then separately lerp the y's etc.
Lets add that in:
public Vector3 Lerp(Vector3 a,Vector3 b, float time) { return new Vector3( Lerp(a.x,b.x,time), Lerp(a.y, b.y, time), Lerp(a.z, b.z, time)); }
Let's also add one for Color:
public Color Lerp(Color a, Color b, float time) { return new Color( Lerp(a.r, b.r, time), Lerp(a.g, b.g, time), Lerp(a.b, b.b, time), Lerp(a.a, b.a, time)); }
As you can see, it's basically the same thing. Let's test this. The easiest way to get started is to create a time slider:
[Range(0,1)] public float TimeValue;
In Update all we do is pass TimeValue into our Lerp function.
Here is the complete test script:
public class LerpTestOne : MonoBehaviour { [Range(0,1)] public float TimeValue = 0; public Color A, B; public Color Output; public void Update() { Output = Lerp(A, B, TimeValue); } public float Lerp(float start, float goal, float time) { var difference = goal - start; return start + difference * time; } public Vector3 Lerp(Vector3 a,Vector3 b, float time) { return new Vector3( Lerp(a.x,b.x,time), Lerp(a.y, b.y, time), Lerp(a.z, b.z, time)); } public Color Lerp(Color a, Color b, float time) { return new Color( Lerp(a.r, b.r, time), Lerp(a.g, b.g, time), Lerp(a.b, b.b, time), Lerp(a.a, b.a, time)); } }
Let's see it in action:
Woop! We have our very own lerping class written from scratch. Next up, we need to add some easing. let's start with a very common curve for this. SmoothStep:
public float SmoothStep(float time) { return time * time * (3f - 2f * time); }
We can also give ourselves the option of turning it on or off:
public bool Smooth = false; public void Update() { if(Smooth) Output = Lerp(A, B, SmoothStep(TimeValue)); else Output = Lerp(A, B, TimeValue); } public float SmoothStep(float time) { return time * time * (3f - 2f * time); }
If we set Smooth to true, we wrap TimeValue in the SmoothStep function and smooth it out.
Now that we have ourselves a fully functional Lerp system, we can take a look at tidying it up.

Using Unity

Firstly, our class is over 50 lines long for something relatively simple. Thankfully, unity has a number of these functions built in. Let's remove our own lerp function and replace it with Mathf.Lerp (which as we looked at before, does the same as our lerp function).
The same goes for Vector3.Lerp and Color.Lerp . With those replaced, lets see how our class looks:
public class LerpTestOne : MonoBehaviour { [Range(0,1)] public float TimeValue = 0; public Color A, B; public Color Output; public bool Smooth = false; public void Update() { if(Smooth) Output = Color.Lerp(A, B, SmoothStep(TimeValue)); else Output = Color.Lerp(A, B, TimeValue); } public float SmoothStep(float time) { return time * time * (3f - 2f * time); } }
That is a lot smaller and more concise. It is not very SOLID though. The open closed principle states:
software entities should be open for extension, but closed for modification.
If we want to try out different Lerp functions (ease our TimeValue differently), we need to add to modify this file. Not to mention, after all that talk in Part 2 about curves, it would be nice to get a visual representation of what my easing will look like.

Animation Curves

Despite the terrible name (they are not just useful for animation) , Unity's AnimationCurves give us everything we need to jazz up our interpolation. Let's add one to our script and have have a look:
public class LerpTestOne : MonoBehaviour { [Range(0,1)] public float TimeValue = 0; public Color A, B; public Color Output; public AnimationCurve Curve = AnimationCurve.Linear(0,0,1,1); public void Update() { Output = Color.Lerp(A, B, Curve.Evaluate(TimeValue)); } }
Our class has gotten a lot simpler again. We add a Curve object and set its start time to 0, its start value to 0, its end time to 1 and its... you get the idea.
Now our editor is a lot more fun:
It actually has a built in curve editor!
We don't need to manually define our curves in code. We can just alter the curve points and see what effect it has on our output.
Keeping in mind what we covered in Part 2; we are sampling time across the bottom. Whatever value the line hits on the left is the delta value provided.
Let's try something like this:
Let's see it in action:
Great! Now we have the tools to make some cool curves that control the interpolation values of our game. We can smoothly transition basically any value in our game and even control the exact way that it transitions.

What Next?

So far, I have been leaving one thing out. I have been very insistent that our Time value is between 0 and 1.
What does that mean though? 0 what? 1 what? In the above examples we had to manually slide our interpolation value ourselves. How do we get it to function over a number of seconds?
This next section will get a bit complex as we dive deeper into the concept of framerate, update loops, and what exactly Time.deltaTime actual is.
Continues in Part 4

Jason Storey
Software Developer and Contractor - Programmer
7
Comments