Was trying the whole day to set up a Camera3D that would follow the player character with SpringArm3D and pivot properly. Right now, my setup looks so:
Encountered jitter and started applying solutions. I:
Tried out-of-the-box physics interpolation. (Things got better, but still undesirable)
Played with Engine.PhysicsJitterFix, which did approximately nothing.
Promoted Physics Ticks per Second, which produced immaculate results, but could hurt performance later.
My screen has a 144 Hz refresh rate. I’m probably not the only one. So how do I make camera move smoothly, while keeping my character’s movement locked to 60 FPS? Should I try to detach the camera from my character completely and try to move its pivot programmatically through _Process() to match the character? My concern is that it would look bad anyway because of low framerate on character movement.
So what is the right way to organise a Camera3D to follow the player character and update its position according to framerate?
So I’m currently still experimenting with this but it seems to be working pretty well at the moment for my first person project.
I have my camera rig set as Top Level and manually adjust the camera’s position in relation to the character’s interpolated position. I keep the tick rate at the default of 60.
This camera position change logic can then be moved to the Process method, so it won’t be stuck at the project’s tick rate and will look a lot smoother at higher frame rates.
IMPORTANT: Physics Interpolation needs to be enabled for the project but your CAMERA nodes (in this case your CameraPivot) needs to be DISABLED. You should see this in the menu Inspector when you click on the node.
Here’s a basic outline of how it works in C#. The logic should be identical in GDScript:
// This is just a representation of the vector difference between the character and Top Level camera system nodes.
private Vector3 TargetCameraPositionDiff;
public override void _Ready()
{
// Get camera system node references
CameraRig = GetNode<Node3D>("%CameraRig");
// Calculate the vector difference of the camera system from the character
TargetCameraPositionDiff = GlobalPosition - CameraRig.GlobalPosition;
// Set top levels
CameraRig.TopLevel = true;
}
public override void _Process(double delta)
{
// Player interpolated position
Transform3D PlayerInterpolatedPosition = GetGlobalTransformInterpolated();
// Interpolated camera position
Vector3 PositionForCamera = PlayerInterpolatedPosition.Origin - TargetCameraPositionDiff;
// Set the camera position manually
CameraRig.GlobalPosition = PositionForCamera;
}
This basically eliminated the camera jitter. I do notice that the meshes attached to the character now have some jitter when moving the camera around so I probably need to interpolate the meshes as well.