Search Unity

Camera Following Rigidbody

Discussion in 'Editor & General Support' started by xmcdeath, Feb 21, 2013.

  1. xmcdeath

    xmcdeath

    Joined:
    Nov 12, 2012
    Posts:
    4
    So, first off, I'm making a game with a player who is essentially a sphere. The game is a 2D side scroller, with two cameras: both following the player, but one focusing on foreground elements that is set to "orthographic", and one that is focused on the background elements set as "perspective". Both have the same script attached to follow the player, but they are not attached to the player in the hierarchy in any way. Also, the player has no gravity; he flies around the level, the limitations being colliders surrounding him.

    Now my question: the player is physics based. He has a rigidbody attached and, in order to make the movement smooth and realistic, I use "AddForce" in the player movement script. All is well, except for the fact that there is some noticeable stuttering in either the camera's or player's movement. What I do know, however, is that when I change the rigidbody's interpolation option, I can increase/decrease the stuttering by a bit.

    Here I've attached the camera script:
    Code (csharp):
    1.  
    2.     // The target we are following
    3.     var target : Transform;
    4.     // The distance in the x-z plane to the target
    5.     var distance : int;
    6.     // the height we want the camera to be above the target
    7.     var height = 5.0;
    8.     // How much we
    9.     var heightDamping = 2.0;
    10.     var rotationDamping = 3.0;
    11.      
    12.     // Place the script in the Camera-Control group in the component menu
    13.     @script AddComponentMenu("Camera-Control/Smooth Follow")
    14.      
    15.     function LateUpdate () {
    16.     // Early out if we don't have a target
    17.     if (!target)
    18.     return;
    19.      
    20.     // Calculate the current rotation angles
    21.     var wantedRotationAngle = target.eulerAngles.y;
    22.     var wantedHeight = target.position.y + height;
    23.      
    24.     var currentRotationAngle = transform.eulerAngles.y;
    25.     var currentHeight = transform.position.y;
    26.      
    27.     // Damp the rotation around the y-axis
    28.     currentRotationAngle = Mathf.LerpAngle (currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);
    29.      
    30.     // Damp the height
    31.     currentHeight = Mathf.Lerp (currentHeight, wantedHeight, heightDamping * Time.deltaTime);
    32.      
    33.     // Convert the angle into a rotation
    34.     var currentRotation = Quaternion.Euler (0, currentRotationAngle, 0);
    35.      
    36.     // Set the position of the camera on the x-z plane to:
    37.     // distance meters behind the target
    38.     transform.position = target.position;
    39.     transform.position -= currentRotation * Vector3.forward * distance;
    40.      
    41.     // Set the height of the camera
    42.     transform.position.y = currentHeight;
    43.      
    44.     // Always look at the target
    45.     transform.LookAt (target);
    46.     }
    And the movement portion of the player's code:

    Code (csharp):
    1.     // Directs The Movement Of The Player
    2.     void FixedUpdate()
    3.     {
    4.      
    5.     if (!loadingLevel)
    6.     {
    7.      
    8.     float vertical = Input.GetAxis("Vertical") * speed;
    9.     float horizontal = Input.GetAxis("Horizontal") * speed;
    10.      
    11.     rigidbody.AddForce(horizontal, vertical, 0);
    12.     } else {
    13.      
    14.     this.rigidbody.velocity = Vector3.zero;
    15.     this.rigidbody.angularVelocity = Vector3.zero;
    16.      
    17.     }
    18.     }
    Any help will be greatly appreciated. Thanks in advance.
     
  2. imphenzia

    imphenzia

    Joined:
    Jun 28, 2011
    Posts:
    413
    I know it sounds odd, but try making the smooth camera updates in FixedUpdate() instead of LateUpdate()... I think it has something to do with jitter with irregular update periods in the Update / LateUpdate functions - but that's just a guess by me.

    In my script, I make it possible to select whether the smooth camera follow update should execute in Update(), FixedUpdate() or LateUpdate() where I've actually set FixedUpdate() as default because it has the least amount of jitter / jerkiness for me.

    Would be interested what you experience if you try it.
     
  3. xmcdeath

    xmcdeath

    Joined:
    Nov 12, 2012
    Posts:
    4
    Thanks for the suggestion. However, placing the code in a FixedUpdate only makes the problem worse.

    The camera is restricted to one angle, as the game is essentially 2D... so would there be a cleaner way of scripting the camera? The code we are currently using is made for 3D smooth follow cameras.
     
  4. zalogic

    zalogic

    Joined:
    Oct 6, 2010
    Posts:
    273
    Hi there!
    Having the exact same issue. Jittery camera with eve
    Does anyone have any feedback or general approach solution to this (rule of thumb?) or at least an explanation to why this is happening?
     
  5. zalogic

    zalogic

    Joined:
    Oct 6, 2010
    Posts:
    273
    Anyway xmcdeath, one problem you have there in your code is you're reading input in the FixedUpdate loop. Which is not good because the engine internally only gets the state of the input every Update. FixedUpdate can be called more than once in a frame.

    @imphy
    Camera update code should only be placed in LateUpdate to make sure all objects in the scene have been updated, including the one you are following because objects position Updates are not made in a known order.
     
  6. imphenzia

    imphenzia

    Joined:
    Jun 28, 2011
    Posts:
    413
    I'm aware that that is what the documentation suggests - problem is that it creates a lot of jitter for me. It's very noticeable when i Lerp the camera in LateUpdate and very smooth in FixedUpdate (like night and day difference) so I'm willing to challenge that "rule" based on the actual result.

    Update: Here's a video to show the difference: https://dl.dropbox.com/u/643622/Forums/JitterTest.mp4 (h.264 video @ 60fps, 18mb in size)
     
    Last edited: Feb 25, 2013
  7. imphenzia

    imphenzia

    Joined:
    Jun 28, 2011
    Posts:
    413
    With some further testing, different methods just seems to determine if the jitter is present on the object which is followed or the surrounding environment. With vsync off and camera lerp follow in FixedUpdate gives the best result for me. if vsync is enabled the spaceship is still smooth but jitter appears on the en environment. If vsync is enabled and camera lerp is in LateUpdate then the environment moves very smooth but the spaceship jitters very much.

    Since the eyes are focusing on the spaceship, jitter is most problematic if the spaceship isn't smooth. I'd really like to find a solution where both object being followed and the environment movements are super smooth with vsync enabled.
     
  8. renaissanceCoder1

    renaissanceCoder1

    Joined:
    Apr 8, 2015
    Posts:
    127
    Just to be clear, it isn't the spaceship or environment that is jittering - it is the camera. I have been dealing with this issue for a few hours now and here are a couple things that those of you who are just stumbling onto this thread can try. For the rigidbody your camera is following, set rigidbody interpolation to interpolate:

    rBody.interpolation = RigidbodyInterpolation.Interpolate;

    Make sure your camera movements and rotations are in LateUpdate. If your rigidbody is moving with velocity, put that code in FixedUpdate. LateUpdate is necessary for the camera to update in because it is basing its movements off of the target it is following. If the camera tries to follow its target's old position, it can cause some problems.
     
    oleg_v likes this.
  9. chadfranklin47

    chadfranklin47

    Joined:
    Aug 11, 2015
    Posts:
    226
    Has anyone found a solution to this? Is the solution the comment above? Thanks.
     
  10. renaissanceCoder1

    renaissanceCoder1

    Joined:
    Apr 8, 2015
    Posts:
    127
    I ended up figuring it out while making a camera controller tutorial. Put all Quaternion rotation and/or rigidbody manipulation in FixedUpdate() - for both the player and the camera. Before I mentioned some of this should be placed in LateUpdate(). This was a misunderstanding when reading some Unity docs.
     
  11. Taphos

    Taphos

    Joined:
    Dec 5, 2012
    Posts:
    11
    I found the solution for this problem.
    As you may guessed jittering happens when camera is following the character of object controlled by rigidbody physics.
    Attach kinematic rigidbody to camera object and let physics engine control and smooth camera movements alongside the character. Change camera position inside FixedUpdate with rigidbody.MovePosition(x) instead of transform.position = x;
    Turn on both rigidbodies interpolation to have smooth position changes on larger FPS rates.
     
  12. chasepettit

    chasepettit

    Joined:
    Oct 23, 2012
    Posts:
    42
    Here's one thing that tripped me up for a bit because it's not really explained well in the documentation anywhere that I could find.

    If you're following a rigidbody that's using interpolation, make sure you're referencing rigidbody.transform.position and rigidbody.transform.rotation instead of rigidbody.position and rigidbody.rotation. The transform's position/rotation is what gets interpolated, and the rigidbody.position and rigidbody.rotation will only update at the physics timestep (i.e. in FixedUpdate).

    Speaking generally, if you're in Update or LateUpdate, reference rigidbody.transform.position/rotation. If you're in FixedUpdate, reference rigidbody.position/rotation.

    So long as you're referencing the interpolated transform position/rotation, you should be fine just updating your camera position from LateUpdate. FixedUpdate should ideally be reserved just for physics updates, and you shouldn't be making any visual updates in there like moving the camera (the exception to this rule being if you're treating the camera itself like a physics object with its own rigidbody w/ interpolation).

    In retrospect, this is all logical and should've been obvious. For that reason, maybe it makes sense that it's not explicitly stated in the documentation, but for the benefit of those like me that overlook this distinction, be careful of which position/rotation you're referencing where.
     
    Last edited: Feb 10, 2016
    Westland and kbrizov like this.
  13. Jeffjeff

    Jeffjeff

    Joined:
    Dec 5, 2012
    Posts:
    1
    I would also like to share a couple of issues that tripped me up when trying to do this (Unity ver. 5.3.1f1):
    1. Interpolation does not work when moving a rigidbody with MovePosition. This is contrary to what the docs say.
      • I believe this is because interpolation relies on the rigidbody's velocity, and MovePosition does not change the velocity.
      • I was able to solve this by setting the rigidbody's velocity directly in FixedUpdate instead of calling MovePosition. If your game is has a more complex physics environment, you'll want to use AddForce instead.
    2. Setting the "Interpolate" field on a rigidbody in any way appears to disable interpolation completely until the rigidbody is reloaded (at which point the new setting will be active).
      • Set from the inspector, set from script, same result. Seems to be a bug.
      • In fact, just loading the "Interpolate" field in the inspector (by clicking on the GameObject in the hierarchy) disabled interpolation until reload.
    Once I'd figured these out, I was able to get smooth character and camera movement using the following path:
    1. Update()
      • Collect player input
    2. FixedUpdate()
      • Move character by changing velocity (either setting velocity or using AddForce).
    3. LateUpdate()
      • Set camera pos based on character pos. Character pos is interpolated, so character and camera motion is smooth.
     
    _eternal and Ranger-Ori like this.
  14. oleg_v

    oleg_v

    Joined:
    Nov 10, 2017
    Posts:
    68
    After many years... :)
    Have Rigidbody controlled by WheelColliders (all updates are in FixedUpdate) and smooth-followed Camera updated in LateUpdate and ofcourse - jittering :)
    Changed all follower rigidbody interpolate to "Interpolate" (None by default) and all became smooth!
    Thank you!
     
  15. AmazingRuss

    AmazingRuss

    Joined:
    May 25, 2008
    Posts:
    933
    Thank you all for your help.... been trying to solve this for YEARS, and now I have!
     
  16. sharoon12345

    sharoon12345

    Joined:
    Sep 15, 2021
    Posts:
    1
    How did you solve it.
     
  17. ShadyMike

    ShadyMike

    Joined:
    Apr 14, 2013
    Posts:
    60
    Lol yeah, would be nice to know your solution.
     
  18. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    304
    This problem has confused me to no end over the years, and there are so many project-specific intricacies that might come up, depending on how you've configured your camera and player.

    All I can really say is, print your player's position on every frame. This sounds easy, but there are four things you should probably keep track of:
    • Player's transform position at the end of FixedUpdate
    • Player's rigidbody position at the end of FixedUpdate
    • Player's transform position at the end of LateUpdate
    • Player's rigidbody position at the end of LateUpdate
    If the player's rigidbody is set to Interpolate, then all four of these values will be different. There's a great explanation in this blog post: https://blog.terresquall.com/2020/08/unity-rigidbodys-interpolate-property

    My setup works when the player's code is in FixedUpdate, the camera's code is in LateUpdate, and the camera is set to follow the player's transform.

    If you're still having trouble, don't forget to double check your execution order. You probably want the camera to move after everything else.
     
  19. aquilis007

    aquilis007

    Joined:
    Aug 11, 2016
    Posts:
    6
    This solved my problem, I just changed in the rigid body interpolate to interpolate.