Files
frog/assets/shader/painterly_water.gdshader
E250429F 3e857fa9f3 credit
2026-09-17 23:19:43 +02:00

71 lines
3.1 KiB
Plaintext

// painterly_water.gdshader — Godot 4.x
// Flat, gouache-style water for a straight river + cascade.
//
// RIVER preset: uv_scale = vec2(2.0, 6.0), flow_speed = 0.10, wobble = 0.05
// FALL preset: uv_scale = vec2(3.0, 1.0), flow_speed = 0.55, wobble = 0.02,
// edge_foam_top = 0.25, edge_foam_bottom = 0.35, foam_amount = 0.75
// POOL preset: uv_scale = vec2(3.0, 3.0), flow_speed = 0.03, wobble = 0.08
shader_type spatial;
render_mode blend_mix, cull_disabled, diffuse_lambert, specular_disabled, shadows_disabled;
// --- palette: keep it to 3 tones + foam, like mixing real paint ---
uniform vec3 color_deep : source_color = vec3(0.07, 0.26, 0.40);
uniform vec3 color_mid : source_color = vec3(0.16, 0.50, 0.58);
uniform vec3 color_light : source_color = vec3(0.48, 0.79, 0.78);
uniform vec3 color_foam : source_color = vec3(0.95, 0.97, 0.94);
uniform sampler2D noise_a : repeat_enable, filter_linear;
uniform sampler2D noise_b : repeat_enable, filter_linear;
uniform sampler2D canvas : repeat_enable, filter_linear;
uniform vec2 uv_scale = vec2(2.0, 6.0);
uniform vec2 flow_dir = vec2(0.0, 1.0); // +Y = "downstream" along the plane's V axis
uniform float flow_speed = 0.10;
uniform float wobble : hint_range(0.0, 0.25) = 0.05; // brush wander
uniform float bands : hint_range(2.0, 8.0) = 4.0; // fewer = more poster-like
uniform float foam_amount: hint_range(0.0, 1.0) = 0.55;
// foam strips along the top / bottom edge of the mesh (for the lip and the splash base)
uniform float edge_foam_top : hint_range(0.0, 0.6) = 0.0;
uniform float edge_foam_bottom : hint_range(0.0, 0.6) = 0.0;
uniform float canvas_scale = 4.0;
uniform float canvas_strength : hint_range(0.0, 1.0) = 0.25;
void fragment() {
vec2 uv = UV * uv_scale;
vec2 flow = flow_dir * TIME * flow_speed;
// slow low-frequency warp — this is what sells the "hand-painted" wobble
vec2 warp = (texture(noise_b, uv * 0.3 - flow * 0.25).rg - 0.5) * wobble * 2.0;
// two layers at different speeds so the motion never looks like a sliding texture
float n1 = texture(noise_a, uv + warp - flow).r;
float n2 = texture(noise_a, uv * 1.9 + warp.yx - flow * 1.7 + vec2(0.37)).r;
float v = n1 * 0.65 + n2 * 0.35;
// posterize into flat steps — the single most important line here
float q = floor(v * bands) / max(bands - 1.0, 1.0);
// edge foam strips
float top = 1.0 - smoothstep(0.0, max(edge_foam_top, 0.001), UV.y);
float bottom = smoothstep(1.0 - max(edge_foam_bottom, 0.001), 1.0, UV.y);
float edge = clamp(top + bottom, 0.0, 1.0) * step(0.35, v); // let noise break it up
vec3 col = mix(color_deep, color_mid, smoothstep(0.00, 0.50, q));
col = mix(col, color_light, smoothstep(0.50, 0.85, q));
col = mix(col, color_foam, step(1.0 - foam_amount * 0.4, q));
col = mix(col, color_foam, edge);
// canvas grain in screen space so the paper stays put while the water moves
float grain = texture(canvas, SCREEN_UV * canvas_scale).r;
col = mix(col, col * (0.75 + grain * 0.5), canvas_strength);
ALBEDO = col;
ROUGHNESS = 1.0;
SPECULAR = 0.0;
METALLIC = 0.0;
}