From 366ff3966257d794ca6c95d613fc6a989b05e55a Mon Sep 17 00:00:00 2001 From: emil28092005 Date: Fri, 30 Oct 2026 20:30:03 +0300 Subject: [PATCH] Sharpen the ice: finer ridged grain, hairline seam sheen, more dispersion Normals are now sampled at 0.008 so the creases resolve instead of being averaged away, and the seam sheen only lights the crack walls, which keeps the open water black. Fracture steps are trimmed so the sheets break at a seam instead of smearing into a pale ribbon. --- 7_ice_over.frag | 26 ++++++++++++++------------ ice_plasma.html | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/7_ice_over.frag b/7_ice_over.frag index 3c08843..aa23fb4 100644 --- a/7_ice_over.frag +++ b/7_ice_over.frag @@ -43,10 +43,10 @@ vec2 fracture(vec2 x) { // Static in world space; only the plasma behind it moves. float height(vec2 x) { vec2 fr = fracture(x); - return 0.085 * (1.0 - abs(2.0 * fbm2(x * 1.9 + 2.0) - 1.0)) - + 0.030 * (1.0 - abs(2.0 * fbm2(x * 4.6 - 5.0) - 1.0)) - + 0.020 * clamp(fr.x * 60.0, -1.0, 1.0) // the slab sits at a different level - + 0.012 * clamp(fr.y * 60.0, -1.0, 1.0); // on each side of a crack + return 0.090 * (1.0 - abs(2.0 * fbm2(x * 2.2 + 2.0) - 1.0)) + + 0.055 * (1.0 - abs(2.0 * fbm2(x * 6.4 - 5.0) - 1.0)) + + 0.014 * clamp(fr.x * 110.0, -1.0, 1.0) // the slab sits at a different level + + 0.009 * clamp(fr.y * 110.0, -1.0, 1.0); // on each side of a crack } void main() { vec2 screen = gl_FragCoord.xy / u_res; @@ -59,7 +59,7 @@ void main() { for (int i = 0; i < 2; i++) t = (FRONT + height(ray.xy * t)) / ray.z; vec3 hit = ray * t; - float e = 0.02; + float e = 0.008; vec2 slope = vec2(height(hit.xy + vec2(e, 0.0)) - height(hit.xy - vec2(e, 0.0)), height(hit.xy + vec2(0.0, e)) - height(hit.xy - vec2(0.0, e))) / (2.0 * e); float bevel = smoothstep(0.14, 0.0, min(min(screen.x, 1.0 - screen.x), min(screen.y, 1.0 - screen.y))); @@ -70,9 +70,9 @@ void main() { // Refracted ray; red and blue bend a little differently, which is what makes ice ring. vec3 inside = refract(ray, normal, 1.0 / IOR); vec2 shearR = (refract(ray, normal, 1.0 / (IOR - 0.012)) - inside).xy; - vec2 shearB = (refract(ray, normal, 1.0 / (IOR + 0.016)) - inside).xy; + vec2 shearB = (refract(ray, normal, 1.0 / (IOR + 0.019)) - inside).xy; inside = normalize(inside); - inside.z = min(inside.z, -0.50); // bound grazing rays at the crack steps + inside.z = min(inside.z, -0.40); // bound grazing rays at the crack steps // Recentre the parallax on the middle of the sheet stack: near and far sheets // then slide past each other at different rates as the pointer moves. @@ -106,12 +106,14 @@ void main() { col += sky * (fresnel * 1.2 + bevel * 0.03); // Steep faces of the crests catch a thin sheen: the edge of the frozen surface, // painted only where the ice actually tilts, so the open water stays black. - float tilt = smoothstep(0.45, 0.95, length(slope)); - col += vec3(0.030, 0.085, 0.105) * tilt; + // Only the crack walls are this steep, so this sheen outlines the seams alone + // instead of washing the whole grain. + float tilt = smoothstep(1.00, 2.60, length(slope)); + col += vec3(0.022, 0.062, 0.078) * tilt; vec2 fr = fracture(hit.xy); - float crack = (1.0 - smoothstep(0.0, 0.006, abs(fr.x))) - + (1.0 - smoothstep(0.0, 0.006, abs(fr.y))); - col += vec3(0.020, 0.055, 0.070) * crack * smoothstep(0.58, 0.80, fbm2(hit.xy * 0.30 + 21.0)); + float crack = (1.0 - smoothstep(0.0, 0.004, abs(fr.x))) + + (1.0 - smoothstep(0.0, 0.004, abs(fr.y))); + col += vec3(0.020, 0.055, 0.068) * crack * smoothstep(0.58, 0.80, fbm2(hit.xy * 0.30 + 21.0)); gl_FragColor = vec4(pow(clamp(col, 0.0, 1.0), vec3(0.4545)), 1.0); } diff --git a/ice_plasma.html b/ice_plasma.html index c052e06..7543d0e 100644 --- a/ice_plasma.html +++ b/ice_plasma.html @@ -17,7 +17,7 @@ canvas{display:block;width:100%;height:100%;touch-action:none}