fix(lighting): match retail indoor ambient (0.20 neutral, not 0.10/0.09/0.08 warm)
Indoor cells rendered "almost black" because the hardcoded ambient at GameWindow.cs:8342-8345 was an early-2026 guess (0.10, 0.09, 0.08 — half retail brightness, warm-tinted) rather than the retail value. The named retail decomp (acclient.pdb, Sept 2013 EoR build) shows CellManager::ChangePosition @ 0x004559B0 calls SmartBox::SetWorldAmbientLight(0.2f, 0xFFFFFFFF) whenever the player's CObjCell::seen_outside flag is 0 — a flat 0.20 white floor, not a dungeon-tone warm color. Investigation also confirmed: - EnvCell.dat does NOT carry inline lights — CEnvCell::UnPack reads numVisibleCells where Binary Ninja's heuristic decomp inferred "num_lights". Retail's CObjCell.light_list is populated at runtime via add_light() calls from neighbouring cell light registrations + per-cell static-object Setup.Lights, NOT from the dat byte stream. - Setup.Lights from indoor static objects (entity.SourceGfxObjOrSetupId prefix 0x02xxxxxx) DO flow through LightInfoLoader.Load (line 5765) and reach LightManager via LightingHookSink. The wire is intact; the per-frame Tick + UBO upload chain (line 6865-6867) is intact. - Retail's particle system does NOT emit lights from particles themselves. The light comes from the owning Setup's LightInfo records. Pre-existing failures in DispatcherToMovementIntegrationTests, BSPStepUpTests, and MotionInterpreterTests are on the branch already and unrelated to this change (verified by stashing + retesting). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
67e64c79cf
commit
a54cd7bef6
2 changed files with 11 additions and 4 deletions
|
|
@ -8319,7 +8319,13 @@ public sealed class GameWindow : IDisposable
|
|||
/// Derive the current sun (directional light, slot 0 of the UBO)
|
||||
/// from the interpolated <see cref="AcDream.Core.World.SkyKeyframe"/>,
|
||||
/// plus the cell ambient. Indoor cells force the sun intensity to
|
||||
/// zero (r13 §13.7) and substitute a fixed dungeon-tone ambient.
|
||||
/// zero and substitute a flat 0.2 white ambient — exact retail
|
||||
/// behavior per <c>CellManager::ChangePosition</c> @ 0x004559B0,
|
||||
/// which calls <c>SmartBox::SetWorldAmbientLight(0.2f, 0xFFFFFFFF)</c>
|
||||
/// when the player's <c>CObjCell::seen_outside</c> flag is 0.
|
||||
/// Indoor brightness then comes from per-cell point lights
|
||||
/// (Setup.Lights on the cell's static objects, registered through
|
||||
/// <see cref="AcDream.Core.Lighting.LightingHookSink"/>).
|
||||
/// </summary>
|
||||
private void UpdateSunFromSky(AcDream.Core.World.SkyKeyframe kf, bool cameraInsideCell)
|
||||
{
|
||||
|
|
@ -8330,7 +8336,8 @@ public sealed class GameWindow : IDisposable
|
|||
|
||||
if (cameraInsideCell)
|
||||
{
|
||||
// Dungeon default per r13 §3 — warm-dark ambient, no sun.
|
||||
// Indoor default — retail's flat 0.2 neutral ambient, sun
|
||||
// zeroed. See xref to retail decomp in the doc comment above.
|
||||
Lighting.Sun = new AcDream.Core.Lighting.LightSource
|
||||
{
|
||||
Kind = AcDream.Core.Lighting.LightKind.Directional,
|
||||
|
|
@ -8340,7 +8347,7 @@ public sealed class GameWindow : IDisposable
|
|||
Range = 1f,
|
||||
};
|
||||
Lighting.CurrentAmbient = new AcDream.Core.Lighting.CellAmbientState(
|
||||
AmbientColor: new System.Numerics.Vector3(0.10f, 0.09f, 0.08f),
|
||||
AmbientColor: new System.Numerics.Vector3(0.20f, 0.20f, 0.20f),
|
||||
SunColor: System.Numerics.Vector3.Zero,
|
||||
SunDirection: sunToWorld);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue