Stylized Water Shader

The watershader doesn’t require textures and imported meshes it’s a pretty nice solution for beginners and non-artists like me.

 

Use for the Noise textures Godot’s build in simplex noise

For the normalmap the same, but enable as_normalmap

Shader code
shader_type spatial;
render_mode blend_mix, specular_phong;

uniform float speed : hint_range(-1,1) = 0.0;

//colors
uniform sampler2D noise1; //add Godot noise here
uniform sampler2D noise2; //add Godot noise here
uniform sampler2D normalmap : hint_normal; //add Godot noise here, enable as_normalmap
uniform vec4 color : hint_color;
uniform vec4 edge_color : hint_color;

//foam
uniform float edge_scale = 0.25;
uniform float near = 0.1;
uniform float far = 100f;

//waves
uniform vec2 wave_strengh = vec2(0.5, 0.25);
uniform vec2 wave_frequency = vec2(12.0, 12.0);
uniform vec2 time_factor = vec2(1.0, 2.0);



float rim(float depth){
	depth = 2f * depth - 1f;
	return near * far / (far + depth * (near - far));
}


float waves(vec2 pos, float time){
	return (wave_strengh.y * sin(pos.y * wave_frequency.y + time * time_factor.y)) + (wave_strengh.x * sin(pos.x * wave_frequency.x + time * time_factor.x));
}


void vertex(){
	VERTEX.y += waves(VERTEX.xy, TIME);
}


void fragment(){
	float time = TIME * speed;
	vec3 n1 = texture(noise1, UV + time).rgb;
	vec3 n2 = texture(noise2, UV - time * 0.2).rgb;
	
	vec2 uv_movement = UV * 4f;
	uv_movement += TIME * speed * 4f;
	
	float sum = (n1.r + n2.r) - 1f;
	
	
	float z_depth = rim(texture(DEPTH_TEXTURE, SCREEN_UV).x);
	float z_pos = rim(FRAGCOORD.z);
	float diff = z_depth - z_pos;
	
	vec2 displacement = vec2(sum * 0.05);
	diff += displacement.x * 50f;
	
	
	vec4 col = mix(edge_color, color, step(edge_scale, diff));
	
	vec4 alpha = vec4(1.0);
	alpha = texture(SCREEN_TEXTURE, SCREEN_UV + displacement);
	
	
	float fin = 0.0;
	if (sum > 0.0 && sum < 0.4) fin = 0.1;
	if (sum > 0.4 && sum < 0.8) fin = 0.0;
	if (sum > 0.8) fin = 1f;
	
	ALBEDO = vec3(fin) + mix(alpha.rgb, col.rgb, color.a);
	
	NORMALMAP = texture(normalmap, uv_movement).rgb;
	ROUGHNESS = 0.1;
	SPECULAR = 1f;
}
Tags
3d, stylized, water
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from kmitt91

mesh-terrain blending

Stylized Wings

Related shaders

Stylized Water Shader

Stylized Water with DepthFade

Absorption Based Stylized Water

Subscribe
Notify of
guest

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Vas
Vas
3 years ago

Wow, this is some really nice water!
Thanks! I really like this

kameloov
kameloov
3 years ago

This is really cool, thank you very much.

minoqi
minoqi
1 year ago

For those on Godot 4, here’s the updated version of the code (Tested on 4.1.1)

shader_type spatial;
render_mode blend_mix;

uniform float speed : hint_range(-1,1) = 0.0;
uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, filter_linear_mipmap;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;

//colors
uniform sampler2D noise1; //add Godot noise here
uniform sampler2D noise2; //add Godot noise here
uniform sampler2D normalmap : hint_normal; //add Godot noise here, enable as_normalmap

uniform vec4 color : source_color;
uniform vec4 edge_color : source_color;

//foam
uniform float edge_scale = 0.25;
uniform float near = 0.1;
uniform float far = 100.0f;

//waves
uniform vec2 wave_strengh = vec2(0.5, 0.25);
uniform vec2 wave_frequency = vec2(12.0, 12.0);
uniform vec2 time_factor = vec2(1.0, 2.0);

float rim(float depth){
    depth = 2.0f * depth - 1.0f;
    return near * far / (far + depth * (near - far));
}


float waves(vec2 pos, float time){
    return (wave_strengh.y * sin(pos.y * wave_frequency.y + time * time_factor.y)) + (wave_strengh.x * sin(pos.x * wave_frequency.x + time * time_factor.x));
}


void vertex(){
    VERTEX.y += waves(VERTEX.xy, TIME);
}

void fragment() {
    float time = TIME * speed;
    vec3 n1 = texture(noise1, UV + time).rgb;
    vec3 n2 = texture(noise2, UV - time * 0.2).rgb;
    
    vec2 uv_movement = UV * 4.0f; // scale UV map 4x
    uv_movement += TIME * speed * 4.0f; // moves UV
    
    float sum = (n1.r + n2.r) - 1.0f;
    
    
    float z_depth = rim(texture(DEPTH_TEXTURE, SCREEN_UV).x);
    float z_pos = rim(FRAGCOORD.z);
    float diff = z_depth - z_pos;
    
    vec2 displacement = vec2(sum * 0.05);
    diff += displacement.x * 50.0f;
    
    
    vec4 col = mix(edge_color, color, step(edge_scale, diff));
    
    vec4 alpha = vec4(1.0);
    alpha = texture(SCREEN_TEXTURE, SCREEN_UV + displacement);
    
    
    float fin = 0.0;
    if (sum > 0.0 && sum < 0.4) fin = 0.1;
    if (sum > 0.4 && sum < 0.8) fin = 0.0;
    if (sum > 0.8) fin = 1.0f;
    
    ALBEDO = vec3(fin) + mix(alpha.rgb, col.rgb, color.a);
    
    NORMAL_MAP = texture(normalmap, uv_movement).rgb;
    ROUGHNESS = 0.1;
    SPECULAR = 1.0f;
}