diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index c879195..2938753 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -6344,6 +6344,28 @@ public sealed class GameWindow : IDisposable Lighting.Tick(camPos); var ubo = AcDream.Core.Lighting.SceneLightingUbo.Build( Lighting, in atmo, camPos, (float)WorldTime.DayFraction); + + // A.5 T22: override fog ramp with N₁/N₂-derived distances so the + // horizon fog masks the N₁ scenery boundary. Sky keyframe fog is + // retail-accurate at normal view distances but far too short for + // the extended N₂=12 (25×25 LB) streaming window. + // FogStart = N₁ × 192m × 0.7 ≈ 538m at defaults (4/12). + // FogEnd = N₂ × 192m × 0.95 ≈ 2188m at defaults. + // Multipliers exposed as env vars for fast iteration at visual gate. + { + const float LandblockSize = 192.0f; + float startMult = ParseEnvFloat("ACDREAM_FOG_START_MULT", 0.7f); + float endMult = ParseEnvFloat("ACDREAM_FOG_END_MULT", 0.95f); + float fogStart = _nearRadius * LandblockSize * startMult; + float fogEnd = _farRadius * LandblockSize * endMult; + // Preserve fog color (xyz), lightning flash (z), and mode (w). + ubo.FogParams = new System.Numerics.Vector4( + fogStart, + fogEnd, + ubo.FogParams.Z, // lightning flash — unchanged + ubo.FogParams.W); // fog mode — unchanged + } + _sceneLightingUbo?.Upload(ubo); // Never cull the landblock the player is currently on. @@ -8862,6 +8884,17 @@ public sealed class GameWindow : IDisposable return copy[copy.Length - 1 - offset]; } + /// A.5 T22: parse a float environment variable, returning + /// when the variable is absent or unparseable. + private static float ParseEnvFloat(string name, float defaultValue) + { + var s = System.Environment.GetEnvironmentVariable(name); + if (s is not null && float.TryParse(s, System.Globalization.NumberStyles.Float, + System.Globalization.CultureInfo.InvariantCulture, out var v)) + return v; + return defaultValue; + } + private void OnClosing() { // Phase A.1: join the streamer worker thread before tearing down GL