Notifications
Article
Interpolation - Part3
Updated 2 days ago
60
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 and looked at curves, but up until now we have only really been discussing the theory. It is time to start writing some code and seeing some of this in action.

Homemade

First, we are going to do it all from scratch, write our out interpolation methods, write our own curves, and 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, there are usually in the form of Vector3 values though, how do you lerp one of them?
Well 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)); }
Lets 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, basically the same thing, only with the addition of another lerp for the alpha. So lets test this. The easiest way to get started is to create a time slider:
[Range(0,1)] public float TimeValue;
then in update all we do is pass time into our Lerp. So the completed test script should look like:
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. So lets start with a very common curve for this. smoothstep:
public float SmoothStep(float time) { return time * time * (3f - 2f * time); }
Let's add that and 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); }
So if we check smooth, we simply wrap time in the smoothstep function and ... smooth it out.
Now 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, lets 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 . So 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 still has one problem I don't like. For every additional curve I want to try out, I have to add a new easing function and change the code.
Not to mention, after all that talk in part2 about curves, it would be nice to get a visual representation of what my easing will look like.

Animation Curves

So now we can finally talk about animation curves! this is the fun part. Despite the terrible name (they are not just useful for animation) , Unity's AnimationCurves give us everything we need to jazz up our interpolation. Lets 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)); } }
Ok our class has gotten a lot simpler again. we add a Curve object and set its start time to 0, and its start value to 0, its end time to 1 and its... you get the idea.
now though our editor is a lot more fun:
It actually has a built in curve editor!
Now we don't need to manually define our curves in code. we can just alter the 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, and whatever value the line hits on the left is the delta value provided. so you should be able to visualize some cool and crazy curves.
Lets 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?

Well, so far I have been leaving one thing out. I have been very insistent that our Time value is a value between 0 and 1.
What does that mean though? 0 what? 1 what? In the above examples we have had to manually slide our interpolation 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; how we can use it to not only interpolate over time, but make sure that interpolation is framerate independent.
Continues in Part 4

Jason Storey
Software Developer and Contractor - Programmer
4
Comments