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:
co-authored by
Claude Fable 5
parent
099cad998d
commit
b6fe686b22
@@ -2210,17 +2210,43 @@ void
|
||||
BoundingBox *bZ = gnode->FindBoundingBoxUnder(qZ, &hZ);
|
||||
if (bC != 0 && bX != 0 && bZ != 0)
|
||||
{
|
||||
// surfaceY = probeY - downDistance; gradient -> world normal (-dH/dx, 1, -dH/dz)
|
||||
const Scalar yC = baseY - hC, yX = baseY - hX, yZ = baseY - hZ;
|
||||
// surfaceY = probeY - downDistance; then add the render-only
|
||||
// VISUAL lift at each probe (task #49b): the quad is drawn on
|
||||
// the VISIBLE terrain (btvisgnd conform), which runs 0..~2u
|
||||
// above the collision solid by DIFFERENT amounts across a
|
||||
// slope -- the VISUAL gradient, not the collision gradient,
|
||||
// is the surface the quad must hug. Lift 0 (no data/gated
|
||||
// off) degrades to the collision gradient.
|
||||
extern float BTVisualGroundLift(float x, float y, float z);
|
||||
Scalar yC = baseY - hC, yX = baseY - hX, yZ = baseY - hZ;
|
||||
yC += BTVisualGroundLift((float)cx, (float)yC, (float)cz);
|
||||
yX += BTVisualGroundLift((float)(cx+D), (float)yX, (float)cz);
|
||||
yZ += BTVisualGroundLift((float)cx, (float)yZ, (float)(cz+D));
|
||||
Vector3D wn(-(yX - yC) / D, 1.0f, -(yZ - yC) / D);
|
||||
Scalar len = (Scalar)sqrtf(wn.x * wn.x + wn.y * wn.y + wn.z * wn.z);
|
||||
if (len > 1e-6f) { wn.x /= len; wn.y /= len; wn.z /= len; }
|
||||
// world -> mech-local: rotate by -gDriveHeading about Y (mech upright, yaw only)
|
||||
const Scalar cth = (Scalar)cosf((float)gDriveHeading);
|
||||
const Scalar sth = (Scalar)sinf((float)gDriveHeading);
|
||||
// world -> mech-local: rotate by -yaw about Y. Use the TRUE
|
||||
// heading from localToWorld (engine convention MATRIX.cpp:196:
|
||||
// Z basis = (sin y, 0, cos y) -> yaw = atan2(z.x, z.z)) -- NOT
|
||||
// the gDriveHeading scalar mirror, which is seeded to 0 and
|
||||
// drifts from the real pose (the task-#48 goto-steering bug
|
||||
// class; a wrong yaw here swings the tilt as the mech turns).
|
||||
UnitVector zAxisS;
|
||||
localToWorld.GetFromAxis(Z_Axis, &zAxisS);
|
||||
const Scalar shYaw = (Scalar)atan2f((float)zAxisS.x, (float)zAxisS.z);
|
||||
const Scalar cth = (Scalar)cosf((float)shYaw);
|
||||
const Scalar sth = (Scalar)sinf((float)shYaw);
|
||||
shadowNormal.x = wn.x * cth - wn.z * sth;
|
||||
shadowNormal.y = wn.y;
|
||||
shadowNormal.z = wn.x * sth + wn.z * cth;
|
||||
if (getenv("BT_SHADOW_LOG"))
|
||||
{
|
||||
static float s_shLog = 0.0f; s_shLog += dt;
|
||||
if (s_shLog >= 1.0f) { s_shLog = 0.0f;
|
||||
DEBUG_STREAM << "[shtilt] wn=(" << wn.x << "," << wn.y << "," << wn.z
|
||||
<< ") local=(" << shadowNormal.x << "," << shadowNormal.y
|
||||
<< "," << shadowNormal.z << ") yaw=" << shYaw << "\n" << std::flush; }
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateShadowJoint(shadowNormal);
|
||||
|
||||
Reference in New Issue
Block a user