Implementing a Godot 3 Shader (2D Waterfall) into Godot 4

Godot Version

Godot 4.1.2

Question

Hello!
I’m quite new to Godot and wanted to implement a shader made for Godot 3 into Godot 4.
I have no idea how to code shaders, but it kinda works. At least for less than a second.
The shader is a 2D waterfall which uses noise textures for the refraction and gaps in the water. It seems as if the texture ‘runs’ (texture moves down) through the waterfall just fine, but only once. After that the waterfall is frozen.
Ah, I’m bad at explaining…
Can you spot any mistakes in the script or do you know why it just works once?
I used a Sprite2D and did everything just as instructed in the description of the shader. Then I changed hint_color to source_color and added uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;

I’m sorry if I didn’t explain it well enough, I don’t know what I’m doing either…
Thanks for any help!

Original 2D Shader:

Script:

/*
Shader from Godot Shaders - the free shader library.
godotshaders.com/shader/2d-waterfall

Feel free to improve and change this shader according to your needs
and consider sharing the modified result on godotshaders.com.
*/

shader_type canvas_item;

uniform vec2 scale; // Used for sprite script. Don't edit this value in the inspector.
uniform float zoom; // Used for sprite script. Don't edit this value in the inspector.

uniform sampler2D refraction_map;
uniform sampler2D water_mask;
uniform sampler2D screen : hint_screen_texture;

uniform vec2 gap_stretch = vec2(0.8, 0.05);
uniform vec2 refraction_stretch = vec2(2.0, 0.8);
uniform float refraction_strength : hint_range(0.0, 0.1) = 0.02;

uniform vec4 water_tint : source_color = vec4(0.2, 0.6, 1.0, 0.1);
uniform vec4 water_highlight : source_color = vec4(1.0, 1.0, 1.0, 0.3);
uniform float speed = 0.5;
uniform float flow_gaps : hint_range(0.0, 1.0) = 0.33;
uniform float highlight_width : hint_range(0.0, 0.3) = 0.02;

uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;

void fragment()
{
	// Get the two noise textures and make them move on the y axis. The gaps move twice as fast as the refraction, but you can tweak this by changing (speed * 0.5)
	vec2 refraction_offset = texture(refraction_map, vec2(UV.x, UV.y + -TIME * speed * 0.5) * scale * refraction_stretch).xy;
	vec2 gap_mask = texture(water_mask, vec2(UV.x, UV.y + -TIME * speed) * scale * gap_stretch).xy;
	
	// Set values between -0.5 and 0.5 (instead of 0 and 1). Otherwise the reflection will move whith increased refraction_strength
	refraction_offset -= 0.3; 
	
	// Get the screen texture and distort it
	vec4 refraction = texture(SCREEN_TEXTURE, SCREEN_UV - refraction_offset * refraction_strength * zoom);
	
	
	// Create holes and apply colors and textures //
	
	vec4 color = vec4(1.0);
	
	// Define what values will be the water highlight color (the gap border)
	float inner_edge = flow_gaps + highlight_width;
	
	// See if the pixel is within the edges range and use the water colors alpha to blend between showing color or refraction texture.
	if (gap_mask.x < inner_edge)
	{
		color.rgb = mix(refraction.rgb, water_highlight.rgb, water_highlight.a);
	}
	else
	{
		color.rgb = mix(refraction.rgb, water_tint.rgb, water_tint.a);
	}
	
	// If the value is below the gap threshhold make it transparent (a gap)
	if (gap_mask.x < flow_gaps)
	{
		color.a = 0.0;
	}
	
	
	// Crate Edge Shape //
	
	// Set the shape for the top and bottom edges. Use water_mask as shape but with other values to flatten it out horizontally. 
	vec2 water_edge = texture(water_mask, vec2(UV.x, UV.y + -TIME * 0.1) * scale * vec2(0.15, 0.6)).xy;
	water_edge -= 0.5;
	
	// Use the same mask as for the gaps for left and right edge.
	vec2 vertical_edge_mask = gap_mask - 0.5;
	
	// Apply the new masks to the edges. This will make the wobble effect.
	color.a = mix(0.0, color.a, step(UV.x + vertical_edge_mask.x * 0.2, 0.92)); // Right edge
	color.a = mix(color.a, 0.0, step(UV.x - vertical_edge_mask.x * 0.2, 0.08)); // Left edge
	
	color.a = mix(0.0, color.a, step(UV.y + water_edge.y * 0.1, 0.95));  //Bottom edge
	color.a = mix(color.a, 0.0, step(UV.y - water_edge.y * 0.05, 0.05)); //Top edge
	
	COLOR = color;
}

Try adding

repeat_enable

to your refraction map sampler2D, like

uniform sampler2D refraction_map: repeat_enable;

From what I understand, in Godot 4 some of the texture settings were moved to the samplers in the shaders.

2 Likes

Oh my god you’re a legend! It works~
Thank you very much! :two_hearts:

3 Likes

Please can you help me out , im trying to implement the same shader in my game . put i dont quiet understand the script and signal part

If you are in Godot 4+ I think the keyword is @tool

Otherwise,

#Connect the item_rect_changed() signal to this function

means that if that Waterfall script is attached to the ColorRect node, you should be able to go to the Node tab on the top right (next to Inspector) while that is selected, and find the signal listed above and connect it to the function in that Waterfall script.

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.