- Home /
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.
have the player's rigidbody interpolated (And have tried it with both extrapolation and none). -The update method for the camera is Fixed Update
- 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. https://imgur.com/a/OOV67w8
Answer by rh_galaxy · Apr 30 at 08:02 PM
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;
}
}
I kept the timestep at .01, Interpolation on, and moved all the rotation code to LateUpdate() but it just seemed to make the jittering worse. I don't think Cinemachine liked it when I had my player moving in FixedUpdate with the rigidbody and trying to follow the rotation in LateUpdate(). :(
Your answer
Follow this Question
Related Questions
Flip over an object (smooth transition) 3 Answers
Rotating player relative to the camera (Unity C#) 1 Answer
Character goes up when the camera looks up 0 Answers
Camera rotation 0 Answers
Pysics not working as expected 1 Answer