Search Unity

How to remove that smooth at the end of Lerp?

Discussion in 'Scripting' started by GeneralGrant, Jun 26, 2010.

  1. GeneralGrant

    GeneralGrant

    Joined:
    Jun 10, 2010
    Posts:
    977
    Sorry for posting so much. I am working on this script with practically no knowledge, but hey, I have to learn somewhere.


    Well, my script includes forces while using lerp to mimic a missile. But I noticed that Lerp slows down upon reaching its destination. Its inside of lateupdate.
     
    Bamalam69 likes this.
  2. spiralgear

    spiralgear

    Joined:
    Dec 13, 2007
    Posts:
    528
  3. GeneralGrant

    GeneralGrant

    Joined:
    Jun 10, 2010
    Posts:
    977
    Uh, what?
     
    SAMYTHEBIGJUICY likes this.
  4. spiralgear

    spiralgear

    Joined:
    Dec 13, 2007
    Posts:
    528
  5. TakuanDaikon

    TakuanDaikon

    Joined:
    Jun 6, 2010
    Posts:
    268
    While it's true that you should pass a value from 0 to 1 for the time parameter to Lerp, there is no smoothing inherent in either the Lerp function (which means Linear Interpolation) or in Time.deltaTime.

    The most common cause of a smoothing or slowdown happening at the end is when you are using Lerp( currentValue, endValue, time ) rather than Lerp( startValue, endValue, time ), as this causes the range that the Lerp has to work with to be a moving target, and causes progressively smaller updates as currentValue approaches endValue.

    Always interpolate from a start value to the end value, never from the current value to the end value.

    .
     
  6. GeneralGrant

    GeneralGrant

    Joined:
    Jun 10, 2010
    Posts:
    977

    Oh!

    So, how do I do the start value?
     
  7. TakuanDaikon

    TakuanDaikon

    Joined:
    Jun 6, 2010
    Posts:
    268
    Well, that's a very general question, but the idea is that you save the current value in a separate variable at the point that you decide to start interpolating.

    For example, I use interpolation to animate GUI windows with grow/shrink/fade animations.

    Whenever the user 'minimizes' or 'restores' a window, I'll capture the current window bounds in a variable called startBounds. Then I calculate the bounds for a 'minimized' window, and save that in endBounds. Similarly, I save the current alpha.

    Then, during each OnGui call, I'll do something like the following:
    Code (csharp):
    1.  
    2. void OnGUI()
    3. {
    4.  
    5.     // Do animation
    6.     if( isAnimating )
    7.     {
    8.  
    9.         animationTime += Time.deltaTime * animationSpeed;
    10.  
    11.         float newX = Mathf.Lerp( startBounds.x, endBounds.x, animationTime );
    12.         float newY = Mathf.Lerp( startBounds.y, endBounds.y, animationTime );
    13.         float newWidth = Mathf.Lerp( startBounds.width, endBounds.width, animationTime );
    14.         float newHeight = Mathf.Lerp( startBounds.height, endBounds.height, animationTime );
    15.  
    16.         float newAlpha = Mathf.Lerp( startAlpha, endAlpha, animationTime );
    17.  
    18.         skillWindow.Bounds = new Rect( newX, newY, newWidth, newHeight );
    19.         skillWindow.Alpha = newAlpha;
    20.  
    21.         if( animationTime >= 1 )
    22.         {
    23.             isAnimating = false;
    24.         }
    25.  
    26.     }
    27.  
    28.     if( /* User wants to restore the window */ )
    29.     {
    30.  
    31.         // Capture 'current' values as start values
    32.  
    33.         startAlpha = skillWindow.Alpha;
    34.         endAlpha = 1;
    35.         startBounds = skillWindow.Bounds;
    36.         endBounds = new Rect( 25, 25, 480, 600 );
    37.  
    38.         animationTime = 0;
    39.         isAnimating = true;
    40.  
    41.     }
    42.  
    43.     // Do whatever other stuff you need
    44.  
    45. }
    46.  
    Obviously the code above isn't directly usable in another project, but it should give a good general overview of how the process can be done.

    .
     
  8. GeneralGrant

    GeneralGrant

    Joined:
    Jun 10, 2010
    Posts:
    977
    Code (csharp):
    1.  var enemyLocation : Vector3 = enemy.position;
    2.  var check = 0;
    3.  var startLocation;
    4.  if(check == 0){
    5.  startLocation = transform.position;
    6.  check = 1;
    7.  }
    8.  transform.position = Vector3.Lerp(startLocation, enemyLocation, Speed/200);
    there is my script. but it still does that smooth down.
     
  9. TakuanDaikon

    TakuanDaikon

    Joined:
    Jun 6, 2010
    Posts:
    268
    It's doing that smooth down because you don't yet understand what parameter to pass for the third variable. The third variable needs to be a value that progresses from 0 to 1 during the time that you want the animation to happen.

    I don't know what the Speed variable in your code is, but I'm betting it doesn't change, and dividing it by 200 makes it look like you are trying to slow down what would otherwise be an insanely fast movement.

    You need something more like this:
    Code (csharp):
    1. var enemyLocation : Vector3 = enemy.position;
    2. var check = 0;
    3.  
    4. var moveTime = 0.0;
    5. var startLocation;
    6.  
    7. if(check == 0){
    8.     startLocation = transform.position;
    9.     check = 1;
    10.     moveTime = 0.0;
    11. }
    12.  
    13. moveTime += Time.deltaTime * Speed;
    14. transform.position = Vector3.Lerp(startLocation, enemyLocation, moveTime);
    15.  
    Notice that the third parameter - moveTime - starts at 0, then is incremented each frame? Speed in this case could be some value representing how many units per second to move. It's not used directly, but is multiplied by Time.deltaTime and added up over time (in moveTime) to achieve the same speed at all times (faster or slower machines, higher or lower cpu load, etc).

    .
     
  10. GeneralGrant

    GeneralGrant

    Joined:
    Jun 10, 2010
    Posts:
    977
    That code seems to have removed the slow down. Thanks. Well, I divided by 200 because there is a float for the speed. And I want this script to be used by many people so I added a slider. But at 50+, the missile moves insanely fast, so, I divided the speed.
     
  11. GeneralGrant

    GeneralGrant

    Joined:
    Jun 10, 2010
    Posts:
    977
    New question!

    How do I only apply lerp for 2 axis? I want it to move on the x and z, but not the y.
     
  12. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Lerp it and assign the result to a temp vector.
    then transfer over x and z on that temp vector to your real one
     
  13. GeneralGrant

    GeneralGrant

    Joined:
    Jun 10, 2010
    Posts:
    977
    I tried this

    Code (csharp):
    1. tempX = Vector3.Lerp(startLocation, enemyLocation.x, moveTime/2);
    2. tempZ = Vector3.Lerp(startLocation, enemyLocation.z, moveTime/2);
    3. transform.position = tempX;
    4. transform.position = tempZ;

    But that didn't work. Why?
     
  14. TakuanDaikon

    TakuanDaikon

    Joined:
    Jun 6, 2010
    Posts:
    268
    Try this:
    Code (csharp):
    1.  
    2. tempX = Mathf.Lerp( startLocation.x, enemyLocation.x, moveTime/2 );
    3. tempZ = Mathf.Lerp( startLocation.z, enemyLocation.z, moveTime/2 );
    4. transform.position = new Vector3( tempX, 0, tempZ );
    5.  
    Use Mathf.Lerp() to interpolate single floats, Vector.Lerp to interpolate entire vectors.

    .
     
  15. GeneralGrant

    GeneralGrant

    Joined:
    Jun 10, 2010
    Posts:
    977
    Ugh... Now it travels on the x and z but it slows down!


    here is my code:

    Code (csharp):
    1. var hit : RaycastHit;
    2. var enemy : Transform;
    3. var height : int = 500;
    4. var Speed : float= 0.0001;
    5. var SupriseMode = false;
    6. var AirToAirMode = false;
    7. var CruiseMode = true;
    8. var debugMode = false;
    9.  
    10.  
    11.  
    12. function Update  () {
    13.  
    14.      find();
    15.      
    16.      Debug.DrawLine(transform.position, enemy.position, Color.blue);
    17. }
    18. function LateUpdate(){
    19. cruise();
    20.  
    21. }
    22.  
    23. function cruise(){
    24. var enemyFound : boolean = false;
    25. if (Physics.Raycast (transform.position, -Vector3.up, hit, height))
    26.      {
    27.          Debug.DrawLine(transform.position, hit.point, Color.yellow);
    28.          if (hit.collider.gameObject.tag == "MissileEnemy")
    29.          {
    30.              enemyFound = true;
    31.          }
    32.          
    33.    if(enemyFound == false){
    34.          //Fly up, because the enemy is not there. Therfor, it must be the gound.
    35.        
    36.          rigidbody.AddForce (Vector3.up * Speed);
    37.          
    38.          }
    39.          else{
    40.          //ITS THE ENEMY, ATTACK!
    41.              //rigidbody.AddForce(-Vector3.up * 500);
    42.              Debug.DrawLine(transform.position, enemy.position, Color.red);
    43.          }
    44.          
    45.      }
    46. }
    47.  
    48. function find(){
    49. var enemyLocation : Vector3 = enemy.position;
    50. var check = 0;
    51. var tempX;
    52. var tempZ;
    53. var moveTime = 0.0;
    54. var startLocation;
    55.  
    56. if(check == 0){
    57.     startLocation = transform.position;
    58.     check = 1;
    59.     moveTime = 0.0;
    60. }
    61. moveTime += Time.deltaTime * Speed;
    62. tempX = Mathf.Lerp( startLocation.x, enemyLocation.x, moveTime/2 );
    63. tempZ = Mathf.Lerp( startLocation.z, enemyLocation.z, moveTime/2 );
    64. transform.position.x = tempX;
    65. transform.position.z = tempZ;
    66. }
    67.  
     
  16. TakuanDaikon

    TakuanDaikon

    Joined:
    Jun 6, 2010
    Posts:
    268
    Dude, you cannot store the start location, end location, and movement time all in the find() function as local variables. They all get reset each time the function is called, which makes it all essentially useless :)

    .
     
  17. DallonF

    DallonF

    Joined:
    Nov 12, 2009
    Posts:
    620
    Never say never; I constantly take advantage of this effect to smooth out movement. It isn't what the OP is asking for, but Lerping from the current value can be very useful for smooth movement.
     
    glenneroo likes this.
  18. Kevin__h

    Kevin__h

    Joined:
    Nov 16, 2015
    Posts:
    38
    I am using Lerp for rotations, I had the same problem as OP so I did what you said and used a startRotation instead of transform.Rotate but now it just moves a little bit every time I go over the trigger, it's supposed to go 90 degrees at once and now it just does 5 or something like that every time. Do you have any solution for this?

    Here is my script (I'm working in C# but it's almost the same)

    using UnityEngine;
    using System.Collections;

    public class RotateTo : MonoBehaviour {

    public float speed;
    public Vector3 targetRotation;
    public GameObject obj;
    float lerp;
    public GameObject dust;
    public AudioSource[] sounds;
    public AudioSource Trigger;
    public AudioSource Fall;
    public Vector3 startRotation;

    void start () {
    sounds = GetComponents<AudioSource>();
    Trigger = sounds[0];
    Fall = sounds[1];
    }

    void OnTriggerEnter(Collider other)
    {
    Debug.Log ("intrigger");
    if (other.tag == "Player")
    {
    Debug.Log ("intriggerplayer");
    StartCoroutine (DoRotation ());
    Trigger.Play ();
    }

    if (other.name == "Wallclimb")
    {
    GameObject.Instantiate (dust, transform.position, Quaternion.identity);
    Debug.Log ("triggered");
    Fall.Play ();
    }
    }

    IEnumerator DoRotation()
    {
    lerp += Time.deltaTime*speed;
    Mathf.Clamp01 (lerp);
    while (obj.transform.rotation != Quaternion.Euler (targetRotation))
    {
    Debug.Log ("inloop");
    obj.transform.rotation = Quaternion.Lerp (Quaternion.Euler (startRotation), Quaternion.Euler (targetRotation), lerp);
    yield return null;
    }
    }
    }
     
  19. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    Way back when I started I had the exact same thought that Lerp was the greatest thing ever... well, its not. Lerp is great for continuing movement and smoothing to a destination. What you actually want is MoveTowards. Move at a speed and if it would have passed that, then it makes it that.

    In the case of Rotate... RotateTowards. Same difference.
     
    A_Marraff and halley like this.
  20. odinvu

    odinvu

    Joined:
    Jul 25, 2018
    Posts:
    3
    It work for me, thanks

     
  21. ging_Turan

    ging_Turan

    Joined:
    Mar 1, 2021
    Posts:
    1
    A_Marraff likes this.