Search Unity

how to detect that Lerp is done interpolating?

Discussion in 'Scripting' started by pretender, Mar 12, 2010.

  1. pretender

    pretender

    Joined:
    Mar 6, 2010
    Posts:
    865
    i need to disable some things until lerp is done with interpolating, how can i detect this?

    currently i have this check that doesnt work
    (i tried to comapare new and old rotational values)


    Code (csharp):
    1.  oldRot=transform.rotation;
    2.  ...
    3.  target = hit.collider.transform;
    4.  newRot=target.rotation;
    5.  ...
    6.  
    7. transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(target.position-transform.position), Time.deltaTime*cameraSpeed);
    8.  
    9. ...
    10.  
    11.  if(newRot==oldRot){
    12.     //do something...
    13.  }
    14.  
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    You're misunderstanding how Lerp works. You don't "detect when Lerp is done"; you call Lerp repeatedly, every frame, and each time you tell it how done it is. The third parameter is a value from 0 to 1. You feed Lerp a variable that counts up to 1, and when that variable is at 1, it's "done".
     
    gnlwnd5084 and stardue like this.
  3. tomvds

    tomvds

    Joined:
    Oct 10, 2008
    Posts:
    1,028
    If you use that particular method of lerping with Time.deltaTime, the end rotation is never reached exactly (mathematically speaking). Every frame the rotation comes a (increasingly smaller) bit closer to the target value, but it never actually arrives.

    It is a matter of deciding within which range the rotation should be of the target to call it done. For example, you could use Mathf.Approximately to compare the individual x,y,z,w properties of the quaternions against eachother.
     
    SanyaBane, shekalo and SparrowGS like this.
  4. pretender

    pretender

    Joined:
    Mar 6, 2010
    Posts:
    865
    ok, thanks both of you...it seems i missed the whole concept and cant yet get it...

    so how to introduce the variable t or how to determine is 1 reached?

    i have this interpolation in my script:
    Code (csharp):
    1. transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(target.position-transform.position), Time.deltaTime*cameraSpeed);
     
  5. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Pseudocode:

    Code (csharp):
    1. var t = 0.0;
    2. while (t < 1.0) {
    3.    t += Time.deltaTime;
    4.    Lerp(start, finish, t);
    5.    yield;
    6. }
    --Eric
     
    Anon1234 likes this.
  6. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    It depends on context. There are two ways Lerp is generally used: in a coroutine, or in Update.
    As a coroutine
    Let's say that, when the level starts, you want a box to slide forward 5 units over the course of 1 second. There's a little piece of code I keep handy for just just a purpose:
    Code (csharp):
    1.  
    2. function Start() {
    3. var duration : float = 1.0;
    4. for (t=0.0; t<duration;t+=Time.deltaTime) {
    5. transform.position = Vector3.Lerp(Vector3(0,0,0), Vector3(0,0,5), t/duration);
    6. yield;
    7. }
    8. // put code to to tell when the lerping action is done
    9. }
    10.  
    What this code does is start at the top, loop through the 'for' loop every frame (the yield instruction, by itself, tells Unity to "wait a frame"), and sets the position of the box somewhere between the first and the second Vector3. How far between is determined by the last parameter - 0.0 means the first vector, 1.0 means the second.
    One caveat (as tomvds pointed out), is that the last run through this loop will NOT set the position to (0,0,5), because the last parameter will be something like .9998234. For that reason, at the end of the loop, it's usually a good idea to manually force-set the final position.

    In Update
    Using Lerp in Update (or OnGUI, FixedUpdate, or any other "every frame" style function) is similar. For "move box from A to B in X seconds", it's not as good of an idea. But it's better for, say, moving a box from A to B based on how much life the player has left.

    Code (csharp):
    1.  
    2. var playerLife : float = 0.5; //50% health
    3. function Update() {
    4. transform.position = Vector3.Lerp ( Vector3(0,0,0), Vector3(5,0,0), playerLife);
    5. }
    6.  
     
  7. melaz

    melaz

    Joined:
    Oct 29, 2013
    Posts:
    2
    "One caveat (as tomvds pointed out), is that the last run through this loop will NOT set the position to (0,0,5), because the last parameter will be something like .9998234. For that reason, at the end of the loop, it's usually a good idea to manually force-set the final position."

    This has proved to be a very useful tip!
     
    SanyaBane likes this.
  8. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    A necropost from the days when I replied to forum posts with Javascript example code.... that is truly impressive!
     
    Harrishun likes this.
  9. youbek123

    youbek123

    Joined:
    Nov 4, 2016
    Posts:
    17
    If you want to check whether that the Obj which is interpolating "reached the target", you can use

    if(Vector3.Distance(startPos, endPos).ToString("0.00") == "0.00"){
    Debug.Log("Target Reached!!!");
    }
     
  10. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    This is absolutely not recommended.
    Your version adds overhead for distance checks, and also generates strings at runtime.

    As other have pointed out long time ago in this very old thread (why do people keep necro-posting?), lerp is based on a value t that you increase over time, and when it reaches 1, you've reached the target (given that the lerp is clamped and prevents overshooting), because that's the math behind it.
     
  11. youbek123

    youbek123

    Joined:
    Nov 4, 2016
    Posts:
    17

    What about checking without generating strings?
    Vector2.Distance(oldMenu.anchoredPosition, targetPoint) < 0.01f
     
  12. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    The thing is, that you don't need to check the distance when you use lerps. You know that you've reached the target as soon as t hits the value 1.
     
  13. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    That depends on how you're using lerp.

    Lerp isn't necessarily a method used over time, though it can be. And how you use it over time effects on if you've reached the target.

    In any given single use of a Lerp you've obviously reached the target if 't' is '1'... but what if you use lerp like this:

    Code (csharp):
    1.  
    2. void Update()
    3. {
    4.     this.transform.position = Vector3.Lerp(this.transform.position, targetPos, 0.5f);
    5. }
    6.  
    This would offer an asymptotic ease toward some target. This might be used if say for instance you had a follow camera that lags behind a little bit.

    How do you know if you've reached 'targetPos' over some duration of time?

    WELL

    First and foremost you're technically in zeno's paradox:
    https://en.wikipedia.org/wiki/Zeno's_paradoxes

    In continuous mathematics (all real numbers are available), you technically would never reach target. Instead only getting infinitely closer to the target with an ever shrinking distance between Achilles and the tortoise.

    BUT we're in computer land and computers are discrete, not continuous. We can only hold numbers of finite size. You'll technically reach the target sooner or later... give or take float error.

    With zeno's paradox given... technically what you'd do instead is check if you're really really close to your target. That the distance between you and the target is exceptionally small within you're desired tolerance.

    In which case, yes, youbek's suggestion would be a valid approach... though I'd use square distance/magnitude to remove the slow sqrt operation.

    With that said though, and to the original threads intent... often times though, if you're pathing over a set amount of time, you can write it as a change over time, and t would = 1 when you're at the goal.

    But that's not ALWAYS the case when using lerp.

    It really depends on the intent.
     
  14. youbek123

    youbek123

    Joined:
    Nov 4, 2016
    Posts:
    17

    Yeah, you right.
    i am using smoothstep formula for my t to increase t = t*t * (3f - 2f*t); So if my condition will be something like t == 1 then to evaluate the consequence, it takes huge amount of time. I think it is because, that t by coming to end slows down.

    So I am checking using distance, if you have any suggestions please give. I'll really appreciate that!

    NOTE: Also i am lerping in update, i am not using any coroutines.
     
  15. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    That's all true, it can be used to achieve lots of different effects, and there's probably no rule that dictates how it must be used.

    However, if someone told me to implement let's say Zeno's paradox using that lerp function, I'd simply keep start & end the same, and adjust t instead. This still allows to iteratively approximate the value of 1 and quit when it's within desired tolerance.

    It's a matter of perspective and probably comes down to personal preference though.

    Anyway, we've all seen the various different uses of lerps, and every time I see a new script that uses it differently, the first question that comes to my mind is whether this is intended and behaves as expected, or is just build upon that attitude "i've seen people doing it just like that". It's not necessarily wrong, but causes confusion in my opinion.

    In contrast, when someone modifies t instead for common use cases, it kind of suggests to me that the person is aware of what's going on.
     
  16. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    I think you missed what I was referencing with zeno's paradox.

    I wasn't talking about implementing zeno's paradox. But that the logical foundation of checking if iterative lerps of the same scale (0.5 in this case) technically wouldn't get you to the goal BECAUSE of zeno's paradox.

    If you wanted to implement zeno's paradox... well you'd do the very thing I just did. You wouldn't simply keep a start & end and adjust t... because then it wouldn't be zeno's paradox. You'd be able to reach the goal.

    Unless you just halved t -1... in which case you just moved the job off one to the other. It's the same thing.

    I get what you're getting at.

    You're saying that seeing people use Lerp not by manipulating t is a code smell that raises the concern the person hasn't actually considered what they're doing.

    But there in was the point of my post.

    Just because that may be a code smell to you. It's not actually true in all cases.

    And that checking the distance may be necessary if the coder DID intend to do it the other way around. Because the other way around isn't a wrong usage of lerp... even if to you it's a code smell. Case in point, the code those people are mimicing is legitimate code. And in that legitimate code scenario, how do you tell if you've reached the target???

    Well, you check if the distance is near.
     
    Suddoha likes this.
  17. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    I'm aware of all that, I think I didn't really miss it. That's the reason why I picked it up and I was also talking about t iteratively approximating 1 to get the job done, as an alternative to changing the start position (in the end it's the example you came up with, I only picked it up).

    Well, it's correct that it just moves the problem, but my point was that it can still be written in a way in which you can wait for t to get as close to 1 as you desire.

    I never said I'd leave t constant, I said I'd adjust it instead. Perhaps it's my wording (adjust in particular?), apologies for that.

    So I meant something like

    which is true, but conforms to the idea of having t move towards 1.

    Well, I did not say it's a code smell, nor did I intend to label it like that.
    That's too negative, and it wouldn't be a code smell if it's implemented just like that on purpose.

    My point was, depending on whom you're working with, it may raise attention and questions. I've been working with lot's of students that just wanted to get the job done, if you were curious and asked why they had chosen to do it in a specific way, well, the answers weren't of technical nature, but they had just seen it somewhere. They didn't really care whether or not it absoutely meets the requirements.

    In a more professional environment, I wouldn't want to question these things. I'd expect that they're aware of how their code works. If they choose to change param 1 or 2, and leave t, well, that's just fine.

    Absolutely right. I didn't mean to say it's wrong, just that you could do it in a different way. And for common cases, you can usually avoid distance checks (and also srqMagnitudes as the cheaper an alternative) when you work with t instead.
     
    Last edited: Feb 28, 2019