📜 ⬆️ ⬇️

About using and understanding the Lerp function in Unity3D

Greetings habrovchan. I decided to write an article about one topic that I recently touched on when communicating with familiar people. The topic concerns not so much use as understanding the typical use of this function. Actually, I am not really a programmer, and not a developer, so my opinion is a view, so to speak, of a layman-amateur.

Writing an article is associated with communicating with non-professionals like me and identifying some disagreements about the behavior of a popular piece of code using the Lerp function in different tutorials.

We are interested in the Lerp function in Unity3D. More specifically, the Lerp method of the Vector3D class. However, all the Lerpas in Unity work more or less identically. So, a classic example of using Lerp in Unity, appearing in many tutorials:

... Vector3 destinationPoint; float smoothing; ... void Update() { // ""      transform.position = Vector3.Lerp (transform.position, destinationPoint, smoothing * Time.deltaTime); } 

In theory, in this code, the object to which the script belongs, instead of instantly moving to the destinationPoint point, moves there smoothly. The code is essentially simple. However, there are certain nuances in its simplicity.
')
The first moment occurred when one person, after casting a glance, said that this code linearly interpolates the position of the object from the current one to the destinationPoint .

Actually, the Lerp function is really just linear interpolation. But this is the function itself. But the effect of the code of the above Update method is not so obvious. When applied, it can be seen that the object is moving in the right direction, and along the way it slows down. In the case of a “true” linear interpolation, the object must begin to move, move at a fixed speed, and then abruptly measure. This is exactly what happens if you refer to the Lerp options for using not from tutorials, but from the official script help (specifically, using the Lerp method). But the above code behaves wrong.

The second moment arose when another person said that this should not work at all. The Lerp function must take a parameter (let's call it traditionally t ), which varies from 0 to 1. Accordingly, when zero, the position corresponds to the starting point of the path; with a unit, it is finite. So, when the parameter runs through values ​​from 0 to 1 there is a movement from the starting point to the final one. But after all, in the above code, the parameter t practically does not change! The variable smoothing, which sets the "smoothness" of movement, is fixed. deltaTime varies randomly, but roughly roughly at the same level; for a constant frame rate, it will be constant. Thus, we can assume that the parameter t does not change at all, and therefore the position of the point will not change. And there will be no movement.

Again, reality shows that it is not. The code works, and the object is moved to the right place. Also with a slowdown.

Why it happens? Because the position of the interpolation starting point changes with each update.

Let us assume for simplicity that the frame rate is stable and the product of the smoothing parameter and the frame length is 0.25 (one quarter). Suppose we have to go d from the starting point to the end point:

image

As a result of

 Vector3.Lerp (transform.position, destinationPoint, 0.25); 

get a point at a quarter distance from the beginning. This point becomes the new position of the object, and the next time we call the Update () method, we will be dancing from it. This is the question: why does this still work?

image

The new distance d 'is now smaller (as the object moved up). Therefore, a quarter of this distance will also be less. As a result, the object will move even closer to the destination point, but by a smaller distance.

image

With the next update - the object will pass an even smaller distance.

This is to the question: why use linear interpolation, and get a non-linear motion. The closer an object is to its destination, the less distance it remains to it, but the smaller the step it takes is like an object from Zeno's aporias.

In fact, the object moves to the destination point by inverse-exponential dependence, constantly approaching it, but never reaching. Well, it's from a mathematical point of view. From the practical, it depends on the chosen scale.

This use of the Lerp function definitely has the right to life, but it does not give clarity. People who have heard the phrase “linear interpolation” often assume a different behavior. In addition, there are many interesting pieces that allow you to turn the interpolation from linear to another. They are usually based on changing the parameter t . The trick is that when using this example, all these developments will not behave as expected. I suppose, the developers of Unity3D themselves understand the functioning of such a code, but they do not explain such nuances, apparently not wanting to load with unnecessary (in their opinion) information.

The usual Lerp function and similar ones are used to obtain a series of intermediate values ​​(usually from initial to final). In this code, it is needed to obtain one specific point: each time Update () is called, it finds the value of the point dividing the length of the path in a given relation.

There was also an interesting question that I didn’t quite understand: since the value of the interpolation parameter does not change, why is there a deltaTime at all? Well, actually, the good practice of coding in Unity assumes independence from the frame rate. Of course, with the instability of the frame rate, the difference in the behavior of the code is that with multiplication by Time.deltaTime , which without it is hardly noticeable. But the fact is a fact.

Another question that I already asked myself: why then multiply by Time.deltaTime in the FixedUpdate () method? After all, the developers claim that the time between calls to this method is strictly fixed (almost ... see below). However, in tutorials, a code similar to the above is also found in the FixedUpdate () method (for example, here ).

There may be several options: perhaps leading this trainer, accustomed to this template, simply drove it without thinking. Or, they guaranteed the identity of the results of the code execution in case, for some reason, the frequency of updating the physics (calls to FixedUpdate () ) is changed. Or maybe they just decided not to add the “magic constants”, but at the same time to ensure a certain compatibility (and portability) of the code between the Update () and FixedUpdate () methods, because otherwise they would have to have separate smoothing for the first and second methods.

In general, with these times, the update is also not all smooth. FixedUpdate () has its own fixedDeltaTime variable, which, judging by the name, should give time between its calls ... But no, the developers themselves recommend using deltaTime () and Update () in FixedUpdate () , since the frequency of FixedUpdate () is fixed -fixed, but not very.

One way or another, the result.

The Lerp function is indeed a linear interpolation function. However, the popular pattern of its use is not at all linearly interpolating the movement and rotation of an object. The code is distinguished by a certain brevity, although it causes difficulties when attempting to apply tried and tested techniques for changing the behavior of linear interpolation. At the same time, the effect of this code, as far as I know, is not explained anywhere in the tutorials, leaving many in the wrong as to how it works.

In general, I prefer the SmoothDamp function, which, although it requires the storage of an additional variable, behaves more predictably (allowing, for example, to set the approximate time of “arrival” of an object at a given place).

Thank you all for your attention.

Source: https://habr.com/ru/post/318046/


All Articles