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;
}
Tags
hot spring, polar, pool, puddle, 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.

More from NekotoArts

Spatial Ice Shader

HQ4X Shader (like in Emulators)

Wind Waker Water – NO Textures needed!

Related shaders

Absorption Based Stylized Water

Pixel Art Water Shader

Toon Water Shader

Subscribe
Notify of
guest

5 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
morningking
morningking
2 years ago

this is great.

baiduwen3
5 months ago

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;
}

jacobibanez
jacobibanez
4 months ago
Reply to  baiduwen3

thanks a lot!

jacobibanez
jacobibanez
4 months ago

How do you achieve that effect? I’m unable to do it 🙁

Gregorio Valle Kattendahl
Gregorio Valle Kattendahl
1 month ago

uniform sampler2D caustics_texture : filter_linear;
uniform sampler2D color_gradient : filter_linear;
uniform sampler2D distort_noise : filter_linear;

(contextual help links are broken 404)
can you publish this 3 ressources, please?