2026-05-20 15:03:47 -04:00
|
|
|
|
shader_type canvas_item;
|
|
|
|
|
|
|
2026-05-20 15:41:26 -04:00
|
|
|
|
// --- Fill control ---
|
2026-05-20 15:03:47 -04:00
|
|
|
|
uniform float fill : hint_range(0.0, 1.0) = 0.0;
|
|
|
|
|
|
uniform vec4 bg_color : source_color = vec4(0.08, 0.08, 0.12, 1.0);
|
|
|
|
|
|
uniform vec4 border_color : source_color = vec4(0.2, 0.2, 0.28, 1.0);
|
2026-05-20 15:41:26 -04:00
|
|
|
|
uniform float corner_radius : hint_range(0.0, 0.5) = 0.05;
|
2026-05-20 15:03:47 -04:00
|
|
|
|
uniform float border_width : hint_range(0.0, 0.1) = 0.008;
|
|
|
|
|
|
uniform float wave_amp : hint_range(0.0, 0.05) = 0.012;
|
|
|
|
|
|
uniform float wave_freq : hint_range(0.0, 15.0) = 4.0;
|
|
|
|
|
|
|
2026-05-20 15:41:26 -04:00
|
|
|
|
// --- Liquid base color (modulated by effects below) ---
|
|
|
|
|
|
uniform vec4 liquid_color : source_color = vec4(0.2, 0.5, 0.8, 1.0);
|
|
|
|
|
|
|
|
|
|
|
|
// --- Animation controls ---
|
|
|
|
|
|
uniform float time_factor : hint_range(0.0, 5.0) = 1.0;
|
|
|
|
|
|
uniform float wave_strength : hint_range(0.0, 0.5) = 0.05;
|
|
|
|
|
|
uniform float ripple_speed : hint_range(0.0, 5.0) = 1.0;
|
|
|
|
|
|
|
|
|
|
|
|
// --- Glow / edge ---
|
|
|
|
|
|
uniform vec4 edge_color : source_color = vec4(0.3, 0.6, 1.0, 1.0);
|
|
|
|
|
|
uniform float glow_intensity : hint_range(0.0, 5.0) = 1.5;
|
|
|
|
|
|
uniform float edge_pulse : hint_range(0.0, 2.0) = 1.0;
|
|
|
|
|
|
|
|
|
|
|
|
// --- Distortion ---
|
|
|
|
|
|
uniform sampler2D noise_tex : repeat_enable;
|
|
|
|
|
|
uniform float noise_scale : hint_range(0.0, 5.0) = 1.0;
|
2026-05-20 21:37:07 -04:00
|
|
|
|
uniform vec2 noise_module_size = vec2(300.0, 240.0);
|
2026-05-20 15:41:26 -04:00
|
|
|
|
uniform float swirl_strength : hint_range(-2.0, 2.0) = 0.5;
|
|
|
|
|
|
uniform float hue_shift_speed : hint_range(0.0, 5.0) = 0.0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ---------- helpers ----------
|
|
|
|
|
|
|
|
|
|
|
|
vec3 rgb2hsv(vec3 c) {
|
|
|
|
|
|
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
|
|
|
|
|
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
|
|
|
|
|
|
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
|
|
|
|
|
|
float d = q.x - min(q.w, q.y);
|
|
|
|
|
|
float e = 1e-10;
|
|
|
|
|
|
return vec3(abs((q.w - q.y) / (6.0 * d + e) + q.z), d / (q.x + e), q.x);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vec3 hsv2rgb(vec3 c) {
|
|
|
|
|
|
vec3 p = abs(fract(c.xxx + vec3(0.0, 1.0 / 3.0, 2.0 / 3.0)) * 6.0 - 3.0);
|
|
|
|
|
|
return c.z * mix(vec3(1.0), clamp(p - 1.0, 0.0, 1.0), c.y);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vec2 get_swirl_uv(vec2 uv, float strength) {
|
|
|
|
|
|
vec2 center = vec2(0.5);
|
|
|
|
|
|
vec2 diff = uv - center;
|
|
|
|
|
|
float dist = length(diff);
|
|
|
|
|
|
float angle = atan(diff.y, diff.x) + strength * (0.5 - dist) * sin(TIME * 0.5);
|
|
|
|
|
|
return center + vec2(cos(angle), sin(angle)) * dist;
|
|
|
|
|
|
}
|
2026-05-20 15:03:47 -04:00
|
|
|
|
|
|
|
|
|
|
float rr_sdf(vec2 p, vec2 half_size, float r) {
|
|
|
|
|
|
vec2 d = abs(p) - half_size + r;
|
|
|
|
|
|
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - r;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-20 15:41:26 -04:00
|
|
|
|
// ---------- main ----------
|
|
|
|
|
|
|
2026-05-20 15:03:47 -04:00
|
|
|
|
void fragment() {
|
|
|
|
|
|
vec2 half_size = vec2(0.5, 0.5);
|
|
|
|
|
|
vec2 uv_centered = UV - half_size;
|
2026-05-20 15:41:26 -04:00
|
|
|
|
float t = TIME * time_factor;
|
2026-05-20 15:03:47 -04:00
|
|
|
|
|
2026-05-20 15:41:26 -04:00
|
|
|
|
// --- rounded-rect mask ---
|
2026-05-20 15:03:47 -04:00
|
|
|
|
float max_r = min(corner_radius, half_size.x);
|
|
|
|
|
|
float outer_d = rr_sdf(uv_centered, half_size, max_r);
|
|
|
|
|
|
float outer = 1.0 - smoothstep(0.0, max(0.001, fwidth(outer_d)), max(outer_d, 0.0));
|
|
|
|
|
|
|
|
|
|
|
|
float inner_r = max(0.0, max_r - border_width);
|
|
|
|
|
|
float inner_hw = max(0.0, half_size.x - border_width);
|
|
|
|
|
|
float inner_hh = max(0.0, half_size.y - border_width);
|
|
|
|
|
|
float inner_d = rr_sdf(uv_centered, vec2(inner_hw, inner_hh), inner_r);
|
|
|
|
|
|
float inner = 1.0 - smoothstep(0.0, max(0.001, fwidth(inner_d)), max(inner_d, 0.0));
|
|
|
|
|
|
|
2026-05-20 15:41:26 -04:00
|
|
|
|
// --- liquid fill line (sum-of-sines + edge damping) ---
|
|
|
|
|
|
float wf = wave_freq * 6.283;
|
|
|
|
|
|
float w1 = sin(UV.x * wf + TIME * 5.0);
|
|
|
|
|
|
float w2 = sin(UV.x * wf * 1.7 + TIME * 7.0 + 1.3) * 0.5;
|
|
|
|
|
|
float w3 = sin(UV.x * wf * 0.6 + TIME * 2.5 + 2.9) * 0.3;
|
|
|
|
|
|
float wave_sum = (w1 + w2 + w3) / 1.8;
|
|
|
|
|
|
|
|
|
|
|
|
// damp wave near left/right walls for meniscus effect
|
|
|
|
|
|
float edge_damp = smoothstep(0.0, 0.08, UV.x) * smoothstep(0.0, 0.08, 1.0 - UV.x);
|
|
|
|
|
|
wave_sum *= edge_damp;
|
|
|
|
|
|
|
|
|
|
|
|
float fill_line = 1.0 - fill + wave_sum * wave_amp;
|
2026-05-20 15:07:42 -04:00
|
|
|
|
float liquid = smoothstep(fill_line - 0.001, fill_line + 0.001, UV.y);
|
2026-05-20 15:03:47 -04:00
|
|
|
|
liquid *= inner;
|
|
|
|
|
|
|
2026-05-20 15:41:26 -04:00
|
|
|
|
// --- build effect colour for the liquid region ---
|
|
|
|
|
|
vec2 uv = UV;
|
2026-05-20 21:37:07 -04:00
|
|
|
|
// Pixel-space noise coordinate: same pixel distance = same noise delta,
|
|
|
|
|
|
// keeping the pattern fixed-size regardless of module aspect or window size.
|
|
|
|
|
|
// The 100.0 constant matches the noise texture size (100×100).
|
|
|
|
|
|
vec2 noise_uv = uv * noise_module_size / 100.0 * noise_scale + t * 0.05;
|
|
|
|
|
|
float noise_val = texture(noise_tex, noise_uv).r;
|
2026-05-20 15:41:26 -04:00
|
|
|
|
|
|
|
|
|
|
// wave distortion
|
|
|
|
|
|
uv.y += sin(uv.x * 10.0 + t) * wave_strength * noise_val;
|
|
|
|
|
|
uv.x += cos(uv.y * 10.0 + t * 0.5) * wave_strength * noise_val;
|
|
|
|
|
|
|
|
|
|
|
|
// ripple rings
|
|
|
|
|
|
float dist_center = distance(uv, vec2(0.5));
|
|
|
|
|
|
uv += sin(dist_center * 20.0 - t * ripple_speed) * (wave_strength * 0.5 * noise_val);
|
2026-05-20 15:03:47 -04:00
|
|
|
|
|
2026-05-20 15:41:26 -04:00
|
|
|
|
// swirl
|
|
|
|
|
|
uv = get_swirl_uv(uv, swirl_strength);
|
|
|
|
|
|
|
|
|
|
|
|
// sample the ColorRect texture (water image if assigned, else 1x1 white)
|
|
|
|
|
|
vec4 tex = texture(TEXTURE, uv);
|
|
|
|
|
|
|
|
|
|
|
|
// hue-shift the base liquid colour, modulated by the texture
|
|
|
|
|
|
vec3 base_rgb = tex.rgb * liquid_color.rgb;
|
|
|
|
|
|
vec3 hsv = rgb2hsv(base_rgb);
|
|
|
|
|
|
hsv.x = fract(hsv.x + t * 0.1 * hue_shift_speed);
|
|
|
|
|
|
hsv.y = clamp(hsv.y + 0.2 * noise_val, 0.0, 1.0);
|
|
|
|
|
|
vec3 effect_rgb = hsv2rgb(hsv);
|
|
|
|
|
|
|
|
|
|
|
|
// top-down lighting — subtle brightening at the very top
|
|
|
|
|
|
float top_light = smoothstep(0.0, 0.3, 1.0 - UV.y);
|
|
|
|
|
|
effect_rgb *= 1.0 + top_light * 0.2;
|
|
|
|
|
|
|
|
|
|
|
|
// overall pulse
|
|
|
|
|
|
float pulse = 0.8 + 0.2 * sin(t);
|
|
|
|
|
|
effect_rgb *= (glow_intensity * pulse);
|
|
|
|
|
|
|
|
|
|
|
|
// tiny sparkle
|
|
|
|
|
|
effect_rgb += 0.03 * vec3(sin(t * 3.0), cos(t * 2.0), noise_val * 0.1);
|
|
|
|
|
|
|
2026-05-20 16:18:33 -04:00
|
|
|
|
// --- 3D water surface ---
|
|
|
|
|
|
float d_surf = UV.y - fill_line; // positive = below surface
|
|
|
|
|
|
float d_abs = abs(d_surf);
|
|
|
|
|
|
|
|
|
|
|
|
// subsurface light scatter — brightest just below surface, fades with depth
|
|
|
|
|
|
float subsurface = exp(-d_surf * 25.0) * step(0.0, d_surf);
|
|
|
|
|
|
effect_rgb *= 1.0 + subsurface * 0.25;
|
|
|
|
|
|
|
2026-05-20 15:41:26 -04:00
|
|
|
|
// --- composite ---
|
|
|
|
|
|
vec3 col = bg_color.rgb;
|
|
|
|
|
|
col = mix(col, effect_rgb, liquid);
|
2026-05-20 15:03:47 -04:00
|
|
|
|
|
2026-05-20 16:18:33 -04:00
|
|
|
|
// foam glow — smooth double-sided falloff (gaussian-like)
|
|
|
|
|
|
float foam_glow = exp(-d_abs * 70.0);
|
|
|
|
|
|
float foam_core = exp(-d_abs * 350.0);
|
|
|
|
|
|
vec3 foam_tint = vec3(0.6, 0.75, 0.95);
|
|
|
|
|
|
col += foam_glow * foam_tint * 0.5;
|
|
|
|
|
|
col += foam_core * vec3(0.75, 0.9, 1.0) * 0.6;
|
|
|
|
|
|
|
|
|
|
|
|
// wave-slope highlight — brightens at wave crests facing the viewer
|
|
|
|
|
|
float wave_slope = (cos(UV.x * wf + TIME * 5.0) * wf
|
|
|
|
|
|
+ cos(UV.x * wf * 1.7 + TIME * 7.0 + 1.3) * wf * 1.7 * 0.5
|
|
|
|
|
|
+ cos(UV.x * wf * 0.6 + TIME * 2.5 + 2.9) * wf * 0.6 * 0.3) * edge_damp / 1.8 * wave_amp;
|
|
|
|
|
|
float slope_highlight = max(0.0, wave_slope) * exp(-d_abs * 200.0);
|
|
|
|
|
|
col += slope_highlight * vec3(0.6, 0.8, 1.0) * 0.4;
|
2026-05-20 15:03:47 -04:00
|
|
|
|
|
2026-05-20 15:41:26 -04:00
|
|
|
|
// border
|
2026-05-20 15:03:47 -04:00
|
|
|
|
col = mix(col, border_color.rgb, outer - inner);
|
|
|
|
|
|
|
|
|
|
|
|
COLOR = vec4(col, outer);
|
|
|
|
|
|
}
|