2D water with reflections

Highly customizable reflective 2D water.

inspired by “Kingdom Two Crowns”.

How to use:

– Add a ColorRect (make sure it is at the bottom of the scren tree).

– Add the shader to the ColorRect.

– For the parameter “noise_texture” just use a default simplex noise texture.

–  For the parameter “noise_texture2” (used for the water texture, which can be turned off) use a simplex noise texture with the parameters shown in the screenshot below.

– Tweak the parameters to your liking and that’s it.


After applying the shader to the ColorRect, it will, by default, be split vertically into two sections:

– the upper section: which is what will be reflected in the bottom section. *

– the bottom section: which contains the water and the reflection of the upper section.


* Make sure that what you want to be reflected is inside of the upper layer of the ColorRect.

Shader code
shader_type canvas_item;

uniform float level : hint_range(0.0, 1.0) = 0.5; 
uniform vec4 water_albedo : hint_color = vec4(0.26, 0.23, 0.73, 1.0);
uniform float water_opacity : hint_range(0.0, 1.0) = 0.35;
uniform float water_speed = 0.05;
uniform float wave_distortion = 0.2;
uniform int wave_multiplyer = 7;
uniform bool water_texture_on = true;
uniform float reflection_X_offset = 0.0;
uniform float reflection_Y_offset = 0.0;
uniform sampler2D noise_texture : hint_albedo;
uniform sampler2D noise_texture2 : hint_albedo;

void fragment() {
	vec2 uv = UV;
	COLOR = vec4(0.0);
	if (uv.y >= level) {
		COLOR.a = 1.0;
		// distorted reflections
		vec2 water_uv = vec2(uv.x, uv.y * float(wave_multiplyer));
		float noise = texture(noise_texture, vec2(water_uv.x + TIME * water_speed, water_uv.y)).x * wave_distortion;
		noise -= (0.5 * wave_distortion);
		// water texture
		if (water_texture_on) {
			float water_texture_limit = 0.35;
			vec4 water_texture = texture(noise_texture2, uv * vec2(0.5, 4.0) + vec2(noise, 0.0));
			float water_texture_value = (water_texture.x < water_texture_limit) ? 1.0 : 0.0;	
			COLOR.xyz = vec3(water_texture_value);
		// putting everything toghether 
		vec4 current_texture = texture(SCREEN_TEXTURE, vec2(SCREEN_UV.x + noise + reflection_X_offset, 1.0 - SCREEN_UV.y - (level - 0.5) * 2.0 + reflection_Y_offset));
		COLOR = mix(COLOR, current_texture, 0.5);
		COLOR = mix(COLOR, water_albedo, water_opacity);
2d, reflection, water
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

2D Water distortion effect (Godot 4)

Wind Waker 2d Water Shader (GODOT 4)

Pixel Animated Water

Notify of

Newest Most Voted
Inline Feedbacks
View all comments
4 months ago

Thank you! I’m trying to wrap my head around this. I’m having an issue where if my camera moves up, the reflection also moves. How would I make it so the reflection is fixed no matter where the camera goes?

27 days ago
Reply to  jason

Also have this problem and the wave just stops at the start. Did you ever find a solution?

27 days ago
Reply to  jason

Ok, found a solution for wave stopping, the noise has to be set to be repeated like so: uniform sampler2D noise_texture : repeat_enable;

9 days ago

Does this Work in godot 4 I changed the hint_color to source_color and changed the SCREEN_TEXTURE and it seemed to work but when I added noise it looked like a bunch of lines