Terrain Surface Snap for Landed Ships
Issue: #760 Parent Epic: #429 (Planetary Terrain System)
Problem
When a ship is landed, the physics server computes the ship’s position using the exact heightmap bilinear sample at the landing surface normal. The web client renders the terrain using a 33x33 vertex grid per patch, with GPU linear interpolation between vertices. The interpolated surface between vertices doesn’t exactly match the heightmap sample, causing the ship mesh to float visibly above (or clip below) the rendered terrain.
Solution
When pinning a landed ship to the rotating body surface, use the client’s own TerrainManager.getTerrainHeight() to compute the terrain elevation at the ship’s direction from the body center. This ensures the ship sits exactly on the terrain surface the player sees.
Algorithm
In cockpitExtrapolation.js, after computing the landed body-local offset:
- Compute the ship’s unit direction from body center (body-local space)
- Query
TerrainManager.getTerrainHeight(bodyName, nx, ny, nz)for the client-side terrain elevation - If terrain height is available, recompute the ship’s distance from body center as:
r = baseRadius + clientTerrainHeight + groundContactOffset - Set the body-local offset magnitude to this radius (preserving direction)
- Transform back to world coordinates as before
Fallback
If getTerrainHeight returns null (terrain not loaded yet, or body has no terrain), fall back to the server-provided position (existing behavior).
Ground Contact Offset
The ship class’s ground_contact_offset is needed on the client side. This is the distance from the ship’s center of mass to its feet/contact point. For the planetary_lander class, this is 4.56 meters (foot pad bottom in the GLB model).
The offset is passed from the server via the ship state data. If not available, default to 0.
Files Changed
services/web-client/src/cockpitExtrapolation.js— Snap landed ship to client terrain surfaceservices/web-client/src/terrain/TerrainProfiles.js— ExportgetTerrainProfile(already exported)