Search Unity

How to smooth damp towards a moving target without causing jitter in the movement?

Discussion in 'Scripting' started by cecarlsen, Apr 5, 2012.

  1. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    Dear forum

    The title says it all. This should be really simple, but it's killing me.

    Put the script below on a game object in an empty scene and it will generate an example of to moving cubes, a target and a follower. The follower on the left side of the screen is jittering. Why? Mind you this is only visible when the speed is quite high.

    ~ce


    Code (csharp):
    1. using UnityEngine;
    2.  
    3. public class SnakesFollowTest : MonoBehaviour
    4. {
    5.     Transform targetTransform;
    6.     Transform followerTransform;
    7.     Transform camTransform;
    8.    
    9.     Vector3 followerVelocity;
    10.    
    11.     void Start()
    12.     {
    13.         camTransform = Camera.main.transform;
    14.         targetTransform = GameObject.CreatePrimitive( PrimitiveType.Cube ).transform;
    15.         followerTransform = GameObject.CreatePrimitive( PrimitiveType.Cube ).transform;
    16.         targetTransform.name = "target";
    17.         followerTransform.name = "follower";
    18.     }
    19.    
    20.     void Update()
    21.     {
    22.         // move target //
    23.         targetTransform.position += Vector3.right * Time.deltaTime * 200;
    24.        
    25.         // move follower //
    26.         followerTransform.position = Vector3.SmoothDamp( followerTransform.position, targetTransform.position, ref followerVelocity, 0.05f );
    27.        
    28.         // move camera along side the target //
    29.         camTransform.position = new Vector3( targetTransform.position.x, camTransform.position.y, camTransform.position.z );
    30.     }
    31. }
     
    valentin56610 and IgorAherne like this.
  2. MADmarine

    MADmarine

    Joined:
    Aug 31, 2010
    Posts:
    627
    Have you tried using something like Vector3.Lerp instead?
     
  3. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    Yes. Same S*** unfortunately. You can replace line 26 with the line below and the jitter remains.

    Code (csharp):
    1. followerTransform.position = Vector3.Lerp( followerTransform.position, targetTransform.position, Time.deltaTime * 20 );
     
    valentin56610 and IgorAherne like this.
  4. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    You shouldn't pass a multiple of Time.deltaTime into Lerp - it's not a linear function. But you should pass Time.deltaTime into SmoothDamp, as far as I can tell - it is asking for a time delta. Whether it applies it correctly is another matter, I've never used the function.

    If you want to use Lerp, you probably want to pass 1 - Mathf.Exp(-k * Time.deltaTime) or something like that, varying k to change the lerp rate. Bear in mind that it will give a quite different behaviour.

    These functions will both have trouble tracking a moving target though - the follower will lag behind more and more as the target velocity increases. You can write better functions to make the follower not lag behind the target point even when the target is moving with constant speed, which might be better for your purposes or not.
     
    snorulf, CrandellWS and Westland like this.
  5. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    Thanks for giving it a shot George!

    SmoothDamp applies Time.deltaTime by default, so it makes no difference passing it as argument. I tried it.

    It also produces jitter. Try switching line 26 with the line below to test it yourself.

    Code (csharp):
    1. followerTransform.position = Vector3.Lerp( followerTransform.position, targetTransform.position, 1 - Mathf.Exp( -20 * Time.deltaTime ) );
    That's ok, I only want to avoid the jitter.

    The target will need move at a varying speed. It is moving at a constant speed in the example to make the problem more obvious/visible.

    What is the best practice for solving this kind of problem?
     
  6. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    The easiest solution is to just do it all in FixedUpdate. It's still worth correcting for the deltaTime, in case you change your update rate in the future, but you won't need to be quite so careful about it.

    I think the problem with your case, though, is that although the lerp with exponentiation is correct for interpolating towards a fixed target, your target is moving, and the lerp is based on the fully-integrated target position, when it should be based on a continuous integration of the motion during the timeslice.

    So I guess you have three options:

    1) Do it in FixedUpdate instead
    2) Use a more linear following algorithm - which I would expect to show fewer artifacts
    3) Write the lerp as a differential equation and solve it properly

    (3) might be overkill - (2) is usually simpler - but I wanted to convince myself that (3) does work in this case, so I did the maths, getting this:

    Code (csharp):
    1.  
    2.     Vector3 SuperSmoothLerp(Vector3 x0, Vector3 y0, Vector3 yt, float t, float k)
    3.     {
    4.         Vector3 f = x0 - y0 + (yt - y0) / (k * t);
    5.         return yt - (yt - y0) / (k*t) + f * Mathf.Exp(-k*t);
    6.     }
    7.  
    x0 is the follower's old position, y0 is the target's old position, yt is the target's new position, t is the elapsed time, and k is the lerp rate, as in (1 - Mathf.Exp(-k * Time.deltaTime)) before. You used 20 for that. The return value is the follower's new position. So you call it much like Vector3.Lerp, except you pass the target's old and new positions, rather than just its new position.

    The maths assumes that the target is moving with constant velocity over the time slice, so if the target is changing velocity rapidly as well it's still going to jitter a bit. But in any case it should be a lot more smooth than plain Lerp was, and other than being smooth, it has exactly the same behaviour (e.g. response to different k values, following distance, etc).
     
  7. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    Thank's again George, I appreciate the effort =)

    In that case I'm not sure I explained myself clearly enough to begin with. I want the follower to move towards the target at high speed with it's far away and gradually slower as it approaches. The follower should only be able to reach the target when the target stands still. This is practically what the code I posted at first does, but there is jitter in the movement.

    The SuperSmoothLerp function reaches the target while the target is moving. Pretty cool, but it's not exactly the problem I needed to solve.

    Both Lerp, SmoothDamp and (even) SuperSmoothLerp causes visible jitter in the movement of the follower. Run the example below to test this.

    I'm still not sure how to get this right.

    ~ce


    Code (csharp):
    1. using UnityEngine;
    2.  
    3. public class SnakesFollowTest : MonoBehaviour
    4. {
    5.     Transform targetTransform;
    6.     Transform followerTransform;
    7.     Transform camTransform;
    8.    
    9.     //Vector3 followerVelocity;
    10.     Vector3 pastFollowerPosition, pastTargetPosition;
    11.    
    12.     void Start()
    13.     {
    14.         camTransform = Camera.main.transform;
    15.         targetTransform = GameObject.CreatePrimitive( PrimitiveType.Cube ).transform;
    16.         followerTransform = GameObject.CreatePrimitive( PrimitiveType.Cube ).transform;
    17.         targetTransform.name = "target";
    18.         followerTransform.name = "follower";
    19.     }
    20.    
    21.    
    22.     void Update()
    23.     {
    24.         // move target //
    25.         targetTransform.position += Vector3.right * Time.deltaTime * 200;
    26.        
    27.         // move follower //
    28.         followerTransform.position = SuperSmoothLerp( pastFollowerPosition, pastTargetPosition, targetTransform.position, Time.time, 0.5f );
    29.         pastFollowerPosition = followerTransform.position;
    30.         pastTargetPosition = targetTransform.position;
    31.        
    32.         // move camera along side the target //
    33.         camTransform.position = new Vector3( targetTransform.position.x, camTransform.position.y, camTransform.position.z );
    34.     }
    35.    
    36.    
    37.     Vector3 SuperSmoothLerp( Vector3 pastPosition, Vector3 pastTargetPosition, Vector3 targetPosition, float time, float speed )
    38.     {
    39.         Vector3 f = pastPosition - pastTargetPosition + (targetPosition - pastTargetPosition) / (speed * time);
    40.         return targetPosition - (targetPosition - pastTargetPosition) / (speed*time) + f * Mathf.Exp(-speed*time);
    41.     }
    42.    
    43. }
     
    IgorAherne likes this.
  8. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    As I said, if you do it all in FixedUpdate, all the jitter will go away.

    Otherwise, I think the problem in your usage of SuperSmoothLerp is that you're passing in Time.time instead of Time.deltaTime. For me, it's very smooth indeed.

    Here's a webplayer demo, the code I used to test it - based on your original code:

    http://www.gfootweb.webspace.virginmedia.com/SmoothDamp/WebPlayer.html

    You can choose from a few different movement profiles; "Fast" is 200m/s and "Slow" is 100m/s). The bottom cube is following using my function; the other two are using Vector3.Lerp with either linear (centre) or exponential (top) response to changes in the deltaTime.
     
  9. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    I have heard it's bad practise to overload the fixed update function so I want to avoid that.

    I tried using delta time as well, but I still get jitter.

    However it DOES work in your web player example. Can you post the code? I must be doing something wrong.

    Thanks again.
     
  10. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    My code has got kind of long... but if I take the code you just posted and change "Time.time" to "Time.deltaTime", and "0.5f" to "20", it works just like the bottom cube in my web player.
     
  11. cjow

    cjow

    Joined:
    Feb 29, 2012
    Posts:
    132
    You could also try using Time.smoothDeltaTime instead of Time.deltaTime. Explanation here.
     
    keiththewalker likes this.
  12. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    It works! George thank you for this, you totally saved my day!

    That does not solve the problem, but thanks for sharing.

    Here is the final example for the sake of archiving.

    Yeah!


    Code (csharp):
    1. using UnityEngine;
    2.  
    3. public class SnakesFollowTest : MonoBehaviour
    4. {
    5.     Transform targetTransform;
    6.     Transform followerTransform;
    7.     Transform camTransform;
    8.     Vector3 pastFollowerPosition, pastTargetPosition;
    9.    
    10.     void Start()
    11.     {
    12.         camTransform = Camera.main.transform;
    13.         targetTransform = GameObject.CreatePrimitive( PrimitiveType.Cube ).transform;
    14.         followerTransform = GameObject.CreatePrimitive( PrimitiveType.Cube ).transform;
    15.         targetTransform.name = "target";
    16.         followerTransform.name = "follower";
    17.     }
    18.    
    19.     void Update()
    20.     {
    21.         // move target //
    22.         targetTransform.position += Vector3.right * Time.deltaTime * 200;
    23.        
    24.         // move follower //
    25.         followerTransform.position = SmoothApproach( pastFollowerPosition, pastTargetPosition, targetTransform.position, 20f );
    26.         pastFollowerPosition = followerTransform.position;
    27.         pastTargetPosition = targetTransform.position;
    28.  
    29.         // move camera along side the target //
    30.         camTransform.position = new Vector3( targetTransform.position.x, targetTransform.position.y, targetTransform.position.z - 15 );
    31.     }
    32.    
    33.     Vector3 SmoothApproach( Vector3 pastPosition, Vector3 pastTargetPosition, Vector3 targetPosition, float speed )
    34.     {
    35.         float t = Time.deltaTime * speed;
    36.         Vector3 v = ( targetPosition - pastTargetPosition ) / t;
    37.         Vector3 f = pastPosition - pastTargetPosition + v;
    38.         return targetPosition - v + f * Mathf.Exp( -t );
    39.     }
    40. }
     
    iagofonteles and twobob like this.
  13. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    Sooo. Now I have encountered the same problem only with rotations. When I lerp towards a target rotation at high speeds I get jitter in the movement. I just don't have the math smarts to make the SuperSmoothLerp differential equation for quaternions.

    I made an example showing the problem. Put the script on a game object in an empty scene and the problem should be obvious. The small box is the target and big is the follower.

    Anyone able to guide me or write the SuperSmoothLerp function for quaternions?

    ~ce


    Code (csharp):
    1. using UnityEngine;
    2.  
    3. public class RotationFollowTest : MonoBehaviour
    4. {
    5.     Transform targetTransform;
    6.     Transform followerTransform;
    7.     Transform camTransform;
    8.    
    9.     void Start()
    10.     {
    11.         camTransform = Camera.main.transform;
    12.         camTransform.position = new Vector3( 0, 0, -2 );
    13.         targetTransform = GameObject.CreatePrimitive( PrimitiveType.Cube ).transform;
    14.         followerTransform = GameObject.CreatePrimitive( PrimitiveType.Cube ).transform;
    15.         targetTransform.name = "target";
    16.         followerTransform.name = "follower";
    17.         followerTransform.Translate( 0, 0, 2 );
    18.         followerTransform.localScale = new Vector3( 2, 2, 2 );
    19.         (new GameObject()).AddComponent<Light>();
    20.     }
    21.    
    22.     void Update()
    23.     {
    24.         // rotate target //
    25.         targetTransform.Rotate( 0, 0, Time.deltaTime * 1000 );
    26.        
    27.         // move followers rotation toward targets rotation //
    28.         followerTransform.rotation = Quaternion.Lerp( followerTransform.rotation, targetTransform.rotation, Time.deltaTime * 20 );
    29.        
    30.         // move cameras rotate to targets rotation //
    31.         camTransform.rotation = targetTransform.rotation;
    32.     }
    33. }
     
  14. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    There are lots of problems with this. The first is that you're going to run into Nyquist-style sampling issues - you're spinning the cube at 1000 rotations per second, but only running your simulation at maybe 60Hz. Anything that's based on observing the orientation of the cube at 60Hz intervals will never be able to tell exactly how fast it is spinning. You could feed the actual angular velocity vector into the lerp function though to get around that. It's still hard to solve.

    If your rotations will be limited to one dimension then you could do the whole thing using angles instead. For that you need to change the vectors to floats, and again you need to keep track of (or at least think about) whether the target object has fully rotated, and whether you want the follower to have to spin the same number of times to keep up, or whether it's OK for it to catch up next time around. A lot of this depends on your game.
     
  15. Chris-Clark

    Chris-Clark

    Joined:
    Jan 16, 2012
    Posts:
    130
    I know you said earlier you wanted to keep things out of the FixedUpdate() because you heard it was bad to put too much in there. But sometimes it is the right solution. If putting these functions in the fixed update works, maybe you should do that?
     
  16. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    It's not 1000 cycles per second, it's 1000 degrees which means 1000 / 360 = 2.77 hz.

    In the example above it looks like the follower is doing a pretty good job apart from a bit of jitter, which in my case unfortunately means everything. Even when I turn down the rotation speed to 90 degrees per second (0.25hz) I can still see some minor jitter when I go fullscreen.

    I'm not saying it's an easy problem to solve.

    I wish that was the case.

    I'd like to keep it flexible, say, for example be able to run the code in a coroutine.

    ~ce
     
    Last edited: Apr 7, 2012
  17. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
  18. Frank Horrigan

    Frank Horrigan

    Joined:
    Apr 10, 2012
    Posts:
    3
    If you really want to do this the correct way then check out http://www.gamasutra.com/view/feature/3278/rotating_objects_using_quaternions.php?page=2 figure 11. If you read the short section there, you will notice the method of adding angular velocity to a quaternion. I believe this must be done if you want to avoid FixedUpdate().

    One other thing to note, if you place your slerp or lerp call before rotating your target, you should at least reduce the frequency of jitters. I know it's not the same, but in a pinch it might work for you.
     
  19. carmine

    carmine

    Joined:
    Jan 4, 2012
    Posts:
    394

    Did you figure this out? I'm having the EXACT same problem and it's making me insane, I've spent my whole day working on this one thing and I'm still where I was this morning.
     
    valentin56610 likes this.
  20. ASMach

    ASMach

    Joined:
    Nov 26, 2011
    Posts:
    43
    I ran into similar issues with the standard SmoothFollow.js script, so I checked this thread and made a new version that works even at high speeds. All I had to do is replace Time.deltaTime with (1 - Mathf.Exp( -20 * Time.deltaTime )), as shown below:

    Code (csharp):
    1.  
    2. /*
    3. This camera smoothes out rotation around the y-axis and height.
    4. Horizontal Distance to the target is always fixed.
    5.  
    6. There are many different ways to smooth the rotation but doing it this way gives you a lot of control over how the camera behaves.
    7.  
    8. For every of those smoothed values we calculate the wanted value and the current value.
    9. Then we smooth it using the Lerp function.
    10. Then we apply the smoothed values to the transform's position.
    11. */
    12.  
    13. // The target we are following
    14. var target : Transform;
    15. // The distance in the x-z plane to the target
    16. var distance = 4.0;
    17. // the height we want the camera to be above the target
    18. var height = 1.0;
    19. // How much we
    20. var heightDamping = 25.0;
    21. var rotationDamping = 35.0;
    22.  
    23. // Place the script in the Camera-Control group in the component menu
    24. @script AddComponentMenu("Camera-Control/Smooth Follow")
    25.  
    26. function Start ()
    27. {
    28.     // Early out if we don't have a target
    29.     if (!target)
    30.         return;
    31.        
    32.     transform.position = target.position;
    33. }
    34.  
    35. function LateUpdate () {
    36.     // Early out if we don't have a target
    37.     if (!target)
    38.         return;
    39.    
    40.     // Calculate the current rotation angles
    41.     var wantedRotationAngle = target.eulerAngles.y;
    42.     var wantedHeight = target.position.y + height;
    43.        
    44.     var currentRotationAngle = transform.eulerAngles.y;
    45.     var currentHeight = transform.position.y;
    46.    
    47.     // Damp the rotation around the y-axis
    48.     currentRotationAngle = Mathf.LerpAngle (currentRotationAngle, wantedRotationAngle, rotationDamping * (1 - Mathf.Exp( -20 * Time.deltaTime )));
    49.  
    50.     // Damp the height
    51.     currentHeight = Mathf.Lerp (currentHeight, wantedHeight, heightDamping * (1 - Mathf.Exp( -20 * Time.deltaTime )));
    52.  
    53.     // Convert the angle into a rotation
    54.     var currentRotation = Quaternion.Euler (0, currentRotationAngle, 0);
    55.    
    56.     // Set the position of the camera on the x-z plane to:
    57.     // distance meters behind the target
    58.     transform.position = target.position;
    59.     transform.position -= currentRotation * Vector3.forward * distance;
    60.    
    61.     // Set the rotation
    62.     transform.rotation.z = target.rotation.z;
    63.  
    64.     // Set the height of the camera
    65.     transform.position.y = currentHeight;
    66.    
    67.     // Always look at the target
    68.     transform.LookAt (target);
    69. }
    70.  
    The issue that I was having until I looked at this thread and edited SmoothFollow.js to look like the above is that I was having distracting, headache-inducing jitters in a game that involves flying around at high speeds, with the rotation and height damping set high enough to meaningfully follow the player. With the above edits, I've now made everything nice and smooth. Thanks for the help guys!
     
  21. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    Thanks for sharing. I need a smooth lerp function for quaternions though. The script above is restricted to angular movement around the z and y axis.
     
  22. z37

    z37

    Joined:
    Feb 13, 2014
    Posts:
    29
    Really nice thread!
    I am trying to implement this supersmooth lerp method in order to make an object or a camera move smoothly by itself, because jittering appears in this case too.
    I am not super fast at math, so I would appreciate if someone could help me.
     
    valentin56610 likes this.
  23. ZyntharNOR

    ZyntharNOR

    Joined:
    Sep 20, 2013
    Posts:
    16
    This thread was excellent help! Thank you Carl & George! I used it for smoothing a 2D camera :)
     
  24. hereandnowlive

    hereandnowlive

    Joined:
    Jul 24, 2015
    Posts:
    2
    I know this is a really late post considering how old this thread is but I had this same issue and really had to dig to find the solution to keep smooth damp and have no jitter. What I found was that if you make the update types you use on your camera and your object you want to focus the camera on the same, you will no longer have this issue. As per example if you are using fixed update for your player character, use fixed update for your smooth dampening of the camera's movement. I hope this helps who ever stumbles upon this thread with this issue.

    note: I have only tested this with fixed update, I have no idea if it works with the other updates (update and lateupdate) but I have heard it does.
     
  25. majordillow

    majordillow

    Joined:
    Oct 26, 2012
    Posts:
    11
    had same problem but used fixed update! thanks!
     
    Aarondhp28 likes this.
  26. Aarondhp28

    Aarondhp28

    Joined:
    Feb 20, 2017
    Posts:
    1
    I can't believe I read this entire thread just to come to this easy solution. Waste of a half hour, lol, but thank you for the solution!
     
    valentin56610 likes this.
  27. geestwagen

    geestwagen

    Joined:
    Apr 20, 2017
    Posts:
    2
    you must remove the time.deltaTime multiplier and replace the update function with FixedUpdate
     
  28. ArdaOzcan

    ArdaOzcan

    Joined:
    Dec 9, 2017
    Posts:
    7
    Changing Update to FixedUpdate worked for me
     
  29. CrandellWS

    CrandellWS

    Joined:
    Oct 31, 2015
    Posts:
    178
    `transform.position = Vector3.Lerp( transform.position, point, 1 - Mathf.Exp( -2 * Time.deltaTime ) );`


    this was smoother for me than `1 - Mathf.Exp( -20 * Time.deltaTime ) `

    Thanks
     
  30. anthonov

    anthonov

    Joined:
    Sep 24, 2015
    Posts:
    160
    any camera work in LateUpdate avoids most problems
     
    PitaBreadGames likes this.
  31. luispedrofonseca

    luispedrofonseca

    Joined:
    Aug 29, 2012
    Posts:
    944
    Unfortunately that's incorrect. The camera movement should occur after your targets move. So, in case you're moving your targets on a FixedUpdate (all physics related movement occurs at this stage), you definitely shouldn't be moving your camera on a LateUpdate.
     
  32. anthonov

    anthonov

    Joined:
    Sep 24, 2015
    Posts:
    160
    Unless i miss something big, Update and all cycles of FixedUpdate come before LateUpdate.
    https://docs.unity3d.com/uploads/Main/monobehaviour_flowchart.svg
    So your camera move in LateUpdate.
    https://docs.unity3d.com/ScriptReference/MonoBehaviour.LateUpdate.html
     
  33. luispedrofonseca

    luispedrofonseca

    Joined:
    Aug 29, 2012
    Posts:
    944
    @BIGsmall What you're missing is that FixedUpdate is called independently from the main loop, so it results in being called a variable number of times in comparison to the regular Update.

    To try it out make a moving object on the FixedUpdate and then use a LateUpdate camera follow. You'll see the camera stutters a lot.
     
  34. anthonov

    anthonov

    Joined:
    Sep 24, 2015
    Posts:
    160
    This give me good result :
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class TestCamFollow : MonoBehaviour
    4. {
    5.  
    6.     public Camera cam;
    7.     public Rigidbody target;
    8.     [Space]
    9.     public float smoothTime = 3;
    10.     public float maxSpeed = 100;
    11.     public float camHeight = 5;
    12.     private Vector3 force;
    13.     private Vector3 camVelocity;
    14.  
    15.  
    16.     private void Update()
    17.     {
    18.         GetForce();
    19.     }
    20.  
    21.     private void FixedUpdate()
    22.     {
    23.         MoveTarget();
    24.     }
    25.  
    26.     private void LateUpdate()
    27.     {
    28.         MoveCamera();
    29.     }
    30.  
    31.     private void GetForce()
    32.     {
    33.         force.x = Input.GetAxis("Vertical");
    34.         force.z = Input.GetAxis("Horizontal");
    35.     }
    36.  
    37.     private void MoveTarget()
    38.     {
    39.         target.AddForce(force, ForceMode.Force);
    40.     }
    41.  
    42.     private void MoveCamera()
    43.     {
    44.         Vector3 newPosition = Vector3.SmoothDamp(cam.transform.position, target.transform.position, ref camVelocity, smoothTime, maxSpeed, Time.deltaTime);
    45.         newPosition.y = camHeight;
    46.         cam.transform.position = newPosition;
    47.         cam.transform.LookAt(target.transform, Vector3.up);
    48.     }
    49.  
    50.  
    51. }
    Do you mean a different test ?
     
    DavidSof likes this.
  35. luispedrofonseca

    luispedrofonseca

    Joined:
    Aug 29, 2012
    Posts:
    944
    @BIGsmall That test actually looks good because the LookAt method makes it less noticeable. Try instead to move the camera and the object on parallel planes and you'll see the stutter more clearly.
     
  36. anthonov

    anthonov

    Joined:
    Sep 24, 2015
    Posts:
    160
    There is no stutter from the camera. The RigidBody can occasionally stutter a little because its fixedDeltaTime is not sync with the update deltaTime.
    Test my script with a rolling sphere and a low fixedTimeStep like 0.05, and you will see stutter from hell.
    Look in the editor view, the camera path is smooth, but the rigidBody stutter.
    The lookAt method, makes rotational jumps to aim at the out-of-sync rigidBody position.
    Do the same now without the looktAt method. no more camera stutter at all.
    Its not the fault of the camera, nor the rigidBody, but the lookAt method who work as a deltaTime thing to follow a fixedDeltaTime thing. So there is out-of-sync.

    The solution to me is NOT to place camera work in FixedUpdate because i guess:
    - You are not sure if the camera's fixedUpdate come after all the rigidBodys fixedUpdate,
    - Your camera work can have more than one cycle per frame if fixedTimeStep is shorter than deltaTime,
    - Your camera will be out-of-sync with every no-physic-things moving in the scene. Its position will stutter like the rigidBody.

    My solution is to use a first target follower how can use smoothDamp and deltaTime to follow the stutter rigidBody .
    Then your camera has just to follow the target follower with its own smoothDamp for position, and the lookAt method for rotation, and all is smooth now.
    And the camera work is still in LateUpdate.
     
    Last edited: May 24, 2018
  37. luispedrofonseca

    luispedrofonseca

    Joined:
    Aug 29, 2012
    Posts:
    944
    @BIGsmall What I was saying in the first place was that putting the camera movement in LateUpdate doesn't solve all problems, like you mentioned above, and that it highly depends on what type of movement you have.
    Of course you can circumvent it in various ways (like the one you mentioned above) but in general, the easiest method is to simply match the camera update type with your target update type.
     
  38. anthonov

    anthonov

    Joined:
    Sep 24, 2015
    Posts:
    160
    Whatever you did in Update or FixedUpdate, you have to put your camera work in LateUpdate, because its sync with frame rate.
    Placing camera work in FixedUpdate like you mentioned just add more problems to me. I see no reason to do that.
    Edit:
    I see what you mean when you say the easiest method is to match the camera update with the target update, and i don't want to look rude saying its a bad idea.
    Sure the target will looks smooth at the screen, but all the moving update objects at the screen will shake instead of the target.
    So no perfect solution, If I understood correctly.
     
    Last edited: May 24, 2018
  39. VaskeDaGame

    VaskeDaGame

    Joined:
    Jun 5, 2018
    Posts:
    2
    try using fixedupdate or lateupdate. it should help
     
  40. chingwa

    chingwa

    Joined:
    Dec 4, 2009
    Posts:
    3,790
    Well this did not solve my stuttering issues (they are seemingly unrelated to camera movement code), but it did give me nice SuperSmooth camera movement. Thanks! :D
     
  41. rudyperalta831

    rudyperalta831

    Joined:
    Apr 13, 2020
    Posts:
    1
    Yo... I know it's been like 3 years, but would you mind dropping that differential equation? xD

    I'm only in calc 2 right now and Diff EQ makes no sense lol
     
    valentin56610 likes this.
  42. chingwa

    chingwa

    Joined:
    Dec 4, 2009
    Posts:
    3,790
    @rudyperalta831 I simply copied/adapted it from what George Foot posted above. Below is the equation, and below that a useage example.
    Code (CSharp):
    1.     public Vector3 SuperSmoothVector3Lerp( Vector3 pastPosition, Vector3 pastTargetPosition, Vector3 targetPosition, float time, float speed ){
    2.         Vector3 f = pastPosition - pastTargetPosition + (targetPosition - pastTargetPosition) / (speed * time);
    3.         return targetPosition - (targetPosition - pastTargetPosition) / (speed*time) + f * Mathf.Exp(-speed*time);
    4.     }
    Code (CSharp):
    1.  
    2.     public Transform cameraTransform;
    3.     public float rotationSmoothTime = 50f;
    4.  
    5.     Vector3 currentRotation;
    6.     Vector3 pastRotation;
    7.     Vector2 mouseSensitivity = new Vector2(2.75f,2.5f);
    8.     Vector2 pitchMinMax = new Vector2(-40f,85f);
    9.     float yaw;
    10.     float pitch;
    11.  
    12.     void FixedUpdate () {
    13.  
    14.             //---------------------------------
    15.             // ROTATE CAMERA
    16.             //---------------------------------
    17.  
    18.                 // Get Cursor movement
    19.                 yaw += Input.GetAxis("Mouse X") * mouseSensitivity.x;
    20.                 pitch -= Input.GetAxis("Mouse Y") * mouseSensitivity.y;
    21.                 pitch = Mathf.Clamp(pitch, pitchMinMax.x, pitchMinMax.y);
    22.            
    23.                 // Set Rotation Smoothing
    24.                 currentRotation = SuperSmoothVector3Lerp(currentRotation, pastRotation, new Vector3(pitch, yaw), Time.deltaTime, rotationSmoothTime);
    25.                 pastRotation = currentRotation;
    26.  
    27.                 cameraTransform.eulerAngles = currentRotation;
    28.     }
    29.  
     
    valentin56610 likes this.