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.
This commit is contained in:
emil28092005
2026-10-30 20:30:03 +03:00
parent ff7b09adef
commit 366ff39662
2 changed files with 15 additions and 13 deletions
+14 -12
View File
@@ -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);
}