Water-like wavelet

This effect can be applied to a ColorRect or any other canvas item. It will simulate a water wavelet. The effect itself is mostly translucent so it can be applied easily on top of anything.

However, it needs some information about its position and size in the viewport. Use the following script to set those uniforms right :

# "target" is the Canvas item which material contains the shader.

func set_shader_params() -> void:
	var viewport_size : Vector2 = get_viewport_rect().size
	var target_size : Vector2 = target.get_global_rect().size
	var target_size_uv : Vector2 = target_size / viewport_size
	var target_pos : Vector2 = target.get_global_rect().position
	var target_pos_uv : Vector2 = target_pos / viewport_size
	target.material.set_shader_param("screen_pos", target_pos_uv)
	target.material.set_shader_param("screen_size", target_size_uv)

The displayed example is driven by an animation player acting on the uniforms to change progression, thickness and wavelet factor.

Shader code
shader_type canvas_item;

uniform float progression : hint_range(0.0, 1.0) = 0.5;

uniform float fade : hint_range(0.0, 1.0) = 0.9;

uniform float thickness : hint_range(0.01, 1.0) = 0.1;

uniform float wavelet_factor : hint_range(.1, 4.) = 4.;

// In pixels.
uniform float deformation_length = 16;

uniform vec2 screen_pos;

uniform vec2 screen_size;

uniform vec4 tint : hint_color = vec4(.5, .5, .9, 1.);

const float PI = 3.1415926535897932384626433832795;

void fragment() {
	vec2 norm = normalize(UV - vec2(.5));
	float dist = distance(UV, vec2(.5)) * 2.;
	float prog = progression * (1. - thickness - 0.01);
	float distortion = clamp((dist - prog) / thickness, -1., 1.);
	distortion = mix(cos(distortion * (PI / wavelet_factor)), 0., step(0.99, abs(distortion)));
	vec2 def = distortion * deformation_length * SCREEN_PIXEL_SIZE;
	vec2 offset_vector = norm * def;
	vec2 target_id = screen_pos + ((UV + offset_vector) * screen_size);
	target_id.y = 1.0 - target_id.y;
	COLOR = mix(vec4(0.),
				vec4(texture(SCREEN_TEXTURE, target_id).rgb, mix(1.0, smoothstep(1., 0., (progression - fade) / (1. - fade)),
				step( fade, progression ))), step(0.01, distortion));
water, wave
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.

More from CasualGarageCoder


Shining Sprite Effect

(Almost) Invisible Character

Related shaders

HQ4X Shader (like in Emulators)

Earthbound-like battle background shader w/scroll effect and palette cycling

RotSprite-Like Algorithm for Cleaner Pixel Art Rotation


1 Comment
Newest Most Voted
Inline Feedbacks
View all comments
3 months ago

Could someone help me to set this up please?

Step one: Create a ColorRect
Step two: Add the shader & shader-code to the ColorRect

But where do I add the set_shader_params function?
I tried to add it to the script of the ColorRect itself with no success.