#119: entity bounds must cover the parts - the gaze-dependent staircase vanish

User re-gate after 2163308/987313a: run-from-town stairs FIXED, barrel
GONE - but the stairs still vanish by VIEWING ANGLE (visible climbing
down, gone climbing up; same at the tower top). The gate3 probe data
exonerates everything downstream: the entity always draws with correct
batches when it reaches the dispatcher (cache hit:119, restZ correct,
zero WALK-REJECTs, never clip-culled) - so the vanish lives in the one
gaze-dependent gate the probe cannot see: the bounds-based cullers.

WorldEntity.RefreshAabb was a fixed +-5 m box around the entity ANCHOR.
The staircase's 43 parts spiral 15 m ABOVE the anchor, and BOTH
visibility gates derive from the box: the dispatcher's per-entity
frustum cull AND RetailPViewRenderer.EntitySphere (the viewcone sphere
= this box's bounding sphere). Looking up the spiral put the anchor's
neighborhood out of view -> the whole entity culled while 15 m of it
stood in front of the camera; looking down kept the anchor in view ->
visible. Exactly the reported asymmetry.

Fix: expand the box by the largest MeshRef part-translation magnitude
(rotation-invariant, so entity.Rotation needs no handling; identity-
part entities get offset 0 - behavior unchanged; scenery scale is
already baked into the part transforms).

Suites: App 246+1skip / Core 1431+2skip / UI 420 / Net 294.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-11 21:58:17 +02:00
parent 987313aa54
commit 1ca412d07b
2 changed files with 58 additions and 2 deletions

View file

@ -116,8 +116,35 @@ public sealed class WorldEntity
public void RefreshAabb()
{
var p = Position;
AabbMin = new Vector3(p.X - DefaultAabbRadius, p.Y - DefaultAabbRadius, p.Z - DefaultAabbRadius);
AabbMax = new Vector3(p.X + DefaultAabbRadius, p.Y + DefaultAabbRadius, p.Z + DefaultAabbRadius);
// #119 follow-up (2026-06-11): the box must cover the MESH, not just the
// anchor. A multi-part Setup's parts sit at root-relative offsets — the
// AAB3 tower's spiral staircase spans 15 m ABOVE its anchor — and BOTH
// visibility gates derive from this box: the dispatcher's per-entity
// frustum cull (WbDrawDispatcher.WalkEntitiesInto) and the viewcone
// sphere (RetailPViewRenderer.EntitySphere = this box's bounding
// sphere). A fixed ±5 m anchor box dropped the staircase whenever the
// gaze left the anchor's neighborhood: stairs visible looking down the
// spiral (anchor in view), gone looking up (anchor culled) — the
// user-reported direction/angle asymmetry. Expand by the largest part
// offset; using the offset MAGNITUDE keeps the box rotation-invariant,
// so entity.Rotation needs no handling here. Identity-part entities
// (1-part Setups, GfxObjs, scenery) get offset 0 — behavior unchanged.
float radius = DefaultAabbRadius;
var refs = MeshRefs;
if (refs is not null)
{
float maxOffset = 0f;
for (int i = 0; i < refs.Count; i++)
{
float len = refs[i].PartTransform.Translation.Length();
if (len > maxOffset) maxOffset = len;
}
radius += maxOffset;
}
AabbMin = new Vector3(p.X - radius, p.Y - radius, p.Z - radius);
AabbMax = new Vector3(p.X + radius, p.Y + radius, p.Z + radius);
AabbDirty = false;
}