Shadow: authentic terrain tilt + decal draw order (feet layer correctly)

User report: the ground shadow painted OVER the mech's feet.  Root cause: the
flat quad + big depth-bias (-0.004 ~= 2-4 world units) workaround for slope
burial -- a bias big enough to beat the TERRAIN also beat the FEET in the
depth test, and the shadow drew in the late alpha-blend pass (after the mech),
so z-arbitration was the only layering control.

Fix, four co-dependent parts (user-verified live: feet on top, opaque,
survives inclines/declines):

- TILT (mech.cpp UpdateShadowJoint): apply the SKL's own contract for
  jointshadow ("apply terrain angle to pitch and roll") -- quad up aligned to
  the surface normal via an orthonormal basis fed to the ENGINE's own
  LinearMatrix->EulerAngles conversion.  Hand-derived Euler signs are exactly
  how the prior tilt attempts "dug into the hillside"; the engine conversion
  is convention-proof.  ~35 deg cliff-guard cap.
- SAMPLER (mech4.cpp): surface gradient from the collision probes PLUS
  BTVisualGroundLift per probe -- the quad hugs the VISIBLE terrain, whose
  lift varies across a slope; world->local rotation by the TRUE yaw from
  localToWorld, not the drift-prone gDriveHeading mirror (the task-#48 bug
  class).  BT_SHADOW_LOG traces the normals.
- DRAW ORDER (new PASS_SHADOW, l4d3d.h/L4VIDRND/L4VIDEO): shadows draw
  between the STATIC terrain and the DYNAMIC opaque bodies -- the classic
  decal order.  The mech, drawn after, z-passes over the shadow: the bias
  can never paint the shadow over the feet, structurally.
- BIAS pairing (L4D3D.cpp): tilt on (default) -> decal epsilon -0.0008;
  BT_SHADOW_TILT=0 flat fallback -> the old -0.004.  BT_SHADOW_BIAS overrides.

KB (locomotion.md): the four-part arrangement recorded as co-dependent, with
the gait-desync-symptom diagnostic hint retained.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-09 16:59:48 -05:00
co-authored by Claude Fable 5
parent 099cad998d
commit b6fe686b22
7 changed files with 145 additions and 30 deletions
+13
View File
@@ -143,6 +143,18 @@ void HierarchicalDrawComponent::Execute()
{
if (isDeathDraw || !l4_application->IsDead())
{
// GROUND SHADOW (task #49b): tshd proxies go to the dedicated
// PASS_SHADOW list ONLY -- drawn after the static terrain but
// before the dynamic opaque bodies, so the mech's feet z-pass
// over the shadow instead of the biased shadow painting over
// the feet. (Their drawOps carry alphaTest=1, which would
// otherwise route them to the late alpha-blend pass.)
if (graphicalObject->GetIsShadow())
{
myRenderer->AddToPassList(graphicalObject, PASS_SHADOW);
}
else
{
bool addedToOpaqueList = false, addedToAlphaList = false, addedToDecalList = false, addedToSphereList = false, addedToSkyList = false;
for (int i=0; i<graphicalObject->GetDrawOpCount(); i++)
{
@@ -187,6 +199,7 @@ void HierarchicalDrawComponent::Execute()
}
}
}
} // close the non-shadow classification branch (task #49b)
}
}
}