diff --git a/LIGHTING.md b/LIGHTING.md
index 9263f5c7..09a103c3 100644
--- a/LIGHTING.md
+++ b/LIGHTING.md
@@ -33,6 +33,7 @@ behind each constant.
| Rain on surfaces | MONKEY (wet): rain gradually darkens and saturates exposed terrain and models, adds puddles and a sky/sun sheen, and produces rings on exterior Enhanced water. Wetness rises over roughly 90 seconds and dries over roughly four minutes; phase 1 has no rain-occlusion map, so shelter is classified only by interior/unlit state and surface facing | Advanced Graphics → Wet Surfaces in Rain, cvar `rainSurfaces` 0/1 (default and High 1), env `WOW_RAIN_SURFACES`, `WOW_WETNESS`, `WOW_WET_T`; `weather/wetness.rs`, `wet_hook.wgsl` |
| Foliage wind | one weather-fed gust/veer field drives grass and classified tree/bush foliage; grass also parts around the player and nearby units | Advanced Graphics → Foliage Wind, cvar `foliageWind` 0 Off / 1 Grass / 2 Grass + Trees (High = 2), capture override `WOW_FOLIAGE_WIND`; field and benders in `benilla-world/src/wind/`. The wave phase is the CPU-integrated travel (speed integrated over time, wrapped seamlessly), and the waves' spatial term uses the fixed profile heading; the veer turns only the bend. Tree exile copies sway through material marker bit 14 (`FOLIAGE_WIND_MARKER`). Capture offset `WOW_CAPTURE_WIND_T` (s). Known: shadow casters (world-shadow proxies, `torch_depth.wgsl`) do not apply the sway, so leaves sample a static shadow; a future world-camera DepthPrepass must call the same offsets |
| 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 (`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..4` diagnostic views (factor, protection, distance, raw occlusion), `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` |
| 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 /
@@ -98,6 +99,9 @@ is its own module, documented in `WATER.md`.
- World lights use upstream's `WorldPointLight`, never Bevy's `PointLight`.
- Foliage wind is vertex-only. Tree and leaf shadow meshes stay static; the small mismatch is the
accepted first-stage cost/complexity tradeoff.
+- MONKEY (lampfog): `ResolvedPointLights` is a CPU-only read view of the live, truncated point table;
+ it does not add a row to the shared GPU buffer. Lamp selection is capped at 100 yd and ranks both
+ exterior and interior rows together before the 16/32 nearest limit is applied.
- WGSL only fails at pipeline creation, so a shader edit is verified by running a world scene, not
by `cargo check`.
- Exterior point lights are selected per draw unit (12 slots, ranked against the chunk's box); the
diff --git a/crates/benilla-app/assets/ui/OptionsFrame.xml b/crates/benilla-app/assets/ui/OptionsFrame.xml
index 9c2ba22c..0a2c9846 100644
--- a/crates/benilla-app/assets/ui/OptionsFrame.xml
+++ b/crates/benilla-app/assets/ui/OptionsFrame.xml
@@ -538,6 +538,8 @@
windTrees = "Grass + Trees",
-- MONKEY (ao): localised contact-shadow row.
ambientOcclusion = "Ambient Occlusion",
+ -- MONKEY (lampfog)
+ lampFog = "Lamp Fog",
yards = "%d yd",
tips = {
LIGHTING_QUALITY =
@@ -677,6 +679,12 @@
.. "High is smoother and reaches a little further.\n\n"
.. "Fades out with distance and spares the sky, water, lit windows and flames. "
.. "Off leaves the image unchanged.",
+ -- MONKEY (lampfog)
+ LAMP_FOG =
+ "Makes nearby lamps and fires glow through the air after dark. Low uses the "
+ .. "nearest 16 lights; High uses 32. Rain and fog strengthen the halos. "
+ .. "The effect is unshadowed, but stops at visible scene depth.\n\n"
+ .. "Off is unchanged, and daylight is unchanged at every setting.",
},
},
ruRU = {
@@ -728,6 +736,8 @@
windTrees = "Трава + деревья",
-- MONKEY (ao): Russian contact-shadow row.
ambientOcclusion = "Затенение окружения",
+ -- MONKEY (lampfog)
+ lampFog = "Свечение фонарей в тумане",
yards = "%d ярд.",
tips = {
LIGHTING_QUALITY =
@@ -879,6 +889,12 @@
.. "«Высокое» — более плавное и захватывает чуть больше.\n\n"
.. "Ослабевает с расстоянием и не затрагивает небо, воду, освещённые окна и пламя. "
.. "«Выкл» оставляет изображение без изменений.",
+ -- MONKEY (lampfog)
+ LAMP_FOG =
+ "После заката ближайшие фонари и огни светятся сквозь воздух. Низкое "
+ .. "качество использует 16 ближайших источников, высокое — 32. Дождь и туман усиливают ореолы. "
+ .. "Эффект не рассчитывает тени, но обрывается на видимой глубине.\n\n"
+ .. "Выключено — без изменений; днём изображение не меняется при любом значении.",
},
},
}
@@ -953,6 +969,8 @@
"RowFoliageWind",
-- MONKEY (ao): appended so the other rows keep their indices.
"RowAmbientOcclusion",
+ -- MONKEY (lampfog)
+ "RowLampFog",
},
-- Player Guild Names is a child of Player Names, as in 1.12 (l.702-708).
Nameplates = {
@@ -3118,6 +3136,22 @@
})
+
+
+
+
+
+
+
+ OptionsRow_OnLoad(self, "lampFog", BENILLA_ADVGFX.lampFog,
+ "BENILLA_TOOLTIP_LAMP_FOG")
+ OptionsDropdownRow_Setup(self, {
+ { text = BENILLA_ADVGFX.fogOff, value = "0" },
+ { text = BENILLA_ADVGFX.qLow, value = "1" },
+ { text = BENILLA_ADVGFX.qHigh, value = "2" },
+ })
+
+