MONKEY (p0): skyDither cvar for the FFXGlow deband dither
The combine's dither lane was armed only by the WOW_DITHER env var. It is now the `skyDither` cvar (0/1, default 0 = reference look; Graphics preset High = 1) with an Advanced Graphics "Sky Dithering" checkbox row (EN + RU). The cvar lands on `benilla_world::ffx_glow::SkyDither` (extracted) through the new `benilla-app/src/monkey_gfx.rs` bridge; WOW_DITHER=1 still forces it on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
86f454ca4c
commit
708859a13a
@@ -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` |
|
||||
| Sky dithering | a faint screen-space dither in the FFXGlow combine so smooth sky and fog gradients do not band (MONKEY p0; was env-only) | Advanced Graphics → Sky Dithering, cvar `skyDither` 0/1 (default 0, Graphics preset High = 1), env `WOW_DITHER=1` still forces it on; bridge in `benilla-app/src/monkey_gfx.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 /
|
||||
|
||||
@@ -519,6 +519,8 @@
|
||||
spellLights = "Spell Lights",
|
||||
nightDarkness = "Night Darkness",
|
||||
interiorDarkness = "Interior Darkness",
|
||||
-- MONKEY (p0 skyDither)
|
||||
skyDither = "Sky Dithering",
|
||||
yards = "%d yd",
|
||||
tips = {
|
||||
LIGHTING_QUALITY =
|
||||
@@ -611,6 +613,10 @@
|
||||
"Scales interior fixture light and room ambient, including the light from "
|
||||
.. "lamps and candles. Lower values make both dimmer.\n\n"
|
||||
.. "1.0 leaves these inputs unchanged. Free at any setting.",
|
||||
-- MONKEY (p0 skyDither)
|
||||
SKY_DITHER =
|
||||
"Adds a faint noise to the final image so smooth sky and fog gradients do not "
|
||||
.. "break into visible bands. Off is the original client's look. Practically free.",
|
||||
},
|
||||
},
|
||||
ruRU = {
|
||||
@@ -643,6 +649,8 @@
|
||||
spellLights = "Свет от заклинаний",
|
||||
nightDarkness = "Темнота ночи",
|
||||
interiorDarkness = "Темнота помещений",
|
||||
-- MONKEY (p0 skyDither)
|
||||
skyDither = "Дизеринг неба",
|
||||
yards = "%d ярд.",
|
||||
tips = {
|
||||
LIGHTING_QUALITY =
|
||||
@@ -743,6 +751,11 @@
|
||||
"Масштабирует свет светильников и фоновое освещение помещений, включая "
|
||||
.. "свет ламп и свечей. Меньшие значения ослабляют и то и другое.\n\n"
|
||||
.. "1.0 оставляет эти составляющие без изменений. Ничего не стоит при любом значении.",
|
||||
-- MONKEY (p0 skyDither)
|
||||
SKY_DITHER =
|
||||
"Добавляет едва заметный шум в итоговое изображение, чтобы плавные переходы цвета "
|
||||
.. "неба и тумана не распадались на полосы. Выключено — вид оригинального клиента. "
|
||||
.. "Почти ничего не стоит.",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -801,6 +814,8 @@
|
||||
"RowInteriorLight", "RowInteriorShadows", "RowExteriorShadows", "RowTorchSoft",
|
||||
"RowFireLight", "RowFireFlicker", "RowSpellLights", "RowLavaGlow",
|
||||
"RowNightDarkness", "RowInteriorDarkness",
|
||||
-- MONKEY (p0 skyDither)
|
||||
"RowSkyDither",
|
||||
},
|
||||
-- Player Guild Names is a child of Player Names, as in 1.12 (l.702-708).
|
||||
Nameplates = {
|
||||
@@ -2827,6 +2842,18 @@
|
||||
OptionsSliderRow_Setup(self, 0.2, 1.5, 0.05, "darkness")
|
||||
</OnLoad></Scripts>
|
||||
</Frame>
|
||||
<!-- MONKEY (p0 skyDither): the combine's deband dither. -->
|
||||
<Frame name="$parentRowSkyDither" inherits="OptionsCheckboxRowTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativeTo="$parentRowInteriorDarkness" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-9"/></Offset></Anchor>
|
||||
<Anchor point="TOPRIGHT" relativeTo="$parentRowInteriorDarkness" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="0" y="-9"/></Offset></Anchor>
|
||||
</Anchors>
|
||||
<Scripts><OnLoad>
|
||||
OptionsRow_OnLoad(self, "skyDither",
|
||||
BENILLA_ADVGFX.skyDither,
|
||||
"BENILLA_TOOLTIP_SKY_DITHER")
|
||||
</OnLoad></Scripts>
|
||||
</Frame>
|
||||
</Frames>
|
||||
<!-- The poll (see AdvGfx_OnUpdate): this is the one page whose
|
||||
settings move from outside it — the Lighting Quality row
|
||||
|
||||
@@ -921,6 +921,13 @@ 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 (p0 skyDither): the FFXGlow combine's deband dither (was env WOW_DITHER only).
|
||||
// Default 0 = the reference look; the Graphics preset's High sets 1.
|
||||
ours(
|
||||
"skyDither",
|
||||
"0",
|
||||
"benilla's own: faint screen dither against sky and fog banding, 0 Off / 1 On",
|
||||
),
|
||||
ours(
|
||||
"waterQuality",
|
||||
"1",
|
||||
@@ -3702,6 +3709,11 @@ mod tests {
|
||||
|app| {
|
||||
app.add_observer(crate::video::on_cvar);
|
||||
},
|
||||
// MONKEY (p0 graphics programme)
|
||||
|app| {
|
||||
app.init_resource::<benilla_world::ffx_glow::SkyDither>();
|
||||
app.add_observer(crate::monkey_gfx::on_cvar);
|
||||
},
|
||||
|app| {
|
||||
app.add_observer(crate::player::camera::on_cvar);
|
||||
},
|
||||
|
||||
@@ -245,6 +245,8 @@ impl PluginGroup for GamePlugins {
|
||||
.add(crate::dynamic_interior::DynamicInteriorPlugin)
|
||||
// MONKEY (volumetric fog): bridge the live setting to Bevy.
|
||||
.add(crate::volumetric_fog::VolumetricFogPlugin)
|
||||
// MONKEY (p0 graphics programme): the programme's cvar bridges (skyDither, ...).
|
||||
.add(crate::monkey_gfx::MonkeyGfxPlugin)
|
||||
// The realmlist (decision 1667) — the logon address the login screen edits. Same reason as
|
||||
// VideoPlugin above: it is a CVar knob, so its resource has to exist before `load_config`.
|
||||
.add(crate::realmlist::RealmlistPlugin)
|
||||
|
||||
@@ -74,6 +74,8 @@ mod doodad_events;
|
||||
/// MONKEY (dynamic interiors): the cvar → benilla-world bridge for the fixture-lit interior lane.
|
||||
// MONKEY (volumetric fog): optional near-field atmosphere plugin.
|
||||
mod volumetric_fog;
|
||||
// MONKEY (p0 graphics programme): the programme's cvar bridges (skyDither, ...).
|
||||
mod monkey_gfx;
|
||||
mod dynamic_interior;
|
||||
mod entities;
|
||||
mod fishing_line;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
//! MONKEY (p0 graphics programme): the cvar bridges of the graphics programme's own settings, each
|
||||
//! landing on the benilla-world resource its renderer reads. One observer, one arm per cvar;
|
||||
//! lanes add their rows here rather than to `video.rs`'s reference block.
|
||||
//!
|
||||
//! | cvar | values | default | Graphics preset High | resource |
|
||||
//! |---|---|---|---|---|
|
||||
//! | `skyDither` | 0 Off / 1 On | 0 | 1 | `benilla_world::ffx_glow::SkyDither` |
|
||||
|
||||
use bevy::prelude::*;
|
||||
use benilla_world::ffx_glow::SkyDither;
|
||||
|
||||
/// The programme's cvar observer (registered by [`MonkeyGfxPlugin`]).
|
||||
pub(crate) fn on_cvar(ev: On<crate::cvars::CvarChanged>, mut dither: ResMut<SkyDither>) {
|
||||
if ev.key().as_str() == "skydither" {
|
||||
let want = ev.num() >= 0.5;
|
||||
if dither.0 != want {
|
||||
dither.0 = want;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers the programme's cvar bridges. Must be added before `CvarPlugin` so the saved values
|
||||
/// applied at Startup reach it (the edge `game_plugins.rs` documents for every knob plugin).
|
||||
pub(crate) struct MonkeyGfxPlugin;
|
||||
|
||||
impl Plugin for MonkeyGfxPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.init_resource::<SkyDither>().add_observer(on_cvar);
|
||||
}
|
||||
}
|
||||
@@ -684,12 +684,18 @@ fn prepare_textures(
|
||||
}
|
||||
}
|
||||
|
||||
/// `WOW_DITHER=1` arms the combine's deband dither (`ffx.lane.w`). Deviation, opt-in, off by
|
||||
/// default: the reference's 8-bit framebuffer is undithered, but a smooth gradient under slow
|
||||
/// motion steps visibly at 1/255. Bevy's own dither never runs under `Tonemapping::None`.
|
||||
fn dither_armed() -> f32 {
|
||||
static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
|
||||
match *ON.get_or_init(|| std::env::var_os("WOW_DITHER").is_some()) {
|
||||
/// MONKEY (p0 skyDither): the combine's deband dither (`ffx.lane.w`), the `skyDither` cvar
|
||||
/// (Advanced Graphics -> Sky Dithering, 0/1, default 0). Deviation, opt-in: the reference's 8-bit
|
||||
/// framebuffer is undithered, but a smooth gradient under slow motion steps visibly at 1/255.
|
||||
/// Bevy's own dither never runs under `Tonemapping::None`. benilla-app's settings bridge writes it.
|
||||
#[derive(Resource, Clone, Copy, Default, PartialEq, Eq, Debug, ExtractResource)]
|
||||
pub struct SkyDither(pub bool);
|
||||
|
||||
/// `WOW_DITHER=1` still arms the dither for a session (it used to be the only switch); otherwise
|
||||
/// the live [`SkyDither`] decides.
|
||||
fn dither_armed(cvar: bool) -> f32 {
|
||||
static ENV: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
|
||||
match cvar || *ENV.get_or_init(|| std::env::var_os("WOW_DITHER").is_some()) {
|
||||
true => 1.0,
|
||||
false => 0.0,
|
||||
}
|
||||
@@ -713,7 +719,7 @@ fn combine_uniform(
|
||||
zone_gain * glow.gain_scale,
|
||||
feed.death,
|
||||
feed.haze,
|
||||
dither_armed(),
|
||||
0.0, // MONKEY (p0 skyDither): the dither arm, set by `live_combine` from [`SkyDither`]
|
||||
wave.phase1,
|
||||
wave.phase2,
|
||||
0.0,
|
||||
@@ -906,6 +912,9 @@ fn live_combine(world: &World, glow: &FfxGlow) -> ([f32; 8], bool) {
|
||||
glow,
|
||||
wave,
|
||||
);
|
||||
// MONKEY (p0 skyDither): the dither lane, from the cvar (or the old env switch).
|
||||
let mut uniform = uniform;
|
||||
uniform[3] = dither_armed(world.get_resource::<SkyDither>().is_some_and(|d| d.0));
|
||||
(uniform, wave_armed(glow.state, wave, death))
|
||||
}
|
||||
|
||||
@@ -1090,6 +1099,8 @@ impl Plugin for FfxGlowPlugin {
|
||||
.init_resource::<GlueFfx>()
|
||||
.init_resource::<FfxHazeMix>()
|
||||
.init_resource::<FfxWave>()
|
||||
// MONKEY (p0 skyDither)
|
||||
.init_resource::<SkyDither>()
|
||||
.add_plugins((
|
||||
ExtractComponentPlugin::<FfxGlow>::default(),
|
||||
ExtractComponentPlugin::<FfxBackdrop>::default(),
|
||||
@@ -1098,6 +1109,7 @@ impl Plugin for FfxGlowPlugin {
|
||||
ExtractResourcePlugin::<GlueFfx>::default(),
|
||||
ExtractResourcePlugin::<FfxHazeMix>::default(),
|
||||
ExtractResourcePlugin::<FfxWave>::default(),
|
||||
ExtractResourcePlugin::<SkyDither>::default(),
|
||||
))
|
||||
.add_systems(
|
||||
Update,
|
||||
|
||||
@@ -63,7 +63,7 @@ fn srgb_to_linear(c: vec3<f32>) -> vec3<f32> {
|
||||
return select(hi, lo, c <= vec3<f32>(0.04045));
|
||||
}
|
||||
|
||||
// Deviation, opt-in (`WOW_DITHER=1`): a dither against banding, which the reference's 8-bit
|
||||
// Deviation, opt-in (MONKEY p0: cvar `skyDither`, or `WOW_DITHER=1`): a dither against banding, which the reference's 8-bit
|
||||
// framebuffer lacks. The hash is Bevy's `screen_space_dither`, copied here because Bevy applies
|
||||
// it only in the tonemapping pass that `Tonemapping::None` skips.
|
||||
fn screen_space_dither(frag_coord: vec2<f32>) -> vec3<f32> {
|
||||
|
||||
Reference in New Issue
Block a user