Quick answer: SceneTree must be running. Node visible. Material assigned. For pause-immune time, push a custom uniform from _process.
Water shader does nothing in pause menu. TIME freezes because the scene tree paused. Push your own clock if you need motion through pause.
The Fix
# Background animator (always runs)
extends Node
@export var material: ShaderMaterial
var t: float = 0.0
func _ready():
process_mode = Node.PROCESS_MODE_ALWAYS
func _process(d):
t += d
material.set_shader_parameter("u_time", t)
# In .gdshader
uniform float u_time;
void fragment() {
vec2 uv = UV + sin(u_time + UV.x * 10.0) * 0.05;
COLOR = texture(TEXTURE, uv);
}
Custom uniform sourced from a PROCESS_MODE_ALWAYS node keeps the shader ticking through pauses. Built-in TIME otherwise pauses with the tree.
Verifying
Pause game. Water keeps animating with custom uniform; freezes with built-in TIME. Both behaviors are useful in different contexts.
“TIME pauses with the tree. Roll your own when you need motion.”
Related Issues
For shader instance uniform, see instance uniform. For particles restart, see particles restart.
Custom clock. Shader ticks through pause.