Commit Graph
2 Commits
Author SHA1 Message Date
CydandClaude Fable 5 07eb74d1f7 BT410 5.3.80: joint articulation is live -- 22 nodes, and the twist reaches the board
RecurseSKLFile now builds a joint renderable for any node whose page name
resolves to a live skeleton Joint: HingeX/Y/Z -> HingeRenderable (watching
Joint::GetHinge), Ball -> BallJointRenderable (watching GetEulerAngles),
otherwise the static path.  Each holds the rest offset in one DCS and the live
rotation in a child DCS, and its Execute diffs the watched value and calls
DPL_FLUSH_DCS -- the engine's own mechanism (L4VIDRND.CPP:1026+).  The value
comes from the mech's JointSubsystem via ResolveJoint, so sim and renderer
read one source.  Gated on BT_JOINTS while it proves out.

  [skl] video\max.skl -> 26 nodes, 1 objects, 1 eye, 22 articulated

The bridge reported anim_abs=1 joints=0 twist=+0.00 before; it now reports
joints=1 twist=-0.86, matching the game's [torso] twist=-0.856.  With the mech
stationary, frames that differed by 0.0% now differ by 62-80%.

A crash it exposed: Mech::ResolveJoint passed segment->GetJointIndex()
straight to GetJoint unchecked, and a segment with no joint reports -1 --
GetNthImplementation then indexes [base + -1*4] and dies (guest 00426A1D).
Torso never hit it because it only asks for its own authored joint name; the
walk asks for every page.  Now bounds-checked against GetJointCount.

Open: the canopy does not stay rigid in the view, though it and the eye hang
off the same articulated node.  Cancelling the bridge's cage compensation
(CAGE_TWIST_SIGN=0) did not close it.  Leading hypothesis: SetupCull builds
worldToEyeMatrix from GetSegmentToWorld(siteeyepoint) -- the SIMULATION's
segment transform -- independent of the render tree, so the canopy follows our
render chain and the eye follows the sim's, and they diverge whenever one
carries the twist and the other does not.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 20:46:18 -05:00
CydandClaude Fable 5 8769dae0ac BT410 5.3.79: the twist is live in the sim and absent from the wire
pod_render_twist.conf isolates it -- throttle and turn zero, torso sweeping,
[sim] confirming spd=0, so only the torso joint can move the view.  Five
frames across a full sweep differ by 0-74 pixels: the view does not move.
The same run's telemetry has the twist sweeping the full authored range
(-0.895 to -0.022 rad, cmdL/cmdR alternating, joint resolved) and the bridge
reports anim_abs=1, joints=0 -- only the root articulates.

The cause: RecurseSKLFile builds each skeleton node's DCS with a baked matrix
and flushes it once at build time, and nothing re-flushes a node when its
joint angle changes.  TorsoSimulation faithfully calls SetRotation() every
frame, updating the Joint object, but no renderable reads that back into the
node's dpl_DCS.  The simulation twists; the board never hears.

The missing piece is the per-frame joint renderable -- the engine's
ChildOffsetRenderable family (L4VIDRND.CPP:930) exists for exactly this, and
our RootRenderable already proves the pattern for the hull.  That one brick
unlocks the torso twist (and the cockpit eye panning with it, since the eye
hangs off that chain), the leg gait, and weapon-pod aim.  Until then the mech
translates through the world as a rigid body -- which is what every frame so
far has shown.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 20:13:12 -05:00