fix(sky): translucency-as-opacity + sky fog floor + additive fog-skip
Three retail-faithful sky/weather composite fixes (one cohesive commit because they touch the same per-Surface flag plumbing path). 1. Surface.Translucency is OPACITY, not (1 - opacity). Retail D3DPolyRender::SetSurface at 0x59c7a6 (decomp 425255-425260) computes `curr_alpha = _ftol2(translucency × 255)` and writes that directly as vertex.color.alpha. ACViewer (TextureCache.cs:142) and WorldBuilder (ObjectMeshManager.cs:1115) both use `1 - translucency` and are wrong by the same misread. Cloud surface 0x08000023 has Translucency=0.25; under the old (1-x) formula opacity was 0.75, making clouds 3× too bright vs retail. Flipped to use translucency directly. Gated on the Translucent flag (0x10) so non-Translucent surfaces (which carry Translucency=0 in the dat) keep opacity 1.0 instead of going invisible. 2. Sky fog re-enabled with a "fog floor" mitigation. Disabled 2026-04-24 because Dereth sky meshes are authored at radii 1050-1820m while storm-keyframe FogEnd is ~400m, which would saturate the entire dome to flat fogColor and destroy stars/moon/dome texture. Retail visibly DOES fog its sky, mechanism still un-pinned. Workaround: clamp `vFogFactor` to a minimum of SKY_FOG_FLOOR=0.2 so the dome shows AT LEAST 20% raw texture even at extreme distances. Tuned via dual- client visual comparison; preserves stars/moon while letting the horizon haze visibly in low-FogEnd keyframes. 3. Additive sky surfaces skip fog entirely. Retail D3DPolyRender::SetSurface at 0x59c882 calls SetFFFogAlphaDisabled(1) when the Additive flag (0x10000) is set — sun, moon, stars, additive cloud sheets render unfogged. Without this gate the sun dimmed to fog color at horizon dusk/dawn instead of staying bright. Plumbed via new `uApplyFog` shader uniform driven by the existing SubMeshGpu.IsAdditive boolean (already set from TranslucencyKind.Additive at upload time). User visually verified all three vs retail screenshots in Holtburg. Tests: 1223 pass.
This commit is contained in:
parent
63b50c5291
commit
97fc1b51d8
4 changed files with 121 additions and 55 deletions
|
|
@ -325,16 +325,28 @@ public sealed unsafe class SkyRenderer : IDisposable
|
|||
_shader.SetFloat("uEmissive", effEmissive);
|
||||
|
||||
// Retail per-Surface translucency override (D3DPolyRender::SetSurface
|
||||
// at 0x59c767): when the Surface's Translucent (0x10) bit is set,
|
||||
// its translucency float drives per-vertex alpha. Both ACViewer
|
||||
// and WorldBuilder render this as opacity = (1 - x). The shader
|
||||
// multiplies output alpha by (1 - uSurfTranslucency); for surfaces
|
||||
// without the bit, SurfTranslucency=0 ⇒ no effect. Critical for
|
||||
// the rain mesh 0x01004C42/0x01004C44 (Translucency=0.5) so its
|
||||
// streaks contribute at half intensity instead of full under the
|
||||
// additive (SrcAlpha, One) blend.
|
||||
// at 0x59c7a6, decomp 425255-425260): when the Surface's
|
||||
// Translucent (0x10) bit is set, retail computes
|
||||
// curr_alpha = _ftol2(translucency × 255) and writes it as vertex
|
||||
// alpha — i.e. the dat's Translucency float is the OPACITY
|
||||
// directly, NOT inverted. ACViewer and WorldBuilder both invert
|
||||
// it (1 - x) and are wrong by the same misread. The shader uses
|
||||
// it directly as an opacity multiplier; for non-Translucent
|
||||
// surfaces the GfxObjMesh.Build() path keeps SurfTranslucency=1.0
|
||||
// (no effect). Critical for rain (Translucency=0.5 → opacity 0.5)
|
||||
// and clouds (Translucency=0.25 → opacity 0.25, dim like retail).
|
||||
_shader.SetFloat("uSurfTranslucency", sub.SurfTranslucency);
|
||||
|
||||
// Retail D3DPolyRender::SetSurface at 0x59c882 calls
|
||||
// SetFFFogAlphaDisabled(1) when the Additive flag (0x10000)
|
||||
// is set on the Surface — so the sun, moon, stars, and any
|
||||
// additive cloud sheet are drawn WITHOUT fog. Skipping fog
|
||||
// on additive surfaces keeps the sun bright at horizon
|
||||
// dusk/dawn (where fog would otherwise dim it to fog color).
|
||||
// Non-additive sky meshes (the dome, opaque cloud layers)
|
||||
// still mix toward fog with the floor mitigation in sky.frag.
|
||||
_shader.SetFloat("uApplyFog", sub.IsAdditive ? 0f : 1f);
|
||||
|
||||
uint tex = _textures.GetOrUpload(sub.SurfaceId);
|
||||
_gl.ActiveTexture(TextureUnit.Texture0);
|
||||
_gl.BindTexture(TextureTarget.Texture2D, tex);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue