feat(physics): CylSphere collision for trees, rocks, NPCs
Most scenery objects (trees, rocks) use CylSphere collision from their Setup, not PhysicsBSP. Register these in ShadowObjectRegistry with a Cylinder collision type. FindObjCollisions now handles both: - BSP: full polygon collision via BSPQuery (buildings, stabs) - Cylinder: radial + vertical cylinder-sphere test (trees, NPCs) Diagnostics showed 170 CylSphere entities vs 278 BSP entities in the Holtburg landblock alone — this roughly doubles collision coverage. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2a4aaf4db7
commit
14b0a6e2b8
3 changed files with 119 additions and 23 deletions
|
|
@ -1800,8 +1800,65 @@ public sealed class GameWindow : IDisposable
|
|||
|
||||
partIndex++;
|
||||
}
|
||||
|
||||
// If no BSP parts were registered, check for CylSphere collision
|
||||
// from the Setup (trees, rocks, NPCs use cylinder collision).
|
||||
if (partIndex == 0 || !entity.MeshRefs.Any(mr =>
|
||||
_physicsDataCache.GetGfxObj(mr.GfxObjId)?.BSP?.Root is not null))
|
||||
{
|
||||
var setup = _physicsDataCache.GetSetup(entity.SourceGfxObjOrSetupId);
|
||||
if (setup is not null && setup.CylSpheres.Count > 0)
|
||||
{
|
||||
var cyl = setup.CylSpheres[0];
|
||||
float cylRadius = cyl.Radius > 0 ? cyl.Radius : setup.Radius;
|
||||
if (cylRadius > 0)
|
||||
{
|
||||
_physicsEngine.ShadowObjects.Register(
|
||||
entity.Id, entity.SourceGfxObjOrSetupId,
|
||||
entity.Position + new System.Numerics.Vector3(cyl.Origin.X, cyl.Origin.Y, cyl.Origin.Z),
|
||||
entity.Rotation, cylRadius,
|
||||
origin.X, origin.Y, lb.LandblockId,
|
||||
AcDream.Core.Physics.ShadowCollisionType.Cylinder, cyl.Height);
|
||||
}
|
||||
}
|
||||
else if (setup is not null && setup.Spheres.Count > 0)
|
||||
{
|
||||
var sph = setup.Spheres[0];
|
||||
if (sph.Radius > 0)
|
||||
{
|
||||
_physicsEngine.ShadowObjects.Register(
|
||||
entity.Id, entity.SourceGfxObjOrSetupId,
|
||||
entity.Position + new System.Numerics.Vector3(sph.Origin.X, sph.Origin.Y, sph.Origin.Z),
|
||||
entity.Rotation, sph.Radius,
|
||||
origin.X, origin.Y, lb.LandblockId,
|
||||
AcDream.Core.Physics.ShadowCollisionType.Cylinder, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Debug: count collision types
|
||||
int withBSP = 0, withCyl = 0, noPhys = 0;
|
||||
foreach (var entity in lb.Entities)
|
||||
{
|
||||
bool hasBSP = false, hasCyl = false;
|
||||
foreach (var mr in entity.MeshRefs)
|
||||
{
|
||||
if (_physicsDataCache.GetGfxObj(mr.GfxObjId)?.BSP?.Root is not null)
|
||||
{ hasBSP = true; break; }
|
||||
}
|
||||
if (!hasBSP)
|
||||
{
|
||||
var setup = _physicsDataCache.GetSetup(entity.SourceGfxObjOrSetupId);
|
||||
if (setup is not null && (setup.CylSpheres.Count > 0 || setup.Spheres.Count > 0))
|
||||
hasCyl = true;
|
||||
}
|
||||
if (hasBSP) withBSP++;
|
||||
else if (hasCyl) withCyl++;
|
||||
else noPhys++;
|
||||
}
|
||||
Console.WriteLine($"shadow: lb=0x{lb.LandblockId:X8} ent={lb.Entities.Count} bsp={withBSP} cyl={withCyl} none={noPhys} reg={_physicsEngine.ShadowObjects.TotalRegistered}");
|
||||
|
||||
// Register each stab as a plugin snapshot so the plugin host has
|
||||
// visibility into the streaming world state.
|
||||
foreach (var entity in lb.Entities)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue