Godot Version
Godot Engine v4.2.1.stable.official.b09f793f5
Question
Hi I’m working on a first person controller for a 3D game. Sometimes when testing there are sporadic spikes in _process and _physics_process resulting in the camera (controlled by the mouse) to stutter a random direction. However it happens unreliably, sometimes when I reboot Godot and or my computer the issue goes away, but sometimes it sticks around.
I’ve consulted the docs (especially: Fixing jitter, stutter and input lag — Godot Engine (stable) documentation in English), looked up related issues on the godot forums / reddit. I’ve learned a lot about Godot in the process accept what is causing this camera/mouse stutter.
Any help or guidance would be much appreciated. Thanks in advance!
Specs:
- Intel(R) Core™ i7-10700K CPU @ 3.80GHz 3.79 GHz
- RAM 32.0 GB
- Windows 11 Home
- Running off an SSD
- NVIDIA GeForce GTX 980 Ti
- Godot Engine v4.2.1.stable.official.b09f793f5
- Vulkan API 1.3.277 - Forward+
Things I have tried:
- Updating OS, graphics drivers, etc
- Turning off all environmental effects/lighting
- Disabling Vsync and/or switching to different vsync modes
- Enabling G-Sync on GPU
- Using Fullscreen, Exclusive Fullscreen, and windowed mode
- Low Processor mode Enabled/Disabled
- Setting monitor refresh rate to 60Hz to match the in game 60 phys ticks setting
- Setting Application > Run > Max FPS to slightly below the physics ticks (56)
- Setting the GPU to a max performance profile
- Switching updating the camera movements between _process and _physics_process
- Checking my CPU, RAM, GPU etc aren’t bottlenecking/heating
- I’ve even switched mice to rule out any weird polling rate / input issues
- Adjusting the max_physics_steps_per_frame
- Tried turning off some of the remote tree refresh settings to make sure Godot wasn’t slowing it down when it was running
- For sanity check I export a .exe and the issue still happens there too
- Probably some other steps I tried but forgot - was trying to figure this out for the better part of a day on my own
I’m 99% sure it’s something in how my code may be structured and my lack of understanding how/when _process vs _physics_process are ran. The fact that it is so inconsistent makes me feel like it’s a hardware issue but I tried my best to rule that out. I’ve been trying to use the profiler tool but all I can see is that for some reason a bunch of physics stuff is getting piled up to the max_physics_steps_per_frame.
class_name Player extends CharacterBody3D
@onready var visual_mesh: MeshInstance3D = $visual_mesh
@onready var collision_mesh: CollisionShape3D = $collision_mesh
var camera_input: Vector2
var rotational_velocity: Vector2
var _yaw_input
var _pitch_input
var SMOOTHNESS = 15
var mouse_sens = 0.7
var _mouse_rotation: Vector3
var _player_rotation: Vector3
var _camera_rotation: Vector3
@onready var CAMERA_CONTROLLER = $camera_rig
@onready var camera_yaw = $camera_rig/Camera_Yaw
@onready var camera_pitch = $camera_rig/Camera_Yaw/Camera_Pitch
var gravity = 9.8
var JUMP_VELOCITY = 5.0
var SPEED = 6.0
func _ready():
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
func _unhandled_input(event):
if event is InputEventMouseMotion:
camera_input = event.relative
if event.is_action_pressed("exit"):
get_tree().quit()
func _physics_process(delta):
movement(delta)
func _process(delta):
update_camera(delta)
func update_camera(delta):
rotational_velocity = lerp(rotational_velocity, camera_input, delta * SMOOTHNESS)
_yaw_input = -rotational_velocity.x * mouse_sens
_pitch_input = -rotational_velocity.y * mouse_sens
_mouse_rotation.x += _pitch_input * delta
_mouse_rotation.x = clamp(_mouse_rotation.x, deg_to_rad(-90.0), deg_to_rad(90.0))
_mouse_rotation.y += _yaw_input * delta
_player_rotation = Vector3(0.0,_mouse_rotation.y,0.0)
_camera_rotation = Vector3(_mouse_rotation.x,0.0,0.0)
camera_pitch.transform.basis = Basis.from_euler(_camera_rotation)
camera_yaw.transform.basis = Basis.from_euler(_player_rotation)
CAMERA_CONTROLLER.rotation.z = 0.0
camera_input = Vector2.ZERO
func movement(delta):
if not is_on_floor():
velocity.y -= gravity * delta
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
var input_dir = Input.get_vector( "move_right", "move_left", "move_backward","move_forward")
var direction = (camera_yaw.transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()