feat(sky): split SkyRenderer into pre-/post-scene passes + retail -120m weather Z offset
Bug A (foreground rain) from docs/research/2026-04-26-sky-investigation-handoff.md:
rain mesh was only visible at horizon, not in the air between camera and
character. Two retail mechanisms ported here:
1. **Render order split.** Retail's `LScape::draw` at 0x00506330 calls
`GameSky::Draw(0)` BEFORE the landblock DrawBlock loop and
`GameSky::Draw(1)` AFTER — i.e. weather meshes render after scene
geometry so additive rain streaks paint on top of terrain and entities.
Acdream was rendering both passes pre-scene, so terrain immediately
painted over the rain.
Refactored `SkyRenderer.Render` into `RenderSky` (filter !IsWeather)
and `RenderWeather` (filter IsWeather) sharing a private `RenderPass`
core that takes a `weatherPass` bool. Partition is per-SkyObject by
`Properties & 0x04` (the WEATHER_BIT, mirroring tools/WeatherEnumerator).
Added `SkyObjectData.IsWeather` getter for the partition.
`GameWindow.OnRender` now calls `RenderSky` before terrain/static-mesh/
particles (line ~4322) and `RenderWeather` after particles (line ~4368).
2. **Weather Z offset.** Retail `GameSky::UpdatePosition` at 0x00506dd0,
lines 0x506e96..0x506e98:
if (((eax_13 & 4) != 0 && (eax_13 & 8) == 0))
int32_t var_4_1 = 0xc2f00000; // 0xc2f00000 == -120.0f
Weather objects (property bit 0x04 set, bit 0x08 unset) get their frame
origin set to player_pos + (0, 0, -120m). The rain cylinder GfxObjs
0x01004C42/0x01004C44 have local Z range 0.11..814.90 (815m tall, 113m
radius). Without the offset the cylinder bottom sat just above the
camera; with -120m the cylinder spans (camera-119.89)..(camera+694.90)
so the camera is inside.
`SkyRenderer.RenderPass` applies the -120m model translation when
`weatherPass` is true (line ~253-254).
3. **Legacy camera-attached emitter gated.** `UpdateWeatherParticles` —
the pre-research workaround that emitted camera-attached rain particles
(broken alpha fade, fixed disk around camera) — is now gated behind
`ACDREAM_FAKE_RAIN_PARTICLES=1`. Default off; the retail-faithful
world-space mesh is the default path.
User-verified: rain is now visible in foreground from many perspectives,
but the cylinder's open-top rim is still visible when looking straight up.
That rim issue is a separate brightness-excess bug filed for follow-up
(Translucency float not plumbed to shader; surface.Translucency=0.5 ignored
so streaks render at 2× retail intensity).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9567597814
commit
3e0da496e0
3 changed files with 130 additions and 5 deletions
|
|
@ -36,6 +36,23 @@ public sealed class SkyObjectData
|
|||
public uint GfxObjId;
|
||||
public uint Properties;
|
||||
|
||||
/// <summary>
|
||||
/// True when this SkyObject is flagged as weather (Properties bit
|
||||
/// <c>0x04</c>). Per the named retail decomp,
|
||||
/// <c>GameSky::CreateDeletePhysicsObjects</c> at <c>0x005073c0</c>
|
||||
/// passes <c>Properties & 0x04</c> as <c>arg5</c> of
|
||||
/// <c>GameSky::MakeObject</c> (<c>0x00506ee0</c>) — when set, the
|
||||
/// CPhysicsObj is added to <c>after_sky_cell</c> instead of
|
||||
/// <c>before_sky_cell</c>, and <c>GameSky::Draw(arg2=1)</c> at
|
||||
/// <c>0x00506ff0</c> draws that cell <i>after</i> the scene. acdream
|
||||
/// uses this flag to split the sky pass: non-weather objects render
|
||||
/// pre-scene (so terrain and entities z-test on top), weather meshes
|
||||
/// (e.g. the 815m-tall rain cylinders <c>0x01004C42</c>/<c>0x01004C44</c>)
|
||||
/// render post-scene with depth-test off so they overlay foreground
|
||||
/// geometry — matching retail's volumetric foreground-rain look.
|
||||
/// </summary>
|
||||
public bool IsWeather => (Properties & 0x04u) != 0u;
|
||||
|
||||
/// <summary>Object is visible at day-fraction <paramref name="t"/>
|
||||
/// by retail's begin/end semantics (r12 §2). Three cases:
|
||||
/// <list type="bullet">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue