T3 (BR-5): viewconeCheck port - per-view sphere culling for statics/dynamics/particles, weather player-gate, unattached outdoor emitters
Ports Render::viewconeCheck (Ghidra 0x0054c250): meshes are sphere-CULLED per portal view, never hard-clipped. NEW ViewconeCuller lifts each slice's <=8 clip-space half-planes to world-space eye-edge planes (the view_vertex.plane analog, acclient.h:32483 - one matrix fold: L = VP rows . P) and tests bounding spheres from the entity's cached AABB (the dispatcher's own cull bounds source). Gating now matches retail's shape end to end: - Per-cell STATICS: sphere vs THEIR CELL's views - the statics-through- walls fix (the cottage phantom staircase's actual draw path: a static outside every view of its cell no longer paints through the wall). - DYNAMICS (last pass): sphere vs their cell's views; outdoor/unresolved vs the outside views (pass-all under the outdoor root). A dynamic in a non-flooded room culls HERE - retail never reaches an object whose cell is not in the draw list; the partition still routes it so the CULL is what drops it, retail's shape exactly. - OutdoorStatic (landscape pass): pre-filtered per outside slice; the per-slice entity gl_ClipDistance routing is DELETED (entities draw outside the clip bracket; terrain/sky keep their plane clip). - PARTICLES: the scissor-AABB gate is DELETED; emitters gate through their cone-surviving owners (candle-flames-through-walls fix). - WEATHER: gated on the PLAYER being outside (retail is_player_outside - an indoor player gets no rain even looking out a doorway). Closes weather-gate-player-vs-viewer. - UNATTACHED emitters (campfires) get their missing outdoor-root pass (closes unattached-particles-dropped-outdoors). Suites: App 226 green (flood gates included), Core baseline unchanged (1398 + 4 pre-existing #99-era). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
88f3ce1fa0
commit
a6aec8c32f
3 changed files with 268 additions and 24 deletions
|
|
@ -7646,6 +7646,7 @@ public sealed class GameWindow : IDisposable
|
|||
playerLb,
|
||||
animatedIds,
|
||||
renderSky,
|
||||
renderWeather: playerSeenOutside,
|
||||
kf,
|
||||
environOverrideActive),
|
||||
// T1: retail's depth discipline (PView::DrawCells, Ghidra 0x005a4840).
|
||||
|
|
@ -7877,6 +7878,25 @@ public sealed class GameWindow : IDisposable
|
|||
AcDream.Core.Vfx.ParticleRenderPass.Scene);
|
||||
}
|
||||
}
|
||||
else if (clipRoot is { IsOutdoorNode: true }
|
||||
&& _particleSystem is not null && _particleRenderer is not null)
|
||||
{
|
||||
// T3 (BR-5): unattached emitters (campfires, ground effects —
|
||||
// AttachedObjectId == 0) under the OUTDOOR root. The unified
|
||||
// path's attached emitters draw via the landscape slice + the
|
||||
// per-cell callbacks; unattached ones had NO pass on
|
||||
// outdoor-node frames (the unattached-particles-dropped-
|
||||
// outdoors divergence, adjusted-confirmed). The outdoor root's
|
||||
// outside view is full-screen (cone pass-all); depth test
|
||||
// composites them against the world.
|
||||
sigSceneParticles = sigSceneParticles == "none" ? "unattached" : sigSceneParticles + "+unattached";
|
||||
_particleRenderer.Draw(
|
||||
_particleSystem,
|
||||
camera,
|
||||
camPos,
|
||||
AcDream.Core.Vfx.ParticleRenderPass.Scene,
|
||||
emitter => emitter.AttachedObjectId == 0);
|
||||
}
|
||||
|
||||
// Bug A fix (post-#26 worktree, 2026-04-26): weather sky
|
||||
// Outdoor LScape post-scene weather. Indoor weather through an exit portal is
|
||||
|
|
@ -9480,6 +9500,7 @@ public sealed class GameWindow : IDisposable
|
|||
uint? playerLb,
|
||||
HashSet<uint>? animatedIds,
|
||||
bool renderSky,
|
||||
bool renderWeather,
|
||||
AcDream.Core.World.SkyKeyframe kf,
|
||||
bool environOverrideActive)
|
||||
{
|
||||
|
|
@ -9510,6 +9531,11 @@ public sealed class GameWindow : IDisposable
|
|||
_terrainCpuSampleCursor = (_terrainCpuSampleCursor + 1) % _terrainCpuSamples.Length;
|
||||
MaybeFlushTerrainDiag();
|
||||
|
||||
// T3 (BR-5): entities draw OUTSIDE the clip bracket — retail meshes
|
||||
// are viewcone-CHECKED, never hard-clipped (Ghidra 0x0054c250); the
|
||||
// sphere pre-filter already ran in RetailPViewRenderer (OutdoorEntities
|
||||
// is the per-slice survivor set).
|
||||
DisableClipDistances();
|
||||
if (sliceCtx.OutdoorEntities.Count > 0)
|
||||
{
|
||||
var sceneryEntry = (playerLb ?? 0u, System.Numerics.Vector3.Zero, System.Numerics.Vector3.Zero,
|
||||
|
|
@ -9539,8 +9565,13 @@ public sealed class GameWindow : IDisposable
|
|||
&& _outdoorSceneParticleEntityIds.Contains(emitter.AttachedObjectId));
|
||||
}
|
||||
|
||||
// T3 (BR-5): weather gates on the PLAYER being outside, not the viewer
|
||||
// root — retail draws weather only when is_player_outside (the rain
|
||||
// cylinder rides the player; an indoor player gets NO rain even while
|
||||
// looking out a doorway). Closes the rain-through-doorways divergence
|
||||
// (weather-gate-player-vs-viewer, adjusted-confirmed).
|
||||
EnableClipDistances();
|
||||
if (renderSky)
|
||||
if (renderSky && renderWeather)
|
||||
{
|
||||
_skyRenderer?.RenderWeather(camera, camPos, (float)WorldTime.DayFraction,
|
||||
_activeDayGroup, kf, environOverrideActive);
|
||||
|
|
@ -9620,8 +9651,12 @@ public sealed class GameWindow : IDisposable
|
|||
if (_visibleSceneParticleEntityIds.Count == 0)
|
||||
return;
|
||||
|
||||
// T3 (BR-5): the scissor-AABB gate is DELETED — retail gates particles
|
||||
// like meshes (viewcone on the owner; depth does the pixels). The
|
||||
// CellEntities set is already the cone-surviving owner list, so the
|
||||
// id-predicate below IS the cone gate; the punch/seal depth discipline
|
||||
// composites the pixels.
|
||||
DisableClipDistances();
|
||||
bool scissor = BeginDoorwayScissor(true, sliceCtx.Slice.NdcAabb);
|
||||
_particleRenderer.Draw(
|
||||
_particleSystem,
|
||||
camera,
|
||||
|
|
@ -9629,8 +9664,6 @@ public sealed class GameWindow : IDisposable
|
|||
AcDream.Core.Vfx.ParticleRenderPass.Scene,
|
||||
emitter => emitter.AttachedObjectId != 0
|
||||
&& _visibleSceneParticleEntityIds.Contains(emitter.AttachedObjectId));
|
||||
if (scissor)
|
||||
_gl!.Disable(EnableCap.ScissorTest);
|
||||
DisableClipDistances();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue