Cinemachine is stuttering with 3D Rigidbody when rotating the camera

I’ve got two cameras, a freelook and a virtual cam that I swap between. They are both following an empty gameobject attached to the player (I have tried to have it follow the player itself as well, but nothing seemed to change in terms of stuttering)

If I’m only moving the character without adjusting the camera, there doesn’t seem to be any stuttering, but as soon as I try to rotate the camera, there’s noticeable stutter (Moreso on the virtual cam, than the freelook) on both the player and the world. I’ve looked at a few other threads with similar issues and have not had much luck.

-I have the player’s rigidbody interpolated (And have tried it with both extrapolation and none).
-The update method for the camera is Fixed Update
-I have updated the Fixed Time step from .02 to .0167 and .01. This seemed to help a little, but still noticeable.

  • I have made a test build with only the core necessary scripts (Slightly altered to only provide the core functions) and the issue still happens in the build of the game.

This is the aiming script that activates and controls the Virtual Camera
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
using Platformer.Movement;

    public class PlayerAimingState : MonoBehaviour
    {
        [SerializeField] float turnSpeed;
        [SerializeField] Transform camFollow;
        [SerializeField] AxisState xAxis;
        [SerializeField] AxisState yAxis;
        [SerializeField] CinemachineVirtualCamera aimCam;
        [SerializeField] CinemachineFreeLook freeCam;
        [SerializeField] Transform player;
        PlayerMovement movement;
        Aimer aimer;
        public  void OnStateChangeFrom()
        {
            aimCam.gameObject.SetActive(false);
            freeCam.gameObject.SetActive(true);
        }

        private void FixedUpdate()
        {
            if(aimer.isAiming)
            {
            OnStateChangeTo();

                AimRotation();
            return;
            }
        OnStateChangeFrom();
        }

        // Start is called before the first frame update
        void Start()
        {
            movement = GetComponentInParent<PlayerMovement>();
            aimer = FindObjectOfType<Aimer>();
        }

        public void AimRotation()
        {
        xAxis.Update(Time.fixedDeltaTime);
        yAxis.Update(Time.fixedDeltaTime);
        camFollow.rotation= Quaternion.RotateTowards(camLookAt.rotation, Quaternion.Euler(new Vector3(yAxis.Value, xAxis.Value, 0)),turnSpeed * Time.fixedDeltaTime);
        transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(new Vector3(0, xAxis.Value, 0)), turnSpeed * Time.fixedDeltaTime);

        }
    }

This is the general rotation code when the above aiming script is not active (At which point, it takes over the rotation with the player rotating with the camera follow object

    public class Rotation : MonoBehaviour
        {
            public void RotatePlayer(float rotationSpeed, Vector3 direction)
            {
                if (direction != Vector3.zero)
                {
                    direction.y = 0;
                    Quaternion newRotation = Quaternion.LookRotation(direction, Vector3.up);
                    transform.rotation = Quaternion.RotateTowards(transform.rotation, newRotation, rotationSpeed * Time.fixedDeltaTime);
                }
            }
        }

And here's the movement code
namespace Platformer.Movement
{
    public class PlayerMovement : MonoBehaviour
    {
        Rigidbody rb;
        Vector3 direction = Vector3.zero;
        Camera cam;
        Rotation rotation;
        Vector3 moveDirection;
        public float rotationSpeed;
        public float movementSpeed;
        float hInput;
        float vInput;
        Aimer aimer;
        private void Awake()
        {
            rb = GetComponent<Rigidbody>();
            cam = Camera.main;
            rotation = GetComponent<Rotation>();
            aimer = GetComponent<Aimer>();
        }
        // Start is called before the first frame update
        void Start()
        {

        }

        // Update is called once per frame
        void Update()
        {
            GetInput();
        }

        private void FixedUpdate()
        {
            MoveToPosition(hInput, vInput) ;
            if (!aimer.isAiming)
            {
                rotation.RotatePlayer(rotationSpeed, moveDirection);
            }

        }
        public Vector3 GetInput()
        {

            hInput = Input.GetAxisRaw("Horizontal");
            vInput = Input.GetAxisRaw("Vertical");
            return new Vector3(hInput, 0, vInput);
        }

        public  void MoveToPosition(float hInput, float vInput)
        {
            var camForward = cam.transform.forward;
            camForward.y = 0;
            Vector3 moveDir = camForward *vInput + cam.transform.right * hInput;
            moveDirection = moveDir;
            direction = transform.position + (moveDir.normalized * movementSpeed * Time.fixedDeltaTime);
            rb.MovePosition(direction);
        }

        public float GetRotationSpeed()
        {
            return rotationSpeed;
        }

        public Vector3 GetDirection()
        {
            //print(moveDirection);
            return moveDirection;
        }
    }
}

Images of the cam setups as well as the aiming and rigidbody settings on the player. Cinemachine Settings - Album on Imgur

I think you should do camera changes (rotation and position) in LateUpdate(), all others in FixedUpdate(). Maybe keep Fixed Time step at 0.01. That’s because you want to move the camera every frame, not just every timestep.

The rigidbody Player should have interpolation on. At least that’s how I do it to get smooth camera movements.

public class CameraController : MonoBehaviour
{
    void LateUpdate()
    {
        Vector3 v = player.transform.position;
        v.z = -4.3f; //add your offset from player
        transform.position = v;
    }
}