Files
benilla-octo/crates/benilla-app/src/dynamic_interior.rs
T
pkuzicandClaude Fable 5.1 e254e6dce8 MONKEY: dynamic WMO interiors + cube-map torch shadows (surfaces + entities)
Interior rooms light per fragment from their authored fixtures instead of
the MOCV bake (direct + fill + ambient, soft rolloff; live cvars
interiorLight/interiorAmbient/interiorFill/interiorExposure/interiorShadows/
interiorDebug), TRANS/EXT batches blend to the day/night reference at the
portal seam, and fixtures admit camera-independently (90 yd).

Torch shadows are a from-scratch depth-map renderer (Bevy point shadows are
dead under ClusterConfig::None): a shared Depth32Float 512^2 x 24-layer Image
+ depth-only pipeline + ViewNode rendering the static caster and a per-frame
entity caster into 6 cube faces for the nearest <=4 fixtures (reverse-Z,
GreaterEqual compare, 4-tap PCF, far fade). WMO surfaces receive through
static_gx group 3; entities receive on the wow_model path through
WowModelExt bindings 91/92/93 (depth array, comparison sampler, 1616-byte
torch table) with a 0.15 yd normal offset against CPU-vs-GPU skinning
self-shadow.

The entity lane is gated on is_interior OR the new MATTE_INDOOR tag bit
(exterior payload bit 14, written by the classifier's Matte law), so a unit
whose verdict flickers Bake<->Matte at one spot keeps its room lighting.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 20:12:47 +01:00

38 lines
1.5 KiB
Rust

//! MONKEY (dynamic interiors): the app-side half of the fixture-lit WMO interior lane — a
//! plug-and-play bridge from the `interiorLight` / `interiorAmbient` / `interiorFill` /
//! `interiorExposure` cvars ([`VideoConfig`]) to benilla-world's [`DynamicInteriors`] resource,
//! which `global_light` packs for `static_gx.wgsl`'s `interior_room_light` (WMO interior surfaces
//! AND interior props light from the room's live fixtures instead of the MOCV bake / the baked prop
//! probe). Independent of the shadow lanes: removing this plugin leaves the resource at its
//! shipped defaults; `interiorLight 0` restores the faithful baked interior path.
//!
//! The knobs are LIVE — `/script SetCVar("interiorExposure", 2)` in chat retunes the room without
//! a rebuild, which is how the defaults were found.
use benilla_world::lighting::DynamicInteriors;
use bevy::prelude::*;
use crate::video::VideoConfig;
pub(crate) struct DynamicInteriorPlugin;
impl Plugin for DynamicInteriorPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, bridge);
}
}
/// Publish the cvars to benilla-world when they change. Guarded so the resource's change ticks
/// stay quiet on idle frames.
fn bridge(video: Res<VideoConfig>, mut out: ResMut<DynamicInteriors>) {
let want = DynamicInteriors {
enabled: video.interior_light,
ambient: video.interior_ambient,
fill: video.interior_fill,
exposure: video.interior_exposure,
debug: video.interior_debug,
};
if *out != want {
*out = want;
}
}