From 9c2eadd98d70b673bba0334e25a8aea0051be9d4 Mon Sep 17 00:00:00 2001 From: pkuzic Date: Sat, 26 Sep 2026 06:00:26 +0100 Subject: [PATCH] MONKEY (visualfix): High cloud detail no longer punches a ring round the glow The erosion weight 4a(1-a) was 0.84 in dense cloud (a = 0.7), so one low base-octave detail cell (~5 degrees) cut a round hole in the mass, and the detail's mean (0.573, not 0.5) lifted the plateau around it: a hard ring near the sun, rimmed by the silver lining. Erosion is now centred on the detail's mean and weighted 6.75a(1-a)^2 (thin edges keep the cauliflower, dense cores keep their shape); thin cloud is not self-shadowed, and the silver lining reads a wider footprint ahead and is capped. Cloud behind the glow is a diffuse brightening again. Co-Authored-By: Claude Opus 5.5 --- crates/benilla-world/src/shaders/cloud.wgsl | 19 ++++++++++++++----- crates/benilla-world/src/shaders/sky_fx.wgsl | 9 ++++++++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/crates/benilla-world/src/shaders/cloud.wgsl b/crates/benilla-world/src/shaders/cloud.wgsl index 36167bea..24697b91 100644 --- a/crates/benilla-world/src/shaders/cloud.wgsl +++ b/crates/benilla-world/src/shaders/cloud.wgsl @@ -32,7 +32,9 @@ fn detailed_cover(uv: vec2, oct: i32) -> f32 { if (a <= 0.0) { return 0.0; } - return sky_fx::cloud_erode(a, sky_fx::cloud_detail(uv, sky_clock.x, oct)); + // MONKEY (visualfix): centred like the pixel's own erosion. + return sky_fx::cloud_erode(a, sky_fx::cloud_detail(uv, sky_clock.x, oct) + 0.5 + - sky_fx::CLOUD_DETAIL_MEAN); } #endif @@ -46,7 +48,9 @@ fn fragment(in: VertexOutput) -> @location(0) vec4 { #ifdef SKY_FX_CLOUDS if (cfx.fx.x >= 1.5) { let n = sky_fx::cloud_detail(in.uv, sky_clock.x, 4); - a = sky_fx::cloud_erode(a, n); + // MONKEY (visualfix): erode about the detail's mean, so High does not add coverage; the + // bias lifted every mid-alpha plateau and drew a ring out of a soft hollow in the tile. + a = sky_fx::cloud_erode(a, n + 0.5 - sky_fx::CLOUD_DETAIL_MEAN); // A painterly tone inside the mass from the same detail. rgb = rgb * (0.93 + 0.14 * n); let strength = cfx.lit.w; @@ -59,9 +63,14 @@ fn fragment(in: VertexOutput) -> @location(0) vec4 { let transmit = exp(-occl * 1.44 * strength); // WarcraftXL's ambient floor 0.55, softened toward the painted texel. let light = 0.62 + 0.38 * transmit; - let ahead = detailed_cover(in.uv + sd * stp * 1.5, 2); - let rim = max(ahead - a, 0.0) * (1.0 - a) * transmit * strength; - rgb = rgb * mix(1.0, light, strength) + cfx.lit.rgb * rim * 0.9; + // MONKEY (visualfix): the silver lining reads a wider footprint ahead and is capped, + // and thin cloud is not self-shadowed: thin cloud before the glow stays a diffuse + // brightening instead of a dark disc inside a bright, rimmed ring. + let ahead = 0.5 * (detailed_cover(in.uv + sd * stp * 1.5, 2) + + detailed_cover(in.uv + sd * stp * 3.0, 2)); + let rim = min(max(ahead - a, 0.0) * (1.0 - a), 0.25) * transmit * strength; + let body = smoothstep(0.25, 0.85, a); + rgb = rgb * mix(1.0, light, strength * body) + cfx.lit.rgb * rim * 0.9; rgb = min(rgb, vec3(1.0)); } } diff --git a/crates/benilla-world/src/shaders/sky_fx.wgsl b/crates/benilla-world/src/shaders/sky_fx.wgsl index e9f8f16c..b239e0c5 100644 --- a/crates/benilla-world/src/shaders/sky_fx.wgsl +++ b/crates/benilla-world/src/shaders/sky_fx.wgsl @@ -291,9 +291,16 @@ fn cloud_detail(uv: vec2, t: f32, octaves: i32) -> f32 { return cloud_billow(p + w * 2.6, octaves); } +// MONKEY (visualfix): the mean of `cloud_detail` (4 octaves; 0.573 measured over 1e6 samples of +// the quintic value noise through `billow`). `cloud_erode` is centred on 0.5. +const CLOUD_DETAIL_MEAN: f32 = 0.573; + // Apply the detail to a base coverage: the edges (mid coverage) are pushed in and out by the // detail, solid cores and clear sky stay put, so the CPU tile still says where cloud is. fn cloud_erode(a: f32, n: f32) -> f32 { - let edge = 4.0 * a * (1.0 - a); + // MONKEY (visualfix): the weight peaks at a = 1/3 (thin edges) and is 0.43 at a = 0.7, where + // 4a(1-a) gave 0.84: one low base-octave cell (~5 degrees) punched a round hole in a dense + // mass, which read as a ring round the glow. + let edge = 6.75 * a * (1.0 - a) * (1.0 - a); return clamp(a + (n - 0.5) * 1.2 * edge, 0.0, 1.0); }