Search Unity

  1. Full schedule for #UniteBerlin is now available! Featuring talks on our roadmap, hands-on labs and much more! Check it out!
    Dismiss Notice
  2. Unity 2018.1 has arrived! Read about it here
    Dismiss Notice
  3. Scriptable Render Pipeline improvements, Texture Mipmap Streaming, and more! Check out what we have in store for you in the 2018.2 Beta.
    Dismiss Notice
  4. ARCore is out of developer preview! Read about it here.
    Dismiss Notice
  5. Magic Leap’s Lumin SDK Technical Preview for Unity lets you get started creating content for Magic Leap One™. Find more information on our blog!
    Dismiss Notice
  6. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

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:
    424
    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. }
     
  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:
    424
  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.
     
    CrandellWS and Westland like this.
  5. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    424
    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?
     
    CrandellWS and SpaceManDan like this.
  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:
    424
    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. }
     
  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:
    424
    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.
     
  12. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    424
    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. }
     
  13. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    424
    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:
    127
    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:
    424
    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:
    424
  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:
    386

    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.
     
  20. MachCUBED

    MachCUBED

    Joined:
    Nov 26, 2011
    Posts:
    40
    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. // The distance in the x-z plane to the target
    15. var distance = 4.0;
    16. // the height we want the camera to be above the target
    17. var height = 1.0;
    18. // How much we
    19. var heightDamping = 25.0;
    20. var rotationDamping = 35.0;
    21.  
    22. // Place the script in the Camera-Control group in the component menu
    23. @script AddComponentMenu("Camera-Control/Smooth Follow")
    24.  
    25. function Start ()
    26. {
    27.     // Early out if we don't have a target
    28.     if (!target)
    29.         return;
    30.        
    31.     transform.position = target.position;
    32. }
    33.  
    34. function LateUpdate () {
    35.     // Early out if we don't have a target
    36.     if (!target)
    37.         return;
    38.    
    39.     // Calculate the current rotation angles
    40.     var wantedRotationAngle = target.eulerAngles.y;
    41.     var wantedHeight = target.position.y + height;
    42.        
    43.     var currentRotationAngle = transform.eulerAngles.y;
    44.     var currentHeight = transform.position.y;
    45.    
    46.     // Damp the rotation around the y-axis
    47.     currentRotationAngle = Mathf.LerpAngle (currentRotationAngle, wantedRotationAngle, rotationDamping * (1 - Mathf.Exp( -20 * Time.deltaTime )));
    48.  
    49.     // Damp the height
    50.     currentHeight = Mathf.Lerp (currentHeight, wantedHeight, heightDamping * (1 - Mathf.Exp( -20 * Time.deltaTime )));
    51.  
    52.     // Convert the angle into a rotation
    53.     var currentRotation = Quaternion.Euler (0, currentRotationAngle, 0);
    54.    
    55.     // Set the position of the camera on the x-z plane to:
    56.     // distance meters behind the target
    57.     transform.position = target.position;
    58.     transform.position -= currentRotation * Vector3.forward * distance;
    59.    
    60.     // Set the rotation
    61.     transform.rotation.z = target.rotation.z;
    62.  
    63.     // Set the height of the camera
    64.     transform.position.y = currentHeight;
    65.    
    66.     // Always look at the target
    67.     transform.LookAt (target);
    68. }
    69.  
    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:
    424
    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.
     
  23. ZyntharNOR

    ZyntharNOR

    Joined:
    Sep 20, 2013
    Posts:
    12
    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!
     
  27. geestwagen

    geestwagen

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

    ArdaOzcan

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

    CrandellWS

    Joined:
    Oct 31, 2015
    Posts:
    45
    `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. BIGsmall

    BIGsmall

    Joined:
    Sep 24, 2015
    Posts:
    43
    any camera work in LateUpdate avoids most problems
     
  31. luispedrofonseca

    luispedrofonseca

    Joined:
    Aug 29, 2012
    Posts:
    671
    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. BIGsmall

    BIGsmall

    Joined:
    Sep 24, 2015
    Posts:
    43
    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:
    671
    @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. BIGsmall

    BIGsmall

    Joined:
    Sep 24, 2015
    Posts:
    43
    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 ?
     
  35. luispedrofonseca

    luispedrofonseca

    Joined:
    Aug 29, 2012
    Posts:
    671
    @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. BIGsmall

    BIGsmall

    Joined:
    Sep 24, 2015
    Posts:
    43
    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 at 5:12 PM
  37. luispedrofonseca

    luispedrofonseca

    Joined:
    Aug 29, 2012
    Posts:
    671
    @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. BIGsmall

    BIGsmall

    Joined:
    Sep 24, 2015
    Posts:
    43
    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 at 10:14 PM