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 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5854ac39c6
commit
75eb764df4
@@ -21,20 +21,24 @@ fn tap(tex: texture_2d<f32>, uv: vec2<f32>, offset: vec2<f32>) -> vec4<f32> {
|
||||
@fragment
|
||||
fn fs_extract(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
|
||||
// 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)));
|
||||
|
||||
@@ -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<f32>(knee), vec3<f32>(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.
|
||||
|
||||
@@ -1534,7 +1534,13 @@ fn fragment(in: GxVsOut) -> @location(0) vec4<f32> {
|
||||
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<f32> {
|
||||
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<f32>(rgb, 1.0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user