feat(physics): use sloped terrain plane in FindEnvCollisions
Our previous FindEnvCollisions built a FLAT contact plane (Normal = +Z)
at the sampled terrain Z, discarding the triangle's actual slope.
Retail uses the real terrain polygon's plane (ACE Landblock.cs:125-137
find_terrain_poly → walkable.Plane) which IS sloped.
Without a true slope normal, AdjustOffset's projection of horizontal
velocity onto the plane produces no slope-aligned Z component — fine
for step-subdivision on flat ground, visibly wrong whenever the contact
plane is carried across frames (via PhysicsBody.ContactPlane persistence
from commit 93cbabb): the projection is a no-op and movement is purely
kinematic. With the real slope normal, projected motion correctly
follows the slope.
Not a user-visible bug fix by itself (DIAG LocalZ shows delta≈0 for the
local player everywhere; the "looks too high in water" issue the user
reported is actually a missing water-rendering feature, not a physics
bug). Landing it anyway because it matches retail behavior and removes
the "flat-plane-is-fine" assumption that would bite on any future
contact-plane-dependent code.
Additions:
- TerrainSurface.SampleSurface(localX, localY) → (Z, Normal), deriving
the plane normal analytically from the triangle's height gradient.
Matches the same triangle SampleZ already interpolates through.
- PhysicsEngine.SampleTerrainPlane(worldX, worldY) → System.Numerics.Plane,
the wrapper that bridges terrain space to transition space.
- TransitionTypes.FindEnvCollisions uses SampleTerrainPlane instead of
synthesizing a flat plane from SampleTerrainZ.
All 717 tests green. Flat-plane case is unchanged (Normal.Z = 1 when
the triangle is level, identical to the old plane).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
93cbabbc87
commit
40f120617d
3 changed files with 139 additions and 8 deletions
|
|
@ -110,6 +110,35 @@ public sealed class PhysicsEngine
|
|||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sample the outdoor terrain plane (Z + sloped normal) at the given
|
||||
/// world-space XY position. The returned <see cref="System.Numerics.Plane"/>
|
||||
/// has the true terrain-triangle normal (NOT a flat <c>(0,0,1)</c>), and
|
||||
/// its <c>D</c> is set so the plane passes through the sampled point. Used
|
||||
/// by <see cref="Transition"/> to build a CORRECT contact plane — a flat
|
||||
/// plane breaks slope tracking because <c>AdjustOffset</c>'s projection
|
||||
/// onto a flat plane cannot impart the Z component that horizontal
|
||||
/// velocity needs to follow the slope.
|
||||
/// </summary>
|
||||
public System.Numerics.Plane? SampleTerrainPlane(float worldX, float worldY)
|
||||
{
|
||||
foreach (var kvp in _landblocks)
|
||||
{
|
||||
var lb = kvp.Value;
|
||||
float localX = worldX - lb.WorldOffsetX;
|
||||
float localY = worldY - lb.WorldOffsetY;
|
||||
if (localX >= 0f && localX < 192f && localY >= 0f && localY < 192f)
|
||||
{
|
||||
var (z, normal) = lb.Terrain.SampleSurface(localX, localY);
|
||||
// System.Numerics.Plane convention: dot(Normal, P) + D == 0
|
||||
// for points P on the plane. Pick P = (worldX, worldY, z).
|
||||
float d = -(normal.X * worldX + normal.Y * worldY + normal.Z * z);
|
||||
return new System.Numerics.Plane(normal, d);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolve an entity's movement from <paramref name="currentPos"/> by
|
||||
/// applying <paramref name="delta"/> (XY only) and computing the correct Z
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue