Quick answer: Physics interpolation jitter is almost always caused by moving objects inside _process() instead of _physics_process(). Move all physics-driven transforms inside _physics_process(), and call reset_physics_interpolation() any time you teleport an object to a new position.
You enable physics interpolation in your Godot 4 project expecting buttery-smooth movement—and instead your character stutters across the screen like it’s running at 12 frames per second. The setting is documented as a one-line fix, so why is the result worse than before you turned it on?
The Symptom
After enabling Project Settings → Physics → Common → Physics Interpolation, objects that move through the scene display one or more of these symptoms:
- Visible stutter or micro-jitter even at high frame rates
- The character visually “snaps” a few pixels on each physics tick
- Enemies or projectiles leave a faint double-image trail
- A teleported object slides smoothly from its old position to its new one over one frame instead of snapping instantly
All of these are symptoms of the interpolation system working correctly, but against you—either because movement is happening in the wrong callback, or because the interpolation state wasn’t reset after a positional warp.
What Causes This
Moving objects in _process() instead of _physics_process(). This is by far the most common cause. Physics interpolation works by recording an object’s transform at the start and end of each physics step, then blending between those two snapshots at the render frame rate. When you write position.x += speed * delta inside _process(), you are changing the transform outside of any physics tick. Godot still sees two snapshots, but they no longer correspond to intentional physics states—the result is visual noise that looks exactly like jitter.
Not calling reset_physics_interpolation() after a teleport. When you snap a character to a spawn point or a camera to a new target, the interpolation system dutifully interpolates from the previous position to the new one over the course of the next physics frame. On screen this looks like the object briefly slides or smears to its new location. Godot provides reset_physics_interpolation() precisely for this case.
Mixing interpolated and non-interpolated movement on the same node. If you use move_and_slide() in _physics_process() but also adjust position directly in response to an animation event or a _process() callback, you are producing conflicting transform snapshots on the same frame. The interpolation system cannot reconcile these and will stutter.
Using Node3D.global_position setter directly on a RigidBody3D. Setting global_position on a RigidBody3D bypasses the physics engine entirely and places the visual representation of the body at the new position without informing the physics simulation. The body’s physics state and its rendered position desynchronize, and interpolation then blends between two disagreeing states.
Enabling Physics Interpolation Project-Wide
First, confirm the setting is actually on. Open Project Settings → Physics → Common and enable Physics Interpolation. You must also make sure your physics tick rate is lower than your target frame rate—interpolation only helps if the render loop runs faster than the physics loop. The default physics tick is 60 Hz, so if you are targeting 60 fps there is no gap to interpolate across; set your monitor to 144 Hz or cap your target frame rate above your physics tick.
You can also enable interpolation per-node without the project setting by setting the physics_interpolation_mode property:
# Enable interpolation on this node only
$Player.physics_interpolation_mode = Node.PHYSICS_INTERPOLATION_MODE_ON
# Disable interpolation for a UI element or HUD that should not interpolate
$HUD.physics_interpolation_mode = Node.PHYSICS_INTERPOLATION_MODE_OFF
The three values are PHYSICS_INTERPOLATION_MODE_INHERIT (default, follows parent), PHYSICS_INTERPOLATION_MODE_ON, and PHYSICS_INTERPOLATION_MODE_OFF. Any node you don’t want to interpolate—particle emitters anchored to the camera, UI overlays, canvas layers—should be set to OFF.
The Fix: Move Everything to _physics_process()
The single most impactful fix is auditing your movement code and ensuring that all positional changes for physics-simulated nodes happen exclusively inside _physics_process().
Wrong — causes jitter:
func _process(delta: float) -> void:
var direction = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
position += Vector3(direction.x, 0, direction.y) * speed * delta # Wrong!
Correct — smooth interpolation:
func _physics_process(delta: float) -> void:
var direction = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
velocity = Vector3(direction.x, 0, direction.y) * speed
move_and_slide() # CharacterBody3D — physics engine owns the transform
For nodes that are not CharacterBody or RigidBody but still need smooth motion—a moving platform controlled by a Tween or an AnimationPlayer, for example—you can keep the animation in _process() as long as physics interpolation is turned off for that node. Interpolation is only beneficial when the physics engine is the authoritative source of position.
Fixing Teleports with reset_physics_interpolation()
Any time you set a node’s position directly—spawning, respawning, loading a new level, or warping a camera—call reset_physics_interpolation() immediately after:
func respawn_player() -> void:
global_position = spawn_point.global_position
reset_physics_interpolation() # Must come AFTER setting position
The ordering matters. If you call reset_physics_interpolation() before setting the new position, Godot resets the snapshots to the old position and will still interpolate to the new one. Set position first, reset second.
For a camera following the player, the same rule applies. After snapping the camera to a new look-at target:
func cut_to_cinematic(target: Node3D) -> void:
global_transform = target.global_transform
reset_physics_interpolation()
# Now interpolation resumes from this new position
CharacterBody3D vs RigidBody3D Interpolation
CharacterBody3D interpolation works well by default because move_and_slide() is always called from _physics_process(), which is the correct hook. The body’s position changes only during physics ticks, so Godot’s two snapshots are always clean. The most common mistake with CharacterBody3D is applying a position offset in _process() for something like a bobbing animation or a recoil effect. Instead, apply those offsets to a child visual node and leave the CharacterBody3D’s own transform untouched.
RigidBody3D is driven entirely by the physics engine, so as long as you don’t fight the engine by setting global_position or linear_velocity outside of _integrate_forces(), interpolation works automatically. Applying forces and impulses via apply_impulse() and apply_force() is safe from any callback because those methods enqueue changes to be applied at the next physics step rather than modifying the transform directly.
extends RigidBody3D
func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
# Safe: this runs inside the physics step
if Input.is_action_pressed("jump"):
state.apply_central_impulse(Vector3.UP * jump_force)
func _process(delta: float) -> void:
# WRONG: do not set linear_velocity here
# linear_velocity = Vector3.UP * 10 # This will cause jitter!
pass
Debugging Interpolation Issues
If you’re unsure which node is causing the jitter, temporarily set physics_interpolation_mode to OFF on all nodes in the scene, then turn it back on one subtree at a time. The jitter will reappear when you re-enable the subtree containing the problematic movement code.
You can also add a temporary debug print to verify your movement code is in the right callback:
func _physics_process(delta: float) -> void:
print("physics tick, position: ", global_position)
move_and_slide()
In the Godot output panel, physics tick prints should appear at a steady rate matching your physics FPS (default 60). If the position is changing between physics ticks, something outside _physics_process() is modifying the transform.
Related Issues
If your character movement feels smooth but collisions still feel imprecise, see Fix: Godot NavigationAgent3D Not Reaching Target Position. For per-object visual glitches that persist even after fixing interpolation, shader-side issues may be the culprit—see Fix: Godot Shader Uniform Not Updating at Runtime.
Physics interpolation is a gift—stop fighting it by moving things in the wrong callback.