From 72dd5a0ce8d317ebd3d5f402c94061ad19fc5c8a Mon Sep 17 00:00:00 2001
From: pkuzic
Date: Sat, 26 Sep 2026 15:55:15 +0100
Subject: [PATCH] MONKEY (leftovers): LightSkybox flags 0x8/0x10 plumbing; 0x10
suppresses the Modern sun-fog lobe
SKYBOX_FORCE_SUN_SHAFTS (0x8) and SKYBOX_NO_SUN_FOG (0x10) constants, CameraSkybox::flag_weight
(heaviest main layer carrying a flag). update_fog_model scales sun_fog_strength by 1 - weight of a
0x10 sky. LIGHTING.md documents both flags (0x8 consumer lands in the next commit).
Co-Authored-By: Claude Opus 5.5
---
LIGHTING.md | 2 +-
crates/benilla-formats/src/lib.rs | 6 +++-
crates/benilla-formats/src/light.rs | 6 +++-
crates/benilla-formats/src/light/skybox.rs | 4 +++
.../benilla-world/src/lighting/fog_model.rs | 5 ++++
crates/benilla-world/src/skybox.rs | 28 +++++++++++++++++++
6 files changed, 48 insertions(+), 3 deletions(-)
diff --git a/LIGHTING.md b/LIGHTING.md
index 651e4aa7..7a182968 100644
--- a/LIGHTING.md
+++ b/LIGHTING.md
@@ -35,7 +35,7 @@ behind each constant.
| Ambient occlusion | soft contact shadows under props, in wall-floor corners and around feet; depth-only SSAO at half resolution (depth-reconstructed normals, 6/12 spiral taps, 4x4 depth-aware blur, bilateral upsample) multiplied into the opaque scene after the opaque pass and before the water copy, so water, particles and UI are untouched; fades out 45-90 yd (Low) / 60-120 yd (High), spares sky and bright pixels; on alpha-tested foliage (a dense window of two-sided depth spikes) the blur widens its depth tolerance and the AO drops 40 %, which removes the leaf grain while planes, silhouettes and contact creases keep full AO (`benilla-app/src/ssao.rs`, `benilla-app/src/shaders/ssao.wgsl`) | Advanced Graphics → Ambient Occlusion (Off/Low/High; default Off, High preset 2), cvar `ambientOcclusion`, env `WOW_AO=0\|1\|2`, `WOW_AO_DEBUG=1..5` diagnostic views (factor, protection, distance, raw occlusion, foliage mask), `WOW_AO_GAIN`/`_RADIUS`/`_BIAS`/`_STRENGTH` tuning |
| Lamp fog | MONKEY (lampfog): the fog fullscreen pass selects the nearest resolved exterior and interior point-table sources and analytically integrates their softened inverse-square light over the camera-to-scene-depth ray. A near-field haze floor makes lamps visible inside the ordinary volumetric haze's 10 yd clear zone; it is zero by day, stronger in rain/fog, and deliberately unshadowed. The table colour already includes intensity, flame flicker and `fireLightGain`. Halo output uses destination headroom and stays below 1.0, so a later bloom pass cannot blow it out | Advanced Graphics → Lamp Fog, cvar `lampFog` 0 Off (default, unchanged) / 1 Low (16 lamps) / 2 High (32 lamps; Graphics preset High = 2), env `WOW_LAMPFOG=0\|1\|2`; `benilla-app/src/volumetric_fog.rs` |
| City window daylight | MONKEY (fix-daylight/integration): a district WMO's oversized window batch (e.g. the Cathedral of Light's stained-glass walls) is split into window-sized daylight apertures, so the nave takes daylight pane by pane. Applies to WMOs loaded after a change | Advanced Graphics → City Window Daylight, cvar `daylightWindowSplit` 0/1 (default 1, the merged behaviour); `benilla-world/src/lighting/daylight.rs` (`set_window_split`), bridge `benilla-app/src/dynamic_interior.rs` |
-| Zone skyboxes | the painted sky a zone's `LightParams` names (clear-weather slot, storm slot lerped by the storm blend) for the living, fading in by the Light sphere falloff with the modern client's crossfade (ghost > WMO > zone); extended `LightSkybox.dbc` flags `0x1` day cycle, `0x2` keep sun/moon/stars/clouds, `0x4` fog-colour horizon cone, plus a celestial second model; every skybox now plays its bones, texture transforms, colour and alpha tracks (`benilla-world/src/skybox.rs`, `skybox_anim.rs`, `benilla-formats/src/light/skybox.rs`) | Advanced Graphics → Zone Skyboxes, cvar `zoneSkyboxes` (0 Off default, 1 On; High = 1), env `WOW_ZONE_SKYBOXES=0\|1` |
+| Zone skyboxes | the painted sky a zone's `LightParams` names (clear-weather slot, storm slot lerped by the storm blend) for the living, fading in by the Light sphere falloff with the modern client's crossfade (ghost > WMO > zone); extended `LightSkybox.dbc` flags `0x1` day cycle, `0x2` keep sun/moon/stars/clouds, `0x4` fog-colour horizon cone, `0x8` forces the screen-space sun shafts through a low or just-set sun (the sky's weight lifts their daylight fade; `post/sun_shafts.rs`), `0x10` fades the Modern fog's sun-colour lobe out by the sky's weight (`lighting/fog_model.rs`), plus a celestial second model; every skybox now plays its bones, texture transforms, colour and alpha tracks (`benilla-world/src/skybox.rs`, `skybox_anim.rs`, `benilla-formats/src/light/skybox.rs`) | Advanced Graphics → Zone Skyboxes, cvar `zoneSkyboxes` (0 Off default, 1 On; High = 1), env `WOW_ZONE_SKYBOXES=0\|1` |
| Night and interior level | global dimming of the night sky term and of interior ambient | `nightGain`, `interiorGain`, `interiorBakeFloor` |
`zoneSkyboxes = 0` disables only the added living-player zone slot. WMO and ghost skyboxes are
diff --git a/crates/benilla-formats/src/lib.rs b/crates/benilla-formats/src/lib.rs
index c47b7f3b..39c7d54d 100644
--- a/crates/benilla-formats/src/lib.rs
+++ b/crates/benilla-formats/src/lib.rs
@@ -135,7 +135,11 @@ pub use light::{Atmosphere, LightCatalog, Submersion, ZERO_KEY_COLOR, ZERO_KEY_S
// MONKEY (fog): `LightFogBand.dbc`.
pub use light::{FogBand, FogBandCatalog, FOG_BANDS_PER_PARAM};
// MONKEY (skybox): the skybox row and the zone walk's entries.
-pub use light::{SkyboxDef, ZoneSkybox, SKYBOX_FOG_BLEND, SKYBOX_FULL_DAY, SKYBOX_KEEP_CELESTIAL};
+// MONKEY (leftovers): + the 0x8 / 0x10 flags.
+pub use light::{
+ SkyboxDef, ZoneSkybox, SKYBOX_FOG_BLEND, SKYBOX_FORCE_SUN_SHAFTS, SKYBOX_FULL_DAY,
+ SKYBOX_KEEP_CELESTIAL, SKYBOX_NO_SUN_FOG,
+};
mod loading_screen;
pub use loading_screen::{load_loading_screens, LoadingScreenCatalog};
mod liquid;
diff --git a/crates/benilla-formats/src/light.rs b/crates/benilla-formats/src/light.rs
index c9a016f5..b07c4be6 100644
--- a/crates/benilla-formats/src/light.rs
+++ b/crates/benilla-formats/src/light.rs
@@ -19,7 +19,11 @@ mod tables;
pub use atmosphere::Atmosphere;
pub use fog_band::{FogBand, FogBandCatalog, FOG_BANDS_PER_PARAM};
-pub use skybox::{SkyboxDef, ZoneSkybox, SKYBOX_FOG_BLEND, SKYBOX_FULL_DAY, SKYBOX_KEEP_CELESTIAL};
+// MONKEY (leftovers): + the 0x8 / 0x10 flags.
+pub use skybox::{
+ SkyboxDef, ZoneSkybox, SKYBOX_FOG_BLEND, SKYBOX_FORCE_SUN_SHAFTS, SKYBOX_FULL_DAY,
+ SKYBOX_KEEP_CELESTIAL, SKYBOX_NO_SUN_FOG,
+};
use atmosphere::{
FB_CLOUD_DENSITY, FB_FOG_END, FB_FOG_START_MULT, IB_AMBIENT, IB_CLOUD_GBASE, IB_CLOUD_SLOPE,
IB_CLOUD_SUN, IB_DIFFUSE, IB_FOG_COLOR, IB_OCEAN_DEEP, IB_OCEAN_SHALLOW, IB_RIVER_DEEP,
diff --git a/crates/benilla-formats/src/light/skybox.rs b/crates/benilla-formats/src/light/skybox.rs
index ab6c319a..cca12efd 100644
--- a/crates/benilla-formats/src/light/skybox.rs
+++ b/crates/benilla-formats/src/light/skybox.rs
@@ -26,6 +26,10 @@ pub const SKYBOX_FULL_DAY: u32 = 0x1;
pub const SKYBOX_KEEP_CELESTIAL: u32 = 0x2;
/// Flag `0x4`: an alpha cone in the final fog colour draws over the model's horizon.
pub const SKYBOX_FOG_BLEND: u32 = 0x4;
+/// MONKEY (leftovers): flag `0x8`: sun shafts run under this sky even where they would fade.
+pub const SKYBOX_FORCE_SUN_SHAFTS: u32 = 0x8;
+/// MONKEY (leftovers): flag `0x10`: the fog's sun-colour lobe is off under this sky.
+pub const SKYBOX_NO_SUN_FOG: u32 = 0x10;
/// One `LightSkybox.dbc` row.
#[derive(Clone, Debug, PartialEq, Eq)]
diff --git a/crates/benilla-world/src/lighting/fog_model.rs b/crates/benilla-world/src/lighting/fog_model.rs
index 22a0d21b..4ff8249d 100644
--- a/crates/benilla-world/src/lighting/fog_model.rs
+++ b/crates/benilla-world/src/lighting/fog_model.rs
@@ -204,6 +204,8 @@ pub(super) fn update_fog_model(
eye_liquid: crate::liquid::EyeLiquid,
viewer: Res,
weather: Option>,
+ // MONKEY (leftovers): LightSkybox flag 0x10 (last frame's backdrop; the skybox resolves later).
+ sky: Option>,
mut frame: ResMut,
) {
let derived = derived_band(&lighting);
@@ -233,6 +235,9 @@ pub(super) fn update_fog_model(
};
let mut next = *frame;
fill_frame(&mut next, setting.0, &lighting, &band);
+ // MONKEY (leftovers): a `0x10` skybox fades the sun-fog lobe out by its weight.
+ let no_sun = sky.map_or(0.0, |s| s.flag_weight(benilla_formats::SKYBOX_NO_SUN_FOG));
+ next.sun_fog_strength *= 1.0 - no_sun.clamp(0.0, 1.0);
if *frame != next {
*frame = next;
}
diff --git a/crates/benilla-world/src/skybox.rs b/crates/benilla-world/src/skybox.rs
index 9df4635a..3029dc01 100644
--- a/crates/benilla-world/src/skybox.rs
+++ b/crates/benilla-world/src/skybox.rs
@@ -92,6 +92,15 @@ impl CameraSkybox {
})
}
+ /// MONKEY (leftovers): the heaviest main layer's weight among those carrying `flag`, 0 if none.
+ pub fn flag_weight(&self, flag: u32) -> f32 {
+ self.0
+ .iter()
+ .filter(|l| !l.celestial && l.flags & flag != 0)
+ .map(|l| l.weight)
+ .fold(0.0, f32::max)
+ }
+
fn layer(&self, path: &str) -> Option<&SkyboxLayer> {
self.0.iter().find(|l| l.path == path)
}
@@ -1084,4 +1093,23 @@ mod tests {
});
assert_eq!(sky.primary().map(|l| l.path.as_str()), Some("b"));
}
+
+ /// MONKEY (leftovers): a flag's weight is its heaviest main carrier; celestial layers and
+ /// layers without the flag do not count.
+ #[test]
+ fn flag_weight_is_the_heaviest_main_carrier() {
+ let with = |path, w, flags| SkyboxLayer {
+ flags,
+ ..layer(path, w)
+ };
+ let mut sky = CameraSkybox(vec![with("a", 0.3, 0x8), with("b", 0.7, 0x1), with("c", 0.5, 0x18)]);
+ sky.0.push(SkyboxLayer {
+ celestial: true,
+ ..with("d", 1.0, 0x18)
+ });
+ assert_eq!(sky.flag_weight(benilla_formats::SKYBOX_FORCE_SUN_SHAFTS), 0.5);
+ assert_eq!(sky.flag_weight(benilla_formats::SKYBOX_NO_SUN_FOG), 0.5);
+ assert_eq!(sky.flag_weight(benilla_formats::SKYBOX_FOG_BLEND), 0.0);
+ assert_eq!(CameraSkybox::default().flag_weight(0x8), 0.0);
+ }
}