Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Lerp with different speed at different axis of object

Discussion in 'Scripting' started by Ceylan12, Dec 30, 2020.

  1. Ceylan12

    Ceylan12

    Joined:
    Dec 24, 2016
    Posts:
    113
    Hello, I have target position for my camera and currently lerping camera to this position. My goal is lerping it seperetly by axises (car's axises). For example for car's x axis I want to make it more smooth. I tried it with this code but it don't work it just putting camera to target pos. I wrote the code at bottom but it didn't work. How can I solve it? Thank you.
    Code (CSharp):
    1.  
    2. Vector3 localCamera = Car.transform.InverseTransformPoint(wantedPosition);
    3. targetX = Mathf.Lerp(targetX,localCamera.x,Time.fixedDeltaTime*smoothX);
    4. targetZ = Mathf.Lerp(targetZ,localCamera.z,Time.fixedDeltaTime*smoothZ);
    5. Vector3 smoothLocalCamera = new Vector3(targetX,localCamera.y,targetZ);
    6. Vector3 smoothGlobalCamera = Car.transform.TransformPoint(smoothLocalCamera);
    7. transform.position = smoothGlobalCamera;
    8. transform.LookAt(Target.position + lookAtVector,Vector3.up);
    9.  
     
    Last edited: Dec 30, 2020
  2. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    I don't fully understand what you're trying to do, but one thing stands out with your use of Lerp.

    You're passing
    Time.fixedDeltaTime*smoothX
    and
    Time.fixedDeltaTime*smoothZ
    as "t" arguments for Lerp... that doesn't look right to me. When lerping, you want to pass a value between 0 and 1, where 0 yields the first parameter, 1 yields the second, and something in between 0 and 1 yields a value between the two parameters.

    What it looks like you're doing is a common way that Lerp is used incorrectly, where the first parameter you're passing essentially gets fed into the Lerp the next time you call it, and the Lerp slowly approaches the target amount, but not in the expected way. It won't be linear.

    For example, what you're doing with your lerp is essentially the following:

    _someVal = Mathf.Lerp(_someVal, 10, Time.deltaTime);


    If you try running that (with _someVal starting at 0), you'll find that _someVal very quickly increases at first, but then more slowly approaches 10. Theoretically it will never reach 10, except by rounding error. But the graph of the value changes will look more like a square root function or a log function, not a linear change.

    The way to avoid this is to not feed in previous results of Lerp into the next call to Lerp.

    I don't know if that'll help with the problem you're running into, but your current use of Lerp will certain produce some weird results.
     
  3. Ceylan12

    Ceylan12

    Joined:
    Dec 24, 2016
    Posts:
    113
    Thank you for answer maybe I should change it but since there is no spesific point I wrote it like that.
    I think I can explain my question better. I have target position for my camera and currently lerping camera to this position. My goal is lerping it seperetly by axises (car's axises). For example for car's x axis I want to make it more smooth. I tried it with this code but it don't work it just putting camera to target pos. Thank you again for answer.
     
  4. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    Usually when I want to lerp between two positions relative to an object, I'll create some empty game objects as children of the object. I'm imagining your example where the camera moves from being above the left tire to being above the right tire (or something like that), or between various anchor points on the car. For that, I'd create some empty game objects on the car for each of the places the camera can go. Then, your lerp code can look something like this. (I haven't tested this out, it's just a rough example of how you might approach this.)

    Code (CSharp):
    1. public Camera Cam;
    2. public Transform AnchorPoint1;
    3. public Transform AnchorPoint2;
    4.  
    5. private float _lerpT;
    6. private Coroutine _cameraMovementRoutine;
    7. public void MoveFrom1To2()
    8. {
    9.     if (_cameraMovementRoutine != null)
    10.     {
    11.         StopCoroutine(_cameraMovementRoutine);
    12.         _cameraMovementRoutine = null;
    13.     }
    14.     _cameraMovementRoutine = StartCoroutine(PerformCameraMovement(AnchorPoint1, AnchorPoint2));
    15. }
    16.  
    17. public void MoveFrom2To1()
    18. {
    19.     if (_cameraMovementRoutine != null)
    20.     {
    21.         StopCoroutine(_cameraMovementRoutine);
    22.         _cameraMovementRoutine = null;
    23.     }
    24.     _cameraMovementRoutine = StartCoroutine(PerformCameraMovement(AnchorPoint2, AnchorPoint1));
    25. }
    26.  
    27. private IEnumerator PerformCameraMovement(Transform p1, Transform p2)
    28. {
    29.     _lerpT = 0;
    30.     while (_lerpT < 1)
    31.     {
    32.         _lerpT = Mathf.Min(1, _lerpT + Time.deltaTime);
    33.         Cam.transform.position = Vector3.Lerp(p1.position, p2.position, _lerpT);
    34.         yield return null;
    35.     }
    36. }
    To move the camera around, you'd just call either the MoveFrom1To2 or MoveFrom2To1 methods, which would kick off the gradual movement of the camera.

    Another approach entirely would be to just use Cinemachine, which is free, and does lots of really convenience camera stuff without you needing to think about it...
     
  5. Ceylan12

    Ceylan12

    Joined:
    Dec 24, 2016
    Posts:
    113
    Thank you for answer again. I think my problem is a little bit different. Currently I can Lerp my camera to target position to follow car but I should divide this Lerp into axis of my cars and Lerp with different speed but I don't know my code is not working.
     
  6. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    I think you'd need to show me a visual of what you want to have happen. Maybe you can find a video of this happening in some other game, to demonstrate what you want it to look like?
     
  7. Ceylan12

    Ceylan12

    Joined:
    Dec 24, 2016
    Posts:
    113

    The first game is my game and second one is other game. In second game camera is smooth whem going left and right in first one it doesnt look good. In my game I'm using lerp but when I decrease speed of lerp to have this effect it become really slow and while car going fast difference between car and camera is increasing so I have to make it more smooth at only car's x axis. How can I do it? Thank you.
     
  8. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    Well, those honestly look like fairly similar effects, just at either different speeds or easings. If you lerped more slowly (smaller smoothX or smoothZ), I expect you'd see more of the sides of the car as its doing a hard turn, as you do on the second part of the video.


    However, probably the big issue is that you're using Lerp for this, instead of a smoother easing function. Lerp literally means "linear interpolation", which means you'll get a constant rate of change. Notice in the second video, the camera rotation takes a little while to get going, then it turns quite a lot, then it turns more slowly at the end of the turn. Maybe take a look at the easing functions here, and use the raw Lerp output as an input into one of these easing functions. Easing functions exist to give you smoother rates of change over time:

    https://gist.github.com/Fonserbc/3d31a25e87fdaa541ddf
     
  9. Ceylan12

    Ceylan12

    Joined:
    Dec 24, 2016
    Posts:
    113
    Thank you I will check this link. I'm using Vector3.SmoothDamp in my game currently. Should I change this into Mathf.Lerp and use this library? Which one should I use? Also is it possible to use SmoothDamp with ease? Thank you.
     
    Last edited: Dec 31, 2020
  10. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    It sounds like SmoothDamp is already a kind of easing. I wasn't familiar with it, but it sounds like you could use that in place of Lerp and other easing approaches, as long as you like the result. I don't know if there are any caveats to using it, though, and I'd probably personally just use an eased lerp, for flexibility. But it's up to you.

    Somewhat related: Here's a website I like for seeing what easing functions do. It's for web design, and won't give you the C# easing code, but it's nice for visualizing the various common easing functions: https://easings.net/
     
  11. Ceylan12

    Ceylan12

    Joined:
    Dec 24, 2016
    Posts:
    113
    Thank you this site helped me. I tried to add it but since there is no specific start and finish position I think my code is wrong.
    Code (CSharp):
    1. float x=0,y=0,z=0;
    2.         if(wantedPosition.x!=0){
    3.             x = Easing.Exponential.Out(1-(wantedPosition.x-cameraVisual.x)/wantedPosition.x);
    4.         }
    5.         if(wantedPosition.y!=0){
    6.             y = Easing.Exponential.Out(1-(wantedPosition.y-cameraVisual.y)/wantedPosition.y);
    7.         }
    8.         if(wantedPosition.z!=0){
    9.             z = Easing.Exponential.Out(1-(wantedPosition.z-cameraVisual.z)/wantedPosition.z);
    10.         }
    11.      
    12.         cameraVisual = Vector3.Lerp(cameraVisual, wantedPosition, smoothMultiplier);
    13.         transform.position = new Vector3(x*wantedPosition.x,y*wantedPosition.y,z*wantedPosition.z);
    14.  
    Anyway I changed smoothMultiplier depending on the car speed with this code and I think it resolved problem
    Code (CSharp):
    1. transform.position = new Vector3(
    2.                   Mathf.SmoothStep(transform.position.x, wantedPosition.x, smoothMultiplier * Time.deltaTime),
    3.                   Mathf.SmoothStep(transform.position.y, wantedPosition.y, smoothMultiplier * Time.deltaTime),
    4.                   Mathf.SmoothStep(transform.position.z, wantedPosition.z, smoothMultiplier * Time.deltaTime));
    5.  
    I think it is not the best way but I don't know maybe I can do it better. What do you think about it? Thank you.
     
  12. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    I think that if it's good enough for you for now, then I'd probably move on to other things. I usually come back to things later and make changes to my old code as I understand things better, and I think that's usually a good idea .
     
    Ceylan12 likes this.
  13. Ceylan12

    Ceylan12

    Joined:
    Dec 24, 2016
    Posts:
    113
    Thank you I will continue with that for now.