fix(app+core): Phase B.3 — player cull-exempt, jump height, slope Z
Three user-reported movement fixes: 1. Player disappears when facing away: StaticMeshRenderer now accepts an alwaysVisibleEntityId. When a culled landblock contains the player entity, it is still drawn. Prevents the frustum culler from hiding the player character when they walk far from their spawn landblock. 2. Jump too high: JumpImpulse reduced from 10.0 to 3.5 (placeholder; retail scales by Jump skill value from the server). 3. Slope Z alignment: replaced the frame-delta slope bias with a foot-forward sampling approach — sample terrain Z at 1 unit ahead in the walk direction and use max(center, foot) as the ground Z. Handles multi-grade slopes where the terrain rises faster than a single-point sample tracks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dc0341e85a
commit
192e066182
4 changed files with 41 additions and 18 deletions
|
|
@ -78,7 +78,8 @@ public sealed unsafe class StaticMeshRenderer : IDisposable
|
|||
|
||||
public void Draw(ICamera camera,
|
||||
IEnumerable<(uint LandblockId, Vector3 AabbMin, Vector3 AabbMax, IReadOnlyList<WorldEntity> Entities)> landblockEntries,
|
||||
FrustumPlanes? frustum = null)
|
||||
FrustumPlanes? frustum = null,
|
||||
uint? alwaysVisibleEntityId = null)
|
||||
{
|
||||
_shader.Use();
|
||||
_shader.SetMatrix4("uView", camera.View);
|
||||
|
|
@ -91,9 +92,19 @@ public sealed unsafe class StaticMeshRenderer : IDisposable
|
|||
{
|
||||
// Per-landblock frustum cull: one AABB test skips all entities in
|
||||
// this landblock if it is fully outside the view frustum.
|
||||
// Exception: never cull a landblock containing the player entity.
|
||||
if (frustum is not null &&
|
||||
!FrustumCuller.IsAabbVisible(frustum.Value, entry.AabbMin, entry.AabbMax))
|
||||
continue;
|
||||
{
|
||||
// Check if this landblock contains the always-visible entity.
|
||||
bool hasAlwaysVisible = false;
|
||||
if (alwaysVisibleEntityId is not null)
|
||||
{
|
||||
foreach (var e in entry.Entities)
|
||||
if (e.Id == alwaysVisibleEntityId.Value) { hasAlwaysVisible = true; break; }
|
||||
}
|
||||
if (!hasAlwaysVisible) continue;
|
||||
}
|
||||
|
||||
foreach (var entity in entry.Entities)
|
||||
{
|
||||
|
|
@ -168,10 +179,18 @@ public sealed unsafe class StaticMeshRenderer : IDisposable
|
|||
|
||||
foreach (var entry in landblockEntries)
|
||||
{
|
||||
// Same per-landblock frustum cull for the translucent pass.
|
||||
// Same per-landblock frustum cull + always-visible exception for pass 2.
|
||||
if (frustum is not null &&
|
||||
!FrustumCuller.IsAabbVisible(frustum.Value, entry.AabbMin, entry.AabbMax))
|
||||
continue;
|
||||
{
|
||||
bool hasAlwaysVisible = false;
|
||||
if (alwaysVisibleEntityId is not null)
|
||||
{
|
||||
foreach (var e in entry.Entities)
|
||||
if (e.Id == alwaysVisibleEntityId.Value) { hasAlwaysVisible = true; break; }
|
||||
}
|
||||
if (!hasAlwaysVisible) continue;
|
||||
}
|
||||
|
||||
foreach (var entity in entry.Entities)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue