MONKEY (post): route emissive materials into HDR
Co-Authored-By: GPT-5.6 Sol (Codex)
This commit is contained in:
co-authored by
GPT-5.6 Sol (Codex)
parent
129ea35f5a
commit
36d03ee462
@@ -24,6 +24,7 @@ behind each constant.
|
||||
| Moon shadows | at night the same shadow rig re-aims at the moon and casts a faint shadow; dims only the night sky term, never point lights | `moonShadowStrength` |
|
||||
| Ground-effect spells | Flamestrike, Rain of Fire, Consecration, Flare and fire traps light the ground for their duration; frost and nature areas stay dark | `spellLightGain` |
|
||||
| Volumetric fog | near-field haze that converges on the zone fog colour (clear within 10 yd, full by 150 yd; mistier at dawn and in bad weather, faint indoors) and sun/moon light shafts through gaps, sampled from the shadow map; own fullscreen pass after the main pass (`benilla-app/src/volumetric_fog.rs`) | Advanced Graphics → Volumetric Fog (Off/Low/High), cvar `volumetricFog`, env `WOW_VOLFOG=0\|1\|2` |
|
||||
| HDR emission and bloom | lit WMO windows, additive models/particles and magma can exceed display white; a soft-capped fullscreen halo is added before the faithful FFX clamp | Advanced Graphics → Bloom (Off/Low/High), cvar `bloom`; Off is the unchanged reference image, suggested High preset value 2 |
|
||||
| Night and interior level | global dimming of the night sky term and of interior ambient | `nightGain`, `interiorGain`, `interiorBakeFloor` |
|
||||
|
||||
Players reach all of it from **Options -> Advanced Graphics** (a Lighting Quality preset Off / Low / Medium / High plus the individual rows; Off is the original client look). The dev build has a panel for all of it: **Ctrl+Shift+D → Lighting & shadows**, with Dim / Default /
|
||||
@@ -35,6 +36,7 @@ is its own module, documented in `WATER.md`.
|
||||
## Where the code lives
|
||||
|
||||
- **Shaders**: `crates/benilla-assets/src/shaders/shadow_hook.wgsl` (shared shadow sampling),
|
||||
`crates/benilla-assets/src/shaders/emissive_hook.wgsl` (shared opt-in HDR multipliers),
|
||||
`crates/benilla-world/src/shaders/torch_depth.wgsl`, and the lighting lanes inside
|
||||
`static_gx.wgsl`, `wow_model.wgsl` and `terrain.wgsl`. The three receivers mirror each other; the
|
||||
comments say where.
|
||||
|
||||
@@ -46,6 +46,7 @@ the technique is listed in the table below. Do not remove either.
|
||||
| Beach surf | a travelling wave front, a lace of foam that dissolves behind it, a swash sheet on the sand | tier |
|
||||
| Swimmers | wake foam, treading rings and a visual-only bob with the swell | tier |
|
||||
| Lava glow | magma surfaces emit warm point lights through the lighting module | Advanced Graphics → Lava Glow, `lavaLightGain` |
|
||||
| Lava HDR | magma partially resists distance fog and feeds the screen-space halo | Advanced Graphics → Bloom, `bloom` (Off/Low/High) |
|
||||
|
||||
Rivers deliberately have NO flow effect: a derived current was tried and removed at the owner's
|
||||
request. If it ever returns it should read the authored MCLQ flow records, not derive one.
|
||||
|
||||
@@ -494,6 +494,8 @@
|
||||
lightingQuality = "Lighting Quality",
|
||||
-- MONKEY (volumetric fog): localised atmospheric quality row.
|
||||
volumetricFog = "Volumetric Fog",
|
||||
-- MONKEY (post): HDR excess + halo quality.
|
||||
bloom = "Bloom",
|
||||
fogOff = "Off",
|
||||
waterQuality = "Water Quality",
|
||||
waterClassic = "Classic",
|
||||
@@ -532,6 +534,9 @@
|
||||
.. "Low, Medium and High use Enhanced water; mirror reflections stay opt-in. "
|
||||
.. "Changing a preset member shows Custom when no preset matches.",
|
||||
-- MONKEY (volumetric fog): explain cost and the shadow-map dependency.
|
||||
-- MONKEY (post): Off guarantees the pre-HDR image.
|
||||
BLOOM =
|
||||
"Makes fire, lava, spells and lit windows carry a soft halo. Low uses a smaller blur chain; High is smoother. Off leaves the original image unchanged.",
|
||||
VOLUMETRIC_FOG =
|
||||
"Off disables volumetric fog. Low adds nearby haze and sun or moon shafts with fewer steps; High uses more steps for smoother shafts. Mist is heavier at dawn and in bad weather, and subtle indoors. Shafts require shadows; with shadows off only haze remains.",
|
||||
WATER_QUALITY =
|
||||
@@ -616,6 +621,8 @@
|
||||
ruRU = {
|
||||
page = "Расширенная графика",
|
||||
lightingQuality = "Качество освещения",
|
||||
-- MONKEY (post): Russian HDR excess + halo quality row.
|
||||
bloom = "Свечение",
|
||||
-- MONKEY (volumetric fog): Russian atmospheric quality row.
|
||||
volumetricFog = "Объёмный туман",
|
||||
fogOff = "Выкл",
|
||||
@@ -657,6 +664,9 @@
|
||||
.. "сохраняют ваши значения. «Низкое», «Среднее» и «Высокое» используют улучшенную воду; "
|
||||
.. "зеркальные отражения включаются отдельно. Изменение настройки набора показывает «Своё», "
|
||||
.. "если ни один набор больше не совпадает.",
|
||||
-- MONKEY (post): localised bloom effect and Off contract.
|
||||
BLOOM =
|
||||
"Добавляет мягкое сияние огню, лаве, заклинаниям и освещённым окнам. Низкое качество использует короткое размытие, высокое — более плавное. Выключение сохраняет исходное изображение.",
|
||||
-- MONKEY (volumetric fog): localised effect and cost explanation.
|
||||
VOLUMETRIC_FOG =
|
||||
"Выкл отключает объёмный туман. Низкое добавляет дымку вблизи и лучи солнца или луны с меньшим числом шагов; Высокое использует больше шагов для более плавных лучей. Туман гуще на рассвете и в непогоду, а в помещениях слабее. Для лучей нужны тени; без теней остаётся только дымка.",
|
||||
@@ -795,7 +805,7 @@
|
||||
-- three of eighteen shadow settings and no hint that the other fifteen existed.
|
||||
AdvancedGraphics = {
|
||||
-- MONKEY (volumetric fog): include in refresh, defaults and search.
|
||||
"RowLightingQuality", "RowWaterQuality", "RowVolumetricFog",
|
||||
"RowLightingQuality", "RowWaterQuality", "RowVolumetricFog", "RowBloom",
|
||||
"RowCharacterShadows", "RowWorldShadows", "RowShadowDistance",
|
||||
"RowShadowResolution", "RowMoonShadows",
|
||||
"RowInteriorLight", "RowInteriorShadows", "RowExteriorShadows", "RowTorchSoft",
|
||||
@@ -2602,11 +2612,28 @@
|
||||
})
|
||||
</OnLoad></Scripts>
|
||||
</Frame>
|
||||
<Frame name="$parentRowCharacterShadows" inherits="OptionsCheckboxRowTemplate">
|
||||
<!-- MONKEY (post): live HDR/bloom tier; Off is the baseline. -->
|
||||
<Frame name="$parentRowBloom" inherits="OptionsDropdownRowTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativeTo="$parentRowVolumetricFog" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-9"/></Offset></Anchor>
|
||||
<Anchor point="TOPRIGHT" relativeTo="$parentRowVolumetricFog" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="0" y="-9"/></Offset></Anchor>
|
||||
</Anchors>
|
||||
<Scripts><OnLoad>
|
||||
OptionsRow_OnLoad(self, "bloom", BENILLA_ADVGFX.bloom,
|
||||
"BENILLA_TOOLTIP_BLOOM")
|
||||
OptionsDropdownRow_Setup(self, {
|
||||
{ text = BENILLA_ADVGFX.fogOff, value = "0" },
|
||||
{ text = BENILLA_ADVGFX.qLow, value = "1" },
|
||||
{ text = BENILLA_ADVGFX.qHigh, value = "2" },
|
||||
})
|
||||
</OnLoad></Scripts>
|
||||
</Frame>
|
||||
<Frame name="$parentRowCharacterShadows" inherits="OptionsCheckboxRowTemplate">
|
||||
<Anchors>
|
||||
<!-- MONKEY (post): bloom is the new row immediately above this one. -->
|
||||
<Anchor point="TOPLEFT" relativeTo="$parentRowBloom" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-9"/></Offset></Anchor>
|
||||
<Anchor point="TOPRIGHT" relativeTo="$parentRowBloom" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="0" y="-9"/></Offset></Anchor>
|
||||
</Anchors>
|
||||
<Scripts><OnLoad>
|
||||
OptionsRow_OnLoad(self, "characterShadows",
|
||||
BENILLA_ADVGFX.characterShadows,
|
||||
|
||||
@@ -921,6 +921,8 @@ pub(crate) const REGISTERED: &[Registered] = &[
|
||||
),
|
||||
// MONKEY (volumetric fog): saved live tier; capture override stays session-only.
|
||||
ours("volumetricFog", "1", "benilla's own: near-field volumetric fog, 0 Off / 1 Low / 2 High"),
|
||||
// MONKEY (post): tier 0 leaves every emissive site and the frame byte-identical.
|
||||
ours("bloom", "0", "benilla's own: HDR emissive bloom, 0 Off / 1 Low / 2 High"),
|
||||
ours(
|
||||
"waterQuality",
|
||||
"1",
|
||||
@@ -2902,6 +2904,8 @@ mod tests {
|
||||
("waterQuality", shadows.water_quality as f32),
|
||||
// MONKEY (volumetric fog): weld registry and renderer defaults.
|
||||
("volumetricFog", shadows.volumetric_fog as f32),
|
||||
// MONKEY (post): weld registry and renderer defaults.
|
||||
("bloom", shadows.bloom as f32),
|
||||
("lavaLightGain", shadows.lava_light_gain),
|
||||
// The two sun lanes and the cascade they share.
|
||||
("worldShadows", flag(shadows.world_shadows)),
|
||||
@@ -3133,6 +3137,8 @@ mod tests {
|
||||
"waterQuality" => video.water_quality as f32,
|
||||
// MONKEY (volumetric fog): verify presets reach the renderer.
|
||||
"volumetricFog" => video.volumetric_fog as f32,
|
||||
// MONKEY (post): the post lane's live tier.
|
||||
"bloom" => video.bloom as f32,
|
||||
"lavaLightGain" => video.lava_light_gain,
|
||||
"fireLightGain" => video.fire_light_gain,
|
||||
"moonShadowStrength" => video.moon_shadow_strength,
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
//!
|
||||
//! Water quality and lava glow use the same guarded bridge into their renderer resources.
|
||||
use benilla_assets::WaterQuality;
|
||||
use benilla_world::lighting::{DynamicInteriors, FireLightGain, LavaLightGain, MoonShadowStrength, SpellLightGain};
|
||||
use benilla_world::lighting::{
|
||||
DynamicInteriors, EmissiveTier, FireLightGain, LavaLightGain, MoonShadowStrength, SpellLightGain,
|
||||
};
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::video::VideoConfig;
|
||||
@@ -60,6 +62,8 @@ fn bridge(
|
||||
mut moon: ResMut<MoonShadowStrength>,
|
||||
mut water: ResMut<WaterQuality>,
|
||||
mut lava: ResMut<LavaLightGain>,
|
||||
// MONKEY (post): bloom also arms the HDR source hooks through the shared light blob.
|
||||
mut emissive: ResMut<EmissiveTier>,
|
||||
) {
|
||||
if water.0 != video.water_quality {
|
||||
water.0 = video.water_quality;
|
||||
@@ -67,6 +71,9 @@ fn bridge(
|
||||
if lava.0 != video.lava_light_gain {
|
||||
lava.0 = video.lava_light_gain;
|
||||
}
|
||||
if emissive.0 != video.bloom {
|
||||
emissive.0 = video.bloom;
|
||||
}
|
||||
if fire.0 != video.fire_light_gain {
|
||||
fire.0 = video.fire_light_gain;
|
||||
}
|
||||
@@ -130,6 +137,7 @@ mod tests {
|
||||
.init_resource::<MoonShadowStrength>()
|
||||
.init_resource::<WaterQuality>()
|
||||
.init_resource::<LavaLightGain>()
|
||||
.init_resource::<EmissiveTier>()
|
||||
.add_plugins(DynamicInteriorPlugin);
|
||||
assert_eq!(app.world().resource::<WaterQuality>().0, VideoConfig::default().water_quality);
|
||||
assert_eq!(app.world().resource::<LavaLightGain>().0, VideoConfig::default().lava_light_gain);
|
||||
|
||||
@@ -222,6 +222,8 @@ pub(crate) struct VideoConfig {
|
||||
pub(crate) water_quality: u8,
|
||||
// MONKEY (volumetric fog): live camera raymarch tier: 0 Off, 1 Low, 2 High.
|
||||
pub(crate) volumetric_fog: u8,
|
||||
// MONKEY (post): emissive HDR + bloom quality, 0 Off / 1 Low / 2 High.
|
||||
pub(crate) bloom: u8,
|
||||
/// Brightness of lava lighting its surroundings, 0..4; 0 disables the glow.
|
||||
/// Published to `benilla_world::lighting::LavaLightGain` by `dynamic_interior::bridge`.
|
||||
pub(crate) lava_light_gain: f32,
|
||||
@@ -467,6 +469,8 @@ impl Default for VideoConfig {
|
||||
water_quality: 1,
|
||||
// MONKEY (volumetric fog): default to the inexpensive atmosphere.
|
||||
volumetric_fog: 1,
|
||||
// MONKEY (post): opt-in; the future High graphics preset selects tier 2.
|
||||
bloom: 0,
|
||||
lava_light_gain: 1.0,
|
||||
fire_flicker: 1.0,
|
||||
display: if windowed_env() {
|
||||
@@ -547,6 +551,8 @@ pub(crate) fn on_cvar(
|
||||
"waterquality" => cfg.water_quality = v.clamp(0.0, 2.0) as u8,
|
||||
// MONKEY (volumetric fog): constrain UI/console writes to supported tiers.
|
||||
"volumetricfog" => cfg.volumetric_fog = v.clamp(0.0, 2.0) as u8,
|
||||
// MONKEY (post): constrain UI/console writes to the supported bloom tiers.
|
||||
"bloom" => cfg.bloom = v.clamp(0.0, 2.0) as u8,
|
||||
"lavalightgain" => cfg.lava_light_gain = v.clamp(0.0, 4.0),
|
||||
"worldshadows" => cfg.world_shadows = ev.flag(),
|
||||
"charactershadows" => cfg.character_shadows = ev.flag(),
|
||||
|
||||
@@ -29,6 +29,8 @@ pub fn register_shaders(app: &mut App) {
|
||||
// (loaded eagerly so `#import benilla::shadow_hook` resolves in terrain/model/static_gx). This is
|
||||
// the ONE place the realtime directional-shadow term lives; the receivers just call into it.
|
||||
load_shader_library!(app, "shaders/shadow_hook.wgsl");
|
||||
// MONKEY (post): shared opt-in HDR multipliers; tier 0 is an exact identity.
|
||||
load_shader_library!(app, "shaders/emissive_hook.wgsl");
|
||||
// MONKEY (enhanced water): the optional water module, `benilla::enhanced_water` (WATER.md).
|
||||
load_shader_library!(app, "shaders/enhanced_water.wgsl");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#define_import_path benilla::emissive_hook
|
||||
|
||||
// MONKEY (post): the opt-in HDR seam shared by windows, additive models/effects and magma.
|
||||
// `light_diffuse.w` was the reference pack's unused clamp marker (always 1); the CPU now adds
|
||||
// the `bloom` tier, so 1 remains a byte-identical Off sentinel without growing the light blob.
|
||||
const EMISSIVE_WMO_WINDOW: u32 = 0u;
|
||||
const EMISSIVE_M2_ADD: u32 = 1u;
|
||||
const EMISSIVE_PARTICLE_ADD: u32 = 2u;
|
||||
const EMISSIVE_MAGMA: u32 = 3u;
|
||||
|
||||
fn tier(packed_lane: f32) -> f32 {
|
||||
return clamp(round(packed_lane - 1.0), 0.0, 2.0);
|
||||
}
|
||||
|
||||
fn emissive_boost(
|
||||
color: vec3<f32>,
|
||||
kind: u32,
|
||||
packed_lane: f32,
|
||||
authored_weight: f32,
|
||||
) -> vec3<f32> {
|
||||
let t = tier(packed_lane);
|
||||
if (t < 0.5) {
|
||||
return color;
|
||||
}
|
||||
let high = step(1.5, t);
|
||||
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));
|
||||
}
|
||||
|
||||
// Distant magma keeps part of its emissive body instead of converging completely to fog.
|
||||
fn magma_fog_resist(packed_lane: f32) -> f32 {
|
||||
let t = tier(packed_lane);
|
||||
return select(0.0, mix(0.32, 0.48, step(1.5, t)), t > 0.5);
|
||||
}
|
||||
@@ -30,6 +30,8 @@
|
||||
}
|
||||
// MONKEY (enhanced water): the optional water module - see enhanced_water.wgsl and WATER.md.
|
||||
#import benilla::enhanced_water::{water_active, water_swell, enhanced_water, WaterFragment}
|
||||
// MONKEY (post): shared tier-gated HDR emission and magma fog resistance.
|
||||
#import benilla::emissive_hook
|
||||
|
||||
@group(#{MATERIAL_BIND_GROUP}) @binding(100) var frames: texture_2d_array<f32>;
|
||||
@group(#{MATERIAL_BIND_GROUP}) @binding(101) var frames_samp: sampler;
|
||||
@@ -227,7 +229,12 @@ fn fragment(in: LiquidVsOut) -> @location(0) vec4<f32> {
|
||||
// Magma/slime: the sheet is the opaque body, unmodulated (the ADT vertex has no colour, the WMO
|
||||
// one is `0xffffffff`) and unlit (lighting off on both paths), but fogged.
|
||||
if (w.kind.x > 0.5) {
|
||||
return vec4<f32>(apply_fog(detail.rgb, in.world_position.xyz, in.room_fog), 1.0);
|
||||
// MONKEY (post): distant magma keeps some authored body and crosses 1.0 for bloom.
|
||||
let fogged = apply_fog(detail.rgb, in.world_position.xyz, in.room_fog);
|
||||
let hot = emissive_hook::emissive_boost(
|
||||
detail.rgb, emissive_hook::EMISSIVE_MAGMA, wow_light.light_diffuse.w, 1.0);
|
||||
return vec4<f32>(mix(fogged, hot,
|
||||
emissive_hook::magma_fog_resist(wow_light.light_diffuse.w)), 1.0);
|
||||
}
|
||||
|
||||
// V, from the authored depth byte CPU-side: clamp(byte/42) on river/lake (LUT `0xc81768`,
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
}
|
||||
// MONKEY (shadow hook): the realtime directional-shadow term (fetch + edge/night fade) lives here.
|
||||
#import benilla::shadow_hook
|
||||
// MONKEY (post): shared tier-gated HDR emission; Off is an exact identity.
|
||||
#import benilla::emissive_hook
|
||||
|
||||
// bevy_pbr 0.18.1's `forward_io::FragmentOutput`. No depth output: a fragment depth write costs
|
||||
// the pipeline early-Z, so the sky lane pins its depth in the vertex stage.
|
||||
@@ -1737,6 +1739,9 @@ fn fragment(in: WowVsOut, @builtin(front_facing) is_front: bool) -> WowFragOut {
|
||||
var out_rgb = rgb;
|
||||
if (is_additive) {
|
||||
out_rgb = out_rgb * faded_alpha;
|
||||
// MONKEY (post): additive M2 cards become HDR before their framebuffer blend stacks them.
|
||||
out_rgb = emissive_hook::emissive_boost(
|
||||
out_rgb, emissive_hook::EMISSIVE_M2_ADD, wow_light.light_diffuse.w, 1.0);
|
||||
}
|
||||
// Mod (bit 7) and Mod2x (bit 8) read no source alpha, so the fade rides the colour as in the
|
||||
// reference: texenv preset 5, `mix(prev.rgb, tex.rgb, prev.a)`, with the primary colour forced
|
||||
|
||||
@@ -474,6 +474,11 @@ impl Default for FireLightGain {
|
||||
}
|
||||
}
|
||||
|
||||
/// MONKEY (post): live `bloom` tier. The packer adds it to `light_diffuse.w`, whose old value 1
|
||||
/// was an unread clamp marker, so the 8528-byte shared buffer and every existing decode stay put.
|
||||
#[derive(Resource, Clone, Copy, Default, PartialEq, Eq, Debug)]
|
||||
pub struct EmissiveTier(pub u8);
|
||||
|
||||
/// MONKEY (spellLightGain): marks a `PointLight` that a SPELL EFFECT invented — a kit's aura glow,
|
||||
/// a missile's core, an impact flash, a firework shell's burst. The app's own
|
||||
/// `entities::spell_fx::SpellLight` carries the envelope, the mode and the budget; this is the
|
||||
@@ -641,6 +646,8 @@ pub(super) fn register(app: &mut App) {
|
||||
.init_resource::<DynamicInteriors>()
|
||||
// MONKEY (fire GO lights): the live gain on synthesised fire lights.
|
||||
.init_resource::<FireLightGain>()
|
||||
// MONKEY (post): opt-in HDR emission, packed into an existing float lane.
|
||||
.init_resource::<EmissiveTier>()
|
||||
// MONKEY (spellLightGain): and the one on spell-effect lights, which overrides it.
|
||||
.init_resource::<SpellLightGain>()
|
||||
.init_resource::<super::prop_probes::PropProbeExtract>()
|
||||
@@ -1286,6 +1293,8 @@ fn build_light_data(
|
||||
shadow: ShadowLanes,
|
||||
// MONKEY (dynamic interiors): the interior lane's on/off + live knobs, packed for `static_gx.wgsl`.
|
||||
dynamic_interiors: Res<DynamicInteriors>,
|
||||
// MONKEY (post): the 0/1/2 tier rides the unused `light_diffuse.w` marker.
|
||||
emissive: Res<EmissiveTier>,
|
||||
// MONKEY (fire GO lights): the live gain on synthesised fire lights (0 = the lane off).
|
||||
fire_gain: Res<FireLightGain>,
|
||||
// MONKEY (spellLightGain): and the spell lane's own, which overrides it on a spell row.
|
||||
@@ -1353,6 +1362,8 @@ fn build_light_data(
|
||||
// this packs (rows 0/1, the SH block, the sun's DC redistribution) is LINEAR in that triple, so
|
||||
// one multiply at the input dims all of them consistently and no derived row can be missed.
|
||||
pack_model_core_rows(rows, night_dim(l.ambient), night_dim(l.diffuse), l.sun_dir);
|
||||
// MONKEY (post): old value 1 remains tier Off; no existing shader consumes this marker.
|
||||
rows[1][3] = 1.0 + emissive.0.min(2) as f32;
|
||||
// MONKEY (world shadows): pack the world-shadow lane flag into the free `sh_c16.w` lane. The
|
||||
// MCSH terrain-shadow suppression in `terrain.wgsl` keys on THIS — not on the mere presence of
|
||||
// a shadow sun — so character-only shadows (sun present, world lane off) keep the baked MCSH.
|
||||
@@ -2037,6 +2048,8 @@ mod tests {
|
||||
.init_resource::<ShadowHandover>()
|
||||
.init_resource::<DynamicInteriors>()
|
||||
.init_resource::<FireLightGain>()
|
||||
// MONKEY (post): the packer reads the live HDR tier too.
|
||||
.init_resource::<EmissiveTier>()
|
||||
.init_resource::<SpellLightGain>()
|
||||
.add_systems(Update, build_light_data);
|
||||
app.world_mut()
|
||||
|
||||
@@ -51,6 +51,8 @@ pub use global_light::WorldPointLight;
|
||||
// MONKEY (spellLightGain): the spell lane's marker + its live gain — the two-word world-side
|
||||
// shadow of benilla-app's own `SpellLight` lifecycle, and the dial the packer folds over it.
|
||||
pub use global_light::{SpellFxLight, SpellLightGain};
|
||||
// MONKEY (post): live 0/1/2 emissive tier packed without growing the shared light blob.
|
||||
pub use global_light::EmissiveTier;
|
||||
pub use global_light::{
|
||||
room_claim_bytes, CLAIM_EXT_OK, LIT_ROOM_EXT_DENY, ROOM_CLAIM_MAX, ROOM_CLAIM_STRIDE,
|
||||
};
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
}
|
||||
// MONKEY (shadow hook): the realtime directional-shadow term (fetch + edge/night fade) lives here.
|
||||
#import benilla::shadow_hook
|
||||
// MONKEY (post): shared tier-gated HDR emission; Off is an exact identity.
|
||||
#import benilla::emissive_hook
|
||||
|
||||
// Group 0 is Bevy's standard mesh-view bind group (view matrices, directional-light records and
|
||||
// the shadow textures the retained pass reads).
|
||||
@@ -1980,6 +1982,12 @@ fn fragment(in: GxVsOut) -> @location(0) vec4<f32> {
|
||||
let factor = clamp((fog_span.y - eye_z) / denom, 0.0, 1.0);
|
||||
rgb = mix(fog_color.xyz, rgb, factor);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
// Gamma-space output; alpha pinned 1.0, every draw here is opaque.
|
||||
return vec4<f32>(rgb, 1.0);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
// - BLEND_MOD2X: (rgb, 1) under (Dst, Src) = `2·src·dst`, rain's state; reads no alpha.
|
||||
|
||||
#import bevy_render::view::View
|
||||
// MONKEY (post): shared tier-gated HDR emission; Off is an exact identity.
|
||||
#import benilla::emissive_hook
|
||||
|
||||
// Prefix of `lighting::global_light`'s buffer; keep in sync with wow_model.wgsl's copy.
|
||||
struct WowLight {
|
||||
@@ -160,7 +162,9 @@ fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
}
|
||||
#ifdef BLEND_ADD
|
||||
// Premultiplied in gamma, so stacked quads sum like the reference's bytes.
|
||||
return vec4<f32>(rgb * c.a, 0.0);
|
||||
// MONKEY (post): boost before the additive framebuffer blend, never after the stack.
|
||||
return vec4<f32>(emissive_hook::emissive_boost(
|
||||
rgb * c.a, emissive_hook::EMISSIVE_PARTICLE_ADD, wow_light.light_diffuse.w, 1.0), 0.0);
|
||||
#else
|
||||
#ifdef BLEND_OPAQUE
|
||||
return vec4<f32>(rgb, 1.0);
|
||||
|
||||
Reference in New Issue
Block a user