Water Hotspring Exercise
The shader for a little water shader I made and posted on twitter.
I made a written article for the full breakdown of this effect here: Polar Water Breakdown
Keep in mind that this is meant more as a personal shader exercise and a way to present some shader topics, you will very likely need to adapt this to suit your own game.
Shader code
shader_type spatial;
uniform sampler2D caustics_texture : hint_black;
uniform sampler2D color_gradient : hint_albedo;
uniform sampler2D distort_noise : hint_black;
uniform float flow_speed = 0.3;
uniform float vignette_size = 0.3;
uniform float vignette_blend = 0.1;
uniform float distort_strength = 0.1;
uniform float disc_speed = 0.5;
const float TAU = 6.283185307;
vec2 polar_coordinates(vec2 uv, vec2 center, float zoom, float repeat)
{
vec2 dir = uv - center;
highp float radius = length(dir) * 2.0;
highp float angle = atan(dir.y, dir.x) / TAU;
return mod(vec2(radius * zoom, angle * repeat), 1.0);
}
void vertex(){
float dn = texture(distort_noise, UV + TIME * 0.1).r;
VERTEX.y += dn * 0.1;
}
void fragment(){
// Polar UVs + Noise for caustics
vec2 base_uv = UV;
float dn = texture(distort_noise, UV + TIME * 0.1).r;
base_uv += dn * distort_strength;
base_uv -= distort_strength / 2.0;
highp vec2 polar_uv = polar_coordinates(base_uv, vec2(0.5), 1.0, 1.0);
polar_uv.x -= TIME * flow_speed;
float caus = texture(caustics_texture, polar_uv).r;
// Fade out caustics
float cd = distance(UV, vec2(0.5));
float vign = 1.0 - smoothstep(vignette_size, vignette_size + vignette_blend, cd);
// Color the caustics
float grad_uv = caus * vign;
vec3 color = texture(color_gradient, vec2(grad_uv)).rgb;
// Center discs
float global_disc = 0.0;
for (int i = 0; i < 20; i++){
float offset = float(i) * 0.2;
float radius_disc = 0.8;
float loop = fract((TIME + offset) * disc_speed) * radius_disc;
float disc = smoothstep(cd, cd + 0.01, loop);
float fade = abs(loop - radius_disc);
fade = pow(fade, 5.0);
disc *= fade;
disc = clamp(disc, 0.0, 1.0);
global_disc += disc;
}
global_disc *= 0.6;
ALBEDO = color + global_disc;
}
this is great.
godot4.3
shader_type spatial;
uniform sampler2D caustics_texture : hint_default_black;
uniform sampler2D color_gradient : source_color;
uniform sampler2D distort_noise : hint_default_black;
uniform float flow_speed = 0.3;
uniform float vignette_size = 0.3;
uniform float vignette_blend = 0.1;
uniform float distort_strength = 0.1;
uniform float disc_speed = 0.5;
vec2 polar_coordinates(vec2 uv, vec2 center, float zoom, float repeat)
{
vec2 dir = uv – center;
highp float radius = length(dir) * 2.0;
highp float angle = atan(dir.y, dir.x) / TAU;
return mod(vec2(radius * zoom, angle * repeat), 1.0);
}
void vertex(){
float dn = texture(distort_noise, UV + TIME * 0.1).r;
VERTEX.y += dn * 0.1;
}
void fragment(){
// Polar UVs + Noise for caustics
vec2 base_uv = UV;
float dn = texture(distort_noise, UV + TIME * 0.1).r;
base_uv += dn * distort_strength;
base_uv -= distort_strength / 2.0;
highp vec2 polar_uv = polar_coordinates(base_uv, vec2(0.5), 1.0, 1.0);
polar_uv.x -= TIME * flow_speed;
float caus = texture(caustics_texture, polar_uv).r;
// Fade out caustics
float cd = distance(UV, vec2(0.5));
float vign = 1.0 – smoothstep(vignette_size, vignette_size + vignette_blend, cd);
// Color the caustics
float grad_uv = caus * vign;
vec3 color = texture(color_gradient, vec2(grad_uv)).rgb;
// Center discs
float global_disc = 0.0;
for (int i = 0; i < 20; i++){
float offset = float(i) * 0.2;
float radius_disc = 0.8;
float loop = fract((TIME + offset) * disc_speed) * radius_disc;
float disc = smoothstep(cd, cd + 0.01, loop);
float fade = abs(loop – radius_disc);
fade = pow(fade, 5.0);
disc *= fade;
disc = clamp(disc, 0.0, 1.0);
global_disc += disc;
}
global_disc *= 0.6;
ALBEDO = color + global_disc;
}
thanks a lot!
How do you achieve that effect? I’m unable to do it 🙁