Godot Version
Godot v4.6
Question
Writing a water shader that uses DEPTH_TEXTURE or SCREEN_TEXTURE for effects like intersection foam or transparency, and your water mesh has vertex displacement (waves), you will get directional visual artifacts where parts of the wave appear transparent but only from certain camera angles (-Z in my case).
This took hours to debug, so I’m documenting it here.
Setup
-
A
PlaneMesh(200×200, 100×100 subdivisions) with a spatial shader -
Vertex shader displaces
VERTEX.yto create waves (both gentle base waves and large “rogue wave” humps up to 8 units tall) -
Fragment shader uses
DEPTH_TEXTUREfor intersection foam (foam ring where objects like rocks meet the water surface) -
Fragment shader uses
SCREEN_TEXTUREto blend water color with the scene behind it for transparency
Both DEPTH_TEXTURE and SCREEN_TEXTURE read from the framebuffer as rendered so far. On a single mesh with vertex displacement, different parts of the same mesh overlap in screen space. The elevated parts read the already-rendered flat parts as “the scene behind,” which produces blending.
Attempted fixes that didn’t work:
-
Skipping foam when
rogue_wave_value > threshold: helped but couldn’t catch all edge cases since the depth issue exists at the wave’s edges too -
The issue was directional: facing +Z the waves looked fine, facing -Z they were covered in foam/overlapping with the flat ocean texture. This is because the back slope of the wave (relative to camera) has the flat ocean directly behind it in screen space.
I’m wondering if this is an inherent limitation of screen-space techniques on self-overlapping geometry, or just a bug in Godot. But it’s not obvious when debugging because:
-
The artifacts are directional and only appear from camera angles where the wave slope faces the camera with flat ocean behind it
-
They look like transparency bugs, leading you to chase alpha/blend mode fixes
-
Adding
cull_disableddoesn’t help (and is actually needed for steep wave faces) -
The issue exists regardless of
render_priority,depth_draw_*mode, orblend_*mode
I’m by no means experienced in shaders so any help would be appreciated.
Workaround:
Removing DEPTH_TEXTURE and SCREEN_TEXTURE from the water shaders fixed the transparent overlapping problem. Except now I lose the ability to implement water transparency, and the entire ocean surface is opaque
.