Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug How to fix FPS jitter when rotating camera with mesh?

Discussion in 'Scripting' started by adriansbardaks, Jul 21, 2023.

  1. adriansbardaks

    adriansbardaks

    Joined:
    Jun 4, 2020
    Posts:
    4
    So whenever I walk around and rotate my mouse around, the camera jitters. When it comes to the hierarchy, it looks something like this (the unnecessary parts are blurred out):
    upload_2023-7-21_18-26-6.png

    The Orientation is just an empty object, that stores the rotation of the whole mesh, and Capsule has the Collider. And the Rigidbody settings for SK_Arms_Reload looks like this:
    upload_2023-7-21_18-34-9.png

    The camera inside the Arms Rig is just the position in which the camera should be. The CameraHolder just copies the position of the camera that's in the Arms Rig, and so the CameraHolder has a script MoveCamera, and it goes like this:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. namespace Game.Movement
    6. {
    7.     public class MoveCamera : MonoBehaviour
    8.     {
    9.  
    10.         [SerializeField] Transform cameraPosition;
    11.  
    12.         void Update()
    13.         {
    14.             transform.position = cameraPosition.position;
    15.         }
    16.     }
    17.  
    18. }
    And then there's Camera (the one inside CameraHolder). It has PlayerCam script, and it looks like this:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. namespace Game.Movement
    6. {
    7.     public class PlayerCam : MonoBehaviour
    8.     {
    9.         [SerializeField] public float sensX;
    10.         [SerializeField] public float sensY;
    11.  
    12.         [SerializeField] GameObject mesh;
    13.         [SerializeField] Transform orientation;
    14.  
    15.         private readonly WaitForFixedUpdate _waitForFixedUpdate = new();
    16.         Rigidbody rb;
    17.         private float _tmpRotationVelocity;
    18.  
    19.         float xRotation;
    20.         float yRotation;
    21.        
    22.         // Start is called before the first frame update
    23.         void Start()
    24.         {
    25.             Cursor.lockState = CursorLockMode.Locked;
    26.             Cursor.visible = false;
    27.             rb = mesh.GetComponent<Rigidbody>();
    28.         }
    29.  
    30.         private void Awake() {
    31.             StartCoroutine(LateFixedUpdate());
    32.         }
    33.  
    34.         void Update()
    35.         {
    36.            
    37.  
    38.             // get mouse input
    39.  
    40.             float mouseX = Input.GetAxisRaw("Mouse X") * Time.smoothDeltaTime * sensX;
    41.             float mouseY = Input.GetAxisRaw("Mouse Y") * Time.smoothDeltaTime * sensY;
    42.  
    43.             yRotation += mouseX;
    44.  
    45.             xRotation -= mouseY;
    46.             xRotation = Mathf.Clamp(xRotation, -90f, 90f);
    47.  
    48.             // rotate cam and orientation
    49.             transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
    50.             orientation.rotation = Quaternion.Euler(0, yRotation, 0);
    51.  
    52.            
    53.         }
    54.  
    55.         private IEnumerator LateFixedUpdate()
    56.         {
    57.             while(true)
    58.             {
    59.                 yield return _waitForFixedUpdate;
    60.                 HandleRotation();
    61.             }
    62.         }
    63.  
    64.         private void HandleRotation()
    65.         {
    66.             // rotating the actual mesh
    67.             var targetHorizontalAngle = Mathf.SmoothDampAngle(
    68.                 rb.rotation.eulerAngles.y,
    69.                 yRotation,
    70.                 ref _tmpRotationVelocity,
    71.                 0.1f
    72.             );
    73.             Quaternion targetRotation = Quaternion.Euler(0.0f, targetHorizontalAngle, 0.0f);
    74.             rb.MoveRotation(targetRotation);
    75.         }
    76.     }
    77.  
    78. }
    In this script I tried some fixes from this thread: https://forum.unity.com/threads/character-rotation-camera-jitter.1141756/ (the ones pointed out by MarekNijaki). The mesh in this script is just the GameObject of SK_Arms_Reload and Orientation is the transform of Orientation (the one in SK_Arms_Reload). And so, all of this combined together, the jitter looks like this:
    (ignore the 2 long pauses in the video, that was just the recording software). So yeah, my guess is that the problem is in the fact that the camera is rotating and then the mesh knda copies the rotation of the camera as well, and it ends up jittering, but I'm not sure if that really is the problem and I'm too stupid to actually solve it. So any help would be appreciated. Thanks!
     
  2. zulo3d

    zulo3d

    Joined:
    Feb 18, 2023
    Posts:
    510
    So the camera is a child of a rigidbody?

    You can either set physics frame rate to match your rendering frame rate or unparent the camera and update its transform in Update().

    You can set the physics frame rate in Project Settings/Time/Fixed Timestep
     
    adriansbardaks likes this.
  3. adriansbardaks

    adriansbardaks

    Joined:
    Jun 4, 2020
    Posts:
    4
    Thanks for the reply! I tried setting the physics frame rate to the render frame rate, but it didn't do much. The camera isn't exactly parented to rigidbody. More like they use the same yRotation (look in the PlayerCam script, where the HandleRotation() method is being called, that's where I'm rotating the mesh. upload_2023-7-22_10-17-12.png
    Here I've highlighted the camera that's the actual camera in the scene. The one in Arms Rig is just the position of the camera. What I did notice however is that if I set the physics frame rate higher, then the jitter is reduced greatly, but it's still quite noticable.
     
    Last edited: Jul 22, 2023
  4. zulo3d

    zulo3d

    Joined:
    Feb 18, 2023
    Posts:
    510
    Take the camera out of the CameraHolder and delete the holder. Remove the MoveCamera script.

    I've modified your PlayerCam script:


    Code (CSharp):
    1.     using System.Collections;
    2.     using System.Collections.Generic;
    3.     using UnityEngine;
    4.    
    5.     namespace Game.Movement
    6.     {
    7.         public class PlayerCam : MonoBehaviour
    8.         {
    9.             [SerializeField] public float sensX;
    10.             [SerializeField] public float sensY;
    11.    
    12.             [SerializeField] GameObject mesh;   // Gameobject with rigidbody
    13.  
    14.             Rigidbody rb;
    15.    
    16.             float xRotation;
    17.             float yRotation;
    18.          
    19.             void Start()
    20.             {
    21.                 Cursor.lockState = CursorLockMode.Locked;
    22.                 Cursor.visible = false;
    23.                 rb = mesh.GetComponent<Rigidbody>();
    24.             }
    25.    
    26.  
    27.             void Update()
    28.             {
    29.                 // get mouse input
    30.                 float mouseX = Input.GetAxis("Mouse X") * sensX;
    31.                 float mouseY = Input.GetAxis("Mouse Y") * sensY;
    32.    
    33.                 yRotation += mouseX;
    34.    
    35.                 xRotation -= mouseY;
    36.                 xRotation = Mathf.Clamp(xRotation, -90f, 90f);
    37.    
    38.                 // rotate camera
    39.                 transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
    40.  
    41.                 Vector3 headOffset=rb.transform.up*0.4f;
    42.                 // position camera
    43.                 transform.position = rb.transform.position+headOffset;
    44.  
    45.             }
    46.    
    47.             void FixedUpdate()
    48.             {
    49.                 // Set the rigidbody's rotation:
    50.                 Quaternion targetRotation = Quaternion.Euler(0.0f, yRotation, 0.0f);
    51.                 rb.MoveRotation(targetRotation);
    52.             }
    53.         }
    54.    
    55.     }
     
    adriansbardaks likes this.
  5. adriansbardaks

    adriansbardaks

    Joined:
    Jun 4, 2020
    Posts:
    4
    Thank you for the reply! So I added your modifier script, as well as removed the CameraHolder, and now there is no camera stutter whatsoever, however the mesh still stutters. I tried changing the physics frame rate to the rendering frame rate, tried setting it to the default (which for me was 0.02), but that didn't help. I tried disabling the scripts that are responsible for movement (that are on SK_Arms_Reload), but that didn't help and it also jitters when rotating the mouse only. So yeah, idk what else to test. For reference, this is how it looks now:
     
  6. zulo3d

    zulo3d

    Joined:
    Feb 18, 2023
    Posts:
    510
    Okay two possible solutions:

    Code (CSharp):
    1.             void FixedUpdate()
    2.             {
    3.                 // Set the rigidbody's rotation:
    4.                 Quaternion targetRotation = Quaternion.Euler(0.0f, yRotation, 0.0f);
    5.                 rb.MoveRotation(Quaternion.Slerp(rb.rotation,targetRotation,8*Time.deltaTime));
    6.             }

    Code (CSharp):
    1.            void FixedUpdate()
    2.             {
    3.                 float diff=Mathf.DeltaAngle(rb.transform.eulerAngles.y,transform.eulerAngles.y);
    4.                 rb.AddRelativeTorque(new Vector3(0,diff,0));
    5.                 rb.angularDrag=20;
    6.             }
     
    adriansbardaks likes this.
  7. adriansbardaks

    adriansbardaks

    Joined:
    Jun 4, 2020
    Posts:
    4
    The first solution didn't exactly work, since the stutter was pretty much the same. The other solution, didn't work at first, but I changed the AddRelativeTorque line to this:
    Code (CSharp):
    1. rb.AddRelativeTorque(new Vector3(0,diff,0), ForceMode.Acceleration);
    I tried different ForceModes, but not all of them worked, some needed the first part of AddRelativeTorque to be multiplied by Time.deltaTime. So now, it looks like the jitter is next to 0, but when I move the mouse faster, then the jitter is more noticeable. For reference, here's how it looks now:

    (ignore the relatively long pauses in the video, it's just the recording software)
    I'm not sure how visible the jitter is when rotating quickly, but yeah, it's there. I also changed the angularDrag to 5, because else the mesh was falling behind too much when rotating. Nevertheless, it now looks way better, and I thank you for that!
     
    Last edited: Jul 23, 2023