From 76cee36b2c2639d5f6fcf95cd735e8f9d6ac74c1 Mon Sep 17 00:00:00 2001
From: pkuzic
Date: Fri, 25 Sep 2026 16:55:55 +0100
Subject: [PATCH] MONKEY (fix-post): bloom keeps the base image; window gain on
the light term only
Review P4: emissive_boost now lifts only above a 0.6 knee (equal to the old
gain at 1.0), so additive spells and lava keep their look and the excess feeds
the bloom. Review P3: the window gain applies to static_gx's SIDN light term
before fog, not to the whole fogged batch. Review P6: Low-tier extract taps
scale with the quarter-size target. Review P7: excess capped at 64 (no NaN).
Co-Authored-By: Claude Opus 5.5
---
crates/benilla-app/src/post/bloom.wgsl | 30 +++++++++++--------
.../src/shaders/emissive_hook.wgsl | 11 ++++++-
.../benilla-world/src/shaders/static_gx.wgsl | 16 +++++-----
3 files changed, 36 insertions(+), 21 deletions(-)
diff --git a/crates/benilla-app/src/post/bloom.wgsl b/crates/benilla-app/src/post/bloom.wgsl
index 7313a1d4..98cc1681 100644
--- a/crates/benilla-app/src/post/bloom.wgsl
+++ b/crates/benilla-app/src/post/bloom.wgsl
@@ -21,20 +21,24 @@ fn tap(tex: texture_2d, uv: vec2, offset: vec2) -> vec4 {
@fragment
fn fs_extract(in: FullscreenVertexOutput) -> @location(0) vec4 {
// 13-tap downfilter: a broad, stable footprint when Low uses a quarter-size target.
+ // MONKEY (fix-post): the footprint scales with the target divisor (Low = quarter size, so
+ // 2x offsets), else 16 source pixels fed each output from a 5x5 area and thin sparks shimmered.
+ let spread = select(1.0, 2.0, bloom.tier < 1.5);
var c = tap(source_tex, in.uv, vec2(0.0)) * 0.20;
- c += tap(source_tex, in.uv, vec2( 1.0, 0.0)) * 0.10;
- c += tap(source_tex, in.uv, vec2(-1.0, 0.0)) * 0.10;
- c += tap(source_tex, in.uv, vec2( 0.0, 1.0)) * 0.10;
- c += tap(source_tex, in.uv, vec2( 0.0, -1.0)) * 0.10;
- c += tap(source_tex, in.uv, vec2( 1.0, 1.0)) * 0.06;
- c += tap(source_tex, in.uv, vec2(-1.0, 1.0)) * 0.06;
- c += tap(source_tex, in.uv, vec2( 1.0, -1.0)) * 0.06;
- c += tap(source_tex, in.uv, vec2(-1.0, -1.0)) * 0.06;
- c += tap(source_tex, in.uv, vec2( 2.0, 0.0)) * 0.04;
- c += tap(source_tex, in.uv, vec2(-2.0, 0.0)) * 0.04;
- c += tap(source_tex, in.uv, vec2( 0.0, 2.0)) * 0.04;
- c += tap(source_tex, in.uv, vec2( 0.0, -2.0)) * 0.04;
- let excess = max(c.rgb - vec3(1.0), vec3(0.0));
+ c += tap(source_tex, in.uv, vec2( 1.0, 0.0) * spread) * 0.10;
+ c += tap(source_tex, in.uv, vec2(-1.0, 0.0) * spread) * 0.10;
+ c += tap(source_tex, in.uv, vec2( 0.0, 1.0) * spread) * 0.10;
+ c += tap(source_tex, in.uv, vec2( 0.0, -1.0) * spread) * 0.10;
+ c += tap(source_tex, in.uv, vec2( 1.0, 1.0) * spread) * 0.06;
+ c += tap(source_tex, in.uv, vec2(-1.0, 1.0) * spread) * 0.06;
+ c += tap(source_tex, in.uv, vec2( 1.0, -1.0) * spread) * 0.06;
+ c += tap(source_tex, in.uv, vec2(-1.0, -1.0) * spread) * 0.06;
+ c += tap(source_tex, in.uv, vec2( 2.0, 0.0) * spread) * 0.04;
+ c += tap(source_tex, in.uv, vec2(-2.0, 0.0) * spread) * 0.04;
+ c += tap(source_tex, in.uv, vec2( 0.0, 2.0) * spread) * 0.04;
+ c += tap(source_tex, in.uv, vec2( 0.0, -2.0) * spread) * 0.04;
+ // MONKEY (fix-post): cap the excess so a +inf pixel cannot become an inf/inf NaN halo.
+ let excess = min(max(c.rgb - vec3(1.0), vec3(0.0)), vec3(64.0));
let knee = excess * excess / (excess + vec3(0.50));
// Frost-Nova/firework stacks can reach 5-10x; compress them without hard clipping.
let capped = vec3(5.0) * (vec3(1.0) - exp(-knee / vec3(5.0)));
diff --git a/crates/benilla-assets/src/shaders/emissive_hook.wgsl b/crates/benilla-assets/src/shaders/emissive_hook.wgsl
index 8668b08d..90c3c720 100644
--- a/crates/benilla-assets/src/shaders/emissive_hook.wgsl
+++ b/crates/benilla-assets/src/shaders/emissive_hook.wgsl
@@ -26,7 +26,16 @@ fn emissive_boost(
var gain = mix(1.45, 1.85, high);
if (kind == EMISSIVE_WMO_WINDOW) { gain = mix(1.70, 2.35, high); }
if (kind == EMISSIVE_MAGMA) { gain = mix(1.80, 2.60, high); }
- return color * mix(1.0, gain, clamp(authored_weight, 0.0, 1.0));
+ // MONKEY (fix-post): boost only above a knee, so the base image keeps its look (below 0.6
+ // untouched) and the excess goes to the bloom extract; at 1.0 the result equals the old gain.
+ // A flat multiply saturated every additive spell and the lava to white once the combine clamps.
+ // A window's gain is applied to its emissive light term alone (static_gx), so it stays flat.
+ if (kind == EMISSIVE_WMO_WINDOW) {
+ return color * mix(1.0, gain, clamp(authored_weight, 0.0, 1.0));
+ }
+ let knee = 0.6;
+ let over = max(color - vec3(knee), vec3(0.0));
+ return color + over * ((gain - 1.0) * clamp(authored_weight, 0.0, 1.0) / (1.0 - knee));
}
// Distant magma keeps part of its emissive body instead of converging completely to fog.
diff --git a/crates/benilla-world/src/shaders/static_gx.wgsl b/crates/benilla-world/src/shaders/static_gx.wgsl
index dba4e6bb..ad217a91 100644
--- a/crates/benilla-world/src/shaders/static_gx.wgsl
+++ b/crates/benilla-world/src/shaders/static_gx.wgsl
@@ -1534,7 +1534,13 @@ fn fragment(in: GxVsOut) -> @location(0) vec4 {
sidn_w = 0.0;
}
}
- let sidn_e = sidn_rgb * (wow_light.grade.x * sidn_w);
+ var sidn_e = sidn_rgb * (wow_light.grade.x * sidn_w);
+ // MONKEY (fix-post): the bloom window gain lifts only this light term, before fog (it used
+ // to multiply the whole fogged batch, so fogged buildings glowed as fog x 2.35 at night).
+ if ((in.word & WORD_WINDOW) != 0u) {
+ sidn_e = emissive_hook::emissive_boost(
+ sidn_e, emissive_hook::EMISSIVE_WMO_WINDOW, wow_light.light_diffuse.w, 1.0);
+ }
// MONKEY (ext-class night law): plenty of geometry INSIDE a building is authored
// EXTERIOR-class — the Goldshire inn's whole 57.7 yd shell is one group (`upstairs`,
// MOGP 0x0a09, and it holds the stair down to the cellar), its east stairwell annex is
@@ -2009,12 +2015,8 @@ fn fragment(in: GxVsOut) -> @location(0) vec4 {
rgb = fog_hook::apply_fog(rgb, fog_color.xyz, fog_span, eye_z, in.world_position.xyz,
view.world_position, true, wow_light.monkey);
}
- // MONKEY (post): SIDN/window batches cross 1.0 only at night and when bloom is armed.
- if ((in.word & WORD_WINDOW) != 0u) {
- rgb = emissive_hook::emissive_boost(
- rgb, emissive_hook::EMISSIVE_WMO_WINDOW, wow_light.light_diffuse.w,
- wow_light.grade.x);
- }
+ // MONKEY (post): SIDN/window light crosses 1.0 only at night and when bloom is armed; the
+ // gain is applied to `sidn_e` above (MONKEY fix-post).
// Gamma-space output; alpha pinned 1.0, every draw here is opaque.
return vec4(rgb, 1.0);
}