Water shader distorts objects in front (depth issue?) -Godot 4.6

Godot Version

Godot 4.6.1.stable

Question

Is there a solid way to make ocean waves shader without distorting objects between shader material and viewport?

Hi, I’m working on a water shader using screen_texture for distortion, but I’m running into a rendering issue that I can’t resolve.

Problem

When my plane (mesh) is between the camera and the water, the water shader distorts the plane as well. This results in:

  • A “double” or wavy duplicate of the plane

  • Distorted shadows (appearing duplicated)

  • Even editor icons (like camera gizmos) appearing warped

However, without the ocean mesh, everything appears correct.


Expected Behavior

Only the water surface should be distorted.


Current Behavior

Objects in front of the water are also being distorted, suggesting incorrect depth handling. (maybe)


Shader Code

shader_type spatial;

uniform vec3 water_color : source_color;
uniform float uv_scale = 1.0;
uniform float time_scale = 1.0;
uniform sampler2D water_normal_noise;

uniform sampler2D screen_texture : hint_screen_texture, repeat_disable;
uniform sampler2D depth_texture : hint_depth_texture;

void fragment() {
	// Raw depths
	float scene_depth = texture(depth_texture, SCREEN_UV).r;
	float water_depth = FRAGCOORD.z;

	// Add bias to stabilize comparison
	float distort_mask = step(water_depth - 0.01, scene_depth);

	// UVs
	vec2 _uv = UV * uv_scale;
	vec2 base_suv = SCREEN_UV;

	// Wave motion (normals)
	_uv.x += sin(TIME * time_scale + (_uv.x + _uv.y) * 25.0) * 0.01;
	_uv.y += cos(TIME * time_scale + (_uv.x - _uv.y) * 25.0) * 0.01;

	// Distorted screen UV
	vec2 distorted_suv = base_suv;
	distorted_suv.x += sin(TIME * time_scale + (base_suv.x + base_suv.y) * 25.0) * 0.01;
	distorted_suv.y += cos(TIME * time_scale + (base_suv.x - base_suv.y) * 25.0) * 0.01;

	// Blend instead of branching
	vec2 final_suv = mix(base_suv, distorted_suv, distort_mask);

	ALBEDO = texture(screen_texture, final_suv).rgb;

	NORMAL_MAP = texture(water_normal_noise, _uv).rgb;
	NORMAL *= 0.7;

	ROUGHNESS = 0.2;
}

Thanks in advance!


Pictures of the problem:

in tree is hidden. (OceanLayer2 is collision and flat visual layer)

is visible

See the double shadow and double plane? even the camera gizmo is doubled and wavy.

1 Like

What is the source of your shader code? Could it be that it was written for a Godot version 4.2 or lower?

I ask because with Godot 4.3 the depth axis (Z) was changed to a reverse Z axis (Introducing Reverse Z (AKA I'm sorry for breaking your shader) – Godot Engine).

In Godot 4.2 and lower a Z value of 1.0 meant the near plane and a Z value 0.0 meant the far plane.

In Godot 4.3 and later a Z value of 0.0 means the near plane and a Z value 1.0 means the far plane.

This means that if a shader written for 4.2 (or lower) is used with Godot 4.3 without adapting to the reverse Z the shader treats objects nearer to the camera as behind the water.

You can test this by creating a simple mesh (a white cube, for example) and place it below the water surface. If this mesh is not distorted then this reverse Z problem is your problem.

The solution in that case might be replacing a single line of code in your shader:

	float distort_mask = step(scene_depth, water_depth + 0.01);
1 Like

Thanks tomyy!

This was the solution:

float distort_mask = step(water_depth + 0.01, scene_depth);

I switched it from water_depth - 0.01 to water_depth + 0.01 and it worked.

Thanks again!