Search Unity

Not Understanding Lerp and Slerp

Discussion in 'Scripting' started by Nigey, Oct 28, 2013.

  1. Nigey

    Nigey

    Joined:
    Sep 29, 2013
    Posts:
    1,129
    Trying to get Lerp and Slerp to handle bringing the position and rotation of an object slowly back to it's original saved position after being knocked... It's not working.

    Code (csharp):
    1.  
    2.     Vector3 savedPos, savedRot;
    3.    
    4.     // Use this for initialization
    5.     void Start ()
    6.     {
    7.         // Setting the original position.
    8.         savedPos = transform.position;
    9.        
    10.         savedRot = transform.eulerAngles;
    11.     }
    12.  
    13.     void FixedUpdate()
    14.     {
    15.         if(moonTapped > 0)
    16.         {
    17.             moonTapped -= Time.deltaTime;
    18.             return;
    19.         }
    20.        
    21.         if(savedPos != transform.position)
    22.         {
    23.             Vector3 currPos = transform.position;
    24.            
    25.             transform.position = Vector3.Lerp(currPos, savedPos, Time.deltaTime);
    26.         }
    27.        
    28.         if(savedRot != transform.eulerAngles)
    29.         {
    30.             Vector3 newRot = Vector3.Slerp(transform.eulerAngles, savedRot, Time.deltaTime);
    31.            
    32.             Quaternion rotation = Quaternion.Euler(newRot);
    33.            
    34.             transform.rotation = rotation;
    35.         }
    36.     }
    37.  
    They just stop.. The rotations jerk around repeatedly and the position one just 'stops', and doesn't go back to the saved position.

    Can anyone explain?
     
  2. Patico

    Patico

    Joined:
    May 21, 2013
    Posts:
    886
    Everything looks good, but I don't like that piece of code with 'moonTapped', try to comment it and run again.

    You can also use Quaternion.Slerp instead of Vector3.Slerp for 'savedRot' valiable, it makes you code shorter:

    Code (csharp):
    1.  
    2. Vector3 savedPos;
    3. Quaternion savedRot;
    4.  
    5.     void Start ()
    6.     {
    7.         // Setting the original position.
    8.         savedPos = transform.position;
    9.         savedRot = transform.rotation;
    10.     }
    11.    
    12. void FixedUpdate()
    13.     {
    14.         /* possible this value is too high or is increasing somewhere at another place
    15.         if(moonTapped > 0)
    16.         {
    17.             moonTapped -= Time.deltaTime;
    18.             return;
    19.         }*/
    20.  
    21.         if(savedPos != transform.position)
    22.         {
    23.             transform.position = Vector3.Lerp(transform.position, savedPos, Time.deltaTime);
    24.         }    
    25.        
    26.         if(savedRot != transform.rotation)
    27.         {
    28.             transform.rotation = Quaternion.Slerp(transform.rotation, savedRot, Time.deltaTime);
    29.         }
    30. }
    31.  
    Good luck! :rolleyes:
     
    Last edited: Oct 28, 2013
  3. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    Don't put Time.deltaTime as the interpolation factor. I know that there's a lot of people around saying that's how to use them, but it's bad advice from people who don't actually understand what they're talking about.

    From another time I explained the same thing:
     
    Last edited: Oct 28, 2013
  4. Kirlim

    Kirlim

    Joined:
    Aug 6, 2012
    Posts:
    126
    Time actually is a very misleading name for the lerp factor parameter in the lerp functions. Once I had to explain for 30 minutes that the "time" parameter can be called factor, lerp factor, percentage, banana. Anyhow, I'll leave this for people who will understand it easier with math

    Code (csharp):
    1.  
    2. time = clamp(time, 0, 1);
    3. result = ((1 - time) * Input1) + (time * Input2);
    4.  
    Other way of saying, is that time is in lerp... uhm... space. So for example, instead of using time, you'll actually use (currentLerpTimeElapsed / totalLerpDuration) as your 'time'.
     
  5. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    That's a really good point, calling it "time" is pretty confusing. At the very least it should be considered as a noralized time, because that's something that people can grasp pretty easily.
     
    Last edited: Oct 29, 2013
  6. rutter

    rutter

    Joined:
    Mar 21, 2012
    Posts:
    84
    I usually just explain the lerp parameter as a percentage. Given a t from 0 to 1, you'll get a result that is t percent between a and b.

    If you want a value that changes over time, t needs to change over time.

    Like so:

    Code (csharp):
    1.  
    2.  
    3. public float min = 0f;
    4. public float max = 100f;
    5.  
    6. public float lerpTime = 1f;
    7. float currentLerpTime = lerpTime + 1f;
    8.  
    9. public void StartLerping() {
    10.     currentLerpTime = 0f;
    11. }
    12.  
    13. void Start() {
    14.     StartLerping();
    15. }
    16.  
    17. void Update() {
    18.     currentLerpTime += Time.deltaTime;
    19.     if (currentLerpTime <= lerpTime) {
    20.         float perc = currentLerpTime / lerpTime;
    21.         float current = Mathf.Lerp(min, max, perc);
    22.         Debug.Log("current: " + current);
    23.     } else {
    24.         Debug.Log("finished");
    25.     }
    26. }
    27.  
    You could just as easily vary t by any other parameter, though. What if you want some light's brightness to lerp as it moves? You could vary t based on its position along the world's x-axis, either as a range between two values or as a sine wave as it travels.
     
  7. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    Succinct and clear. I like it. :)
     
  8. Nigey

    Nigey

    Joined:
    Sep 29, 2013
    Posts:
    1,129
    Hi guys,

    Thanks for all your replies. I've now listened to everything you've said and tried re-doing my mode. The position one works perfectly. I have an issue with my rotation one however. Let me show you.

    Code (csharp):
    1.  
    2. public class PlayerScript : MonoBehaviour {
    3.    
    4.     int playerHealth = 100;
    5.     float moonTapped, reposStart, furthestDist, furthestRot, reposSpeed = 2;
    6.     Vector3 savedPos, savedRot;
    7.    
    8.     // Use this for initialization
    9.     void Start ()
    10.     {
    11.         // Setting the Civilisation's original position.
    12.         savedPos = transform.position;
    13.        
    14.         savedRot = transform.eulerAngles;
    15.     }
    16.  
    17.         // Passed health lost from the magnitude of the velocity from the moon
    18.         playerHealth -= healthLost;
    19.        
    20.         // gives a delay before re-aligning the civilisation's position, and sets the start time for reposition as well.
    21.         reposStart = Time.time;
    22.         moonTapped = 1.2f;
    23.  
    24.     // This puts the civilisation's back in their nuetral position after being hit..
    25.     void FixedUpdate()
    26.     {
    27.         // Gives the Civilsations a delay before they reposition
    28.         if(moonTapped > 0)
    29.         {
    30.             // If timer's still higher than requirement, minus time from it.
    31.             moonTapped -= Time.deltaTime;
    32.            
    33.             // Gets the furthest distance/rotation travelled before the delay expires.
    34.             furthestDist = Vector3.Distance(savedPos, transform.position);
    35.             furthestRot = Vector3.Dot(savedRot, transform.eulerAngles);
    36.            
    37.             // Don't let it recalibrate if not ready. Return that S***.
    38.             return;
    39.         }
    40.        
    41.         // Takes the time travelled divided by the total journey left, to get the fraction of the journey travelled.
    42.         float timePosCovered = (Time.time - reposStart) * reposSpeed;
    43.         float timeRotCovered = (Time.time - reposStart) * (reposSpeed + 5);
    44.        
    45.         float fractureDistJourney = timePosCovered / furthestDist;
    46.         float fractureRotJourney = timeRotCovered / furthestRot;
    47.        
    48.         // Repositions the well.. position.
    49.         if(savedPos != transform.position)
    50.         {
    51.             Vector3 currPos = transform.position;
    52.            
    53.             transform.position = Vector3.Lerp(currPos, savedPos, fractureDistJourney);
    54.         }
    55.        
    56.         // Repositions the rotation.
    57.         if(savedRot != transform.eulerAngles)
    58.         {
    59.             Vector3 newRot = Vector3.Slerp(transform.eulerAngles, savedRot, fractureRotJourney);
    60.            
    61.             Quaternion rotation = Quaternion.Euler(newRot);
    62.            
    63.             transform.rotation = rotation;
    64.         }
    65.     }
    66.  
    The rotation does a 'full circle' when hit.. and doesn't go to it's original rotation by the quickest route. Sometimes spinning three times.

    What is going on?