Sharpen the static ice surface

Ridged grain replaces the smooth swells, and two families of fracture lines step the
height, so the refracted sheets break across hard seams instead of drifting. The
height field stays time-independent: only the plasma moves. Grazing rays at a step
are clamped so the sheets never smear off the atlas.
This commit is contained in:
emil28092005
2026-10-30 20:18:28 +03:00
parent 4fce1000f6
commit ff7b09adef
2 changed files with 27 additions and 4 deletions
+26 -3
View File
@@ -24,14 +24,29 @@ float fbm(vec2 p) {
for (int i = 0; i < 3; i++) { sum += amp * noise(p); p = mat2(1.62, 1.17, -1.17, 1.62) * p; amp *= 0.5; }
return sum;
}
float fbm2(vec2 p) {
return 0.5 * noise(p) + 0.25 * noise(mat2(1.62, 1.17, -1.17, 1.62) * p);
}
vec2 atlasUV(vec2 world, float layer) {
vec2 uv = world / (2.0 * EXTENT) + 0.5;
uv = clamp(uv, 0.5 / u_tile_res, 1.0 - 0.5 / u_tile_res); // keep bilinear taps inside the tile
return (vec2(mod(layer, 4.0), floor(layer / 4.0)) + uv) / vec2(4.0, 2.0);
}
// Smooth frozen surface: two octaves, no bubbles, no grain.
// The slab's fracture lines: two families of long, slightly wandering cracks. Shared
// by the height field and the sheen, so each crack is both a bright seam and a step.
vec2 fracture(vec2 x) {
float d = fbm(x * 0.62 + 3.0) - 0.5; // zero set: long winding cracks
float e = fbm(x * 1.35 - 7.0) - 0.5; // a sparser second family
return vec2(d, e);
}
// Frozen surface: fine ridged grain over the plates the cracks have lifted apart.
// Static in world space; only the plasma behind it moves.
float height(vec2 x) {
return 0.15 * fbm(x * 1.3 + 2.0) + 0.05 * fbm(x * 3.7 - 5.0);
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
}
void main() {
vec2 screen = gl_FragCoord.xy / u_res;
@@ -57,7 +72,7 @@ void main() {
vec2 shearR = (refract(ray, normal, 1.0 / (IOR - 0.012)) - inside).xy;
vec2 shearB = (refract(ray, normal, 1.0 / (IOR + 0.016)) - inside).xy;
inside = normalize(inside);
if (inside.z > -0.05) inside = vec3(0.0, 0.0, -1.0);
inside.z = min(inside.z, -0.50); // 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.
@@ -89,6 +104,14 @@ void main() {
float fresnel = pow(1.0 - facing, 5.0);
vec3 sky = mix(vec3(0.004, 0.016, 0.030), vec3(0.075, 0.220, 0.320), normal.y * 0.5 + 0.5);
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;
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));
gl_FragColor = vec4(pow(clamp(col, 0.0, 1.0), vec3(0.4545)), 1.0);
}
+1 -1
View File
File diff suppressed because one or more lines are too long