moonwell-gfx: darker nights and deeper shadows, as WoW Forever's

The post pass takes from the dark and middle tones (eased off toward the bright, so a torch's
pool, a window or the moon keep theirs): post.shadow_depth at any hour, post.night_darkness
far further with the sun down, cooler and a little greyer. The lit air keeps 15% for the moon
(was 35%). The Forever preset sets both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-29 01:22:42 +04:00
parent 5f66d475fd
commit 6b18cdac09
4 changed files with 68 additions and 4 deletions
+16
View File
@@ -217,6 +217,22 @@ const ITEMS: &[Item] = &[
"Сила резкости",
"Sharpen strength",
),
slider(
"post.shadow_depth",
0.0,
1.0,
0.05,
"Глубина теней",
"Shadow depth",
),
slider(
"post.night_darkness",
0.0,
1.0,
0.05,
"Тёмные ночи",
"Dark nights",
),
switch("post.grading", "Цветокоррекция", "Colour grading"),
slider("post.brightness", -0.5, 0.5, 0.01, "Яркость", "Brightness"),
slider("post.contrast", 0.5, 2.0, 0.01, "Контраст", "Contrast"),
+20 -3
View File
@@ -188,7 +188,7 @@ fn publish(
} else {
0.0
};
let night_share = if shadows.moon { 0.35 } else { 0.0 };
let night_share = if shadows.moon { 0.15 } else { 0.0 };
// A low sun lights the air most: the glow and the rays are the dawn's and the dusk's, and the
// noon keeps a third.
let low_sun = 1.0 - 0.65 * smoothstep(0.25, 0.8, sun.y);
@@ -203,8 +203,20 @@ fn publish(
} else {
0.0
};
// The dark: how much the dark and middle tones lose, deeper at night; and the night's cool,
// grey share.
let night = 1.0 - day;
let dark = (s.shadow_depth as f32 * 0.25 + s.night_darkness as f32 * 0.6 * night).min(0.7);
let night_tint = s.night_darkness as f32 * night;
let post_on = s.enabled
&& (s.grading || s.ao || s.sun_shafts || vol > 0.0 || sharpen > 0.0 || gi > 0.0 || fxaa);
&& (s.grading
|| s.ao
|| s.sun_shafts
|| vol > 0.0
|| sharpen > 0.0
|| gi > 0.0
|| fxaa
|| dark > 0.0);
let next = (post_on || halo > 0.0).then(|| PostParams {
grade: Vec4::new(
s.brightness as f32,
@@ -212,7 +224,12 @@ fn publish(
s.saturation as f32,
s.vibrance as f32,
),
tone: Vec4::new(s.warmth as f32, on(post_on && s.grading), 0.0, 0.0),
tone: Vec4::new(
s.warmth as f32,
on(post_on && s.grading),
if post_on { dark } else { 0.0 },
if post_on { night_tint } else { 0.0 },
),
ao: Vec4::new(
s.ao_strength as f32,
s.ao_radius as f32,
+11
View File
@@ -120,6 +120,8 @@ impl GfxSettings {
s.post.saturation = 1.15;
s.post.vibrance = 0.2;
s.post.secondary_light_strength = 1.2;
s.post.shadow_depth = 0.5;
s.post.night_darkness = 0.75;
s.wind.enabled = true;
s.water.enabled = true;
s.lights.enabled = true;
@@ -353,6 +355,11 @@ pub struct PostSettings {
pub secondary_light: bool,
/// Its strength, 0..2.
pub secondary_light_strength: f64,
/// Deeper shadows at any hour, 0..1: the dark and middle tones go down, the bright stay.
pub shadow_depth: f64,
/// Darker nights, 0..1: with the sun down the same curve goes much further, cooler and a
/// little greyer, so a torch, a lamp or a window stands out of the dark.
pub night_darkness: f64,
}
impl Default for PostSettings {
@@ -382,6 +389,8 @@ impl Default for PostSettings {
antialias: true,
secondary_light: true,
secondary_light_strength: 0.8,
shadow_depth: 0.4,
night_darkness: 0.6,
}
}
}
@@ -414,6 +423,8 @@ impl PostSettings {
antialias: self.antialias,
secondary_light: self.secondary_light,
secondary_light_strength: self.secondary_light_strength.clamp(0.0, 2.0),
shadow_depth: self.shadow_depth.clamp(0.0, 1.0),
night_darkness: self.night_darkness.clamp(0.0, 1.0),
}
}
}
+21 -1
View File
@@ -10,7 +10,7 @@
struct Post {
// brightness, contrast, saturation, vibrance
grade: vec4<f32>,
// warmth, grade on, unused, unused
// warmth, grade on, what the dark tones lose (0 off), the night's tint
tone: vec4<f32>,
// strength, radius (yd), ao on, unused
ao: vec4<f32>,
@@ -488,6 +488,25 @@ fn fxaa(uv: vec2<f32>, centre: vec3<f32>) -> vec3<f32> {
return fxaa_at(out_uv);
}
// The dark: the dark and middle tones lose `tone.z` of their light and the bright (a torch's
// pool, a window, the moon) keep theirs, eased between by the luma, as WoW Forever's dim places
// and nights are; at night (`tone.w`) also cooler and a little greyer, as the eye sees in the dark.
fn darkened(c: vec3<f32>) -> vec3<f32> {
let k = post.tone.z;
if (k <= 0.0) {
return c;
}
let l = dot(c, vec3<f32>(0.2126, 0.7152, 0.0722));
var x = c * mix(1.0 - k, 1.0, smoothstep(0.08, 0.75, l));
let n = post.tone.w;
if (n > 0.0) {
let grey = dot(x, vec3<f32>(0.2126, 0.7152, 0.0722));
x = mix(x, vec3<f32>(grey), 0.25 * n);
x = x * mix(vec3<f32>(1.0), vec3<f32>(0.86, 0.94, 1.12), 0.6 * n);
}
return x;
}
// The grade, in the gamma bytes the world pass writes.
fn grade(c: vec3<f32>) -> vec3<f32> {
var x = c + vec3<f32>(post.grade.x);
@@ -518,5 +537,6 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
if (post.tone.y > 0.5) {
rgb = grade(rgb);
}
rgb = darkened(rgb);
return vec4<f32>(rgb, color.a);
}