Torso-elevation aim LIVE: R/F now pitches the view + aim ray (pitch was inert)

User + tester reports: pitch does not work.  Root cause: the Torso sim
integrated the R/F / stick-Y axis into currentElevation (authored limits
and rates all correct) but NOTHING consumed it -- eyepointRotation's only
writer was the look-state switch, so neither the cockpit view nor the aim
ray (camera basis) ever pitched.  Shots always flew level; low targets
(trucks) were unhittable.

Fix (faithful: the pod's stick-Y pitches the EYE; the torso geometry does
not tilt): per-frame compose in the HUD tick --
eyepointRotation = EulerAngles(lookPitch + torsoElevation, lookYaw, 0);
BTCommitLookState now stores its look component in gBTLookPitch/Yaw; new
complete-type bridge BTGetTorsoElevation (torso.cpp, mirrors
BTGetTorsoTwist).  DPLEyeRenderable consumes it every frame, so the view
and the boresight aim pitch together (crosshair stays screen-centred).

Sign PIXEL-CALIBRATED via new diag BT_FORCE_ELEV=<-1..1> (pins the axis
headless): screenshots confirm axis +1 (key R) = aim UP, -1 (F) = down.
X still recenters.  Awaiting human verification.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-19 12:54:39 -05:00
co-authored by Claude Fable 5
parent 6f6a39b8c9
commit b85afed925
3 changed files with 67 additions and 0 deletions
+12
View File
@@ -199,3 +199,15 @@ the shell green), `BT_COP_DUMP` (per-batch punch/bbox), `BT_EYE_FWD=<f>` (eye po
- Uses: [[bgf-format]] (PUNCH, vertex tags) · [[rendering]] (ramp model, skeleton branch)
- Feeds: [[gauges-hud]] (the HUD overlays this view) · [[subsystems]] (gyro, task #56)
- Gotchas: [[reconstruction-gotchas]] §14 (LookAt axis guess), §15 (per-patch edge counting)
## Torso-elevation aim -> EYE PITCH (fixed 2026-07-19) [T2, pixel-calibrated]
User+tester report "pitch does not work": the Torso sim integrated R/F (stick-Y)
into `currentElevation` (authored limits/rates) but NOTHING consumed it — the
view and the aim ray (camera basis, `BTGetAimRay`) never pitched. Fix: the
per-frame HUD tick composes `eyepointRotation = EulerAngles(lookPitch + elev,
lookYaw, 0)` (mech4.cpp; look component stored by `BTCommitLookState` in
`gBTLookPitch/Yaw`; elevation via the new `BTGetTorsoElevation` torso.cpp
bridge). `DPLEyeRenderable` reads it every frame -> the view AND the boresight
aim pitch together (crosshair stays screen-centred, authentic). Sign
pixel-calibrated with `BT_FORCE_ELEV=<-1..1>` screenshots: axis +1 (key R) =
aim UP. The torso GEOMETRY does not tilt — only the eye, like the pod.
+43
View File
@@ -2716,6 +2716,18 @@ void
sElev = 0.0f; // X recenters pitch too
}
gBTElevAxis = sElev;
// DIAG (BT_FORCE_ELEV=<-1..1>): pin the elevation
// axis for headless pitch verification (no focus).
{
static float s_fe = -2.0f;
if (s_fe < -1.5f)
{
const char *fe = getenv("BT_FORCE_ELEV");
s_fe = fe ? (float)atof(fe) : -3.0f;
}
if (s_fe >= -1.0f)
gBTElevAxis = s_fe;
}
if (getenv("BT_INPUT_LOG"))
{
static float s_eacc = 0.0f; s_eacc += dt;
@@ -4933,6 +4945,28 @@ void
extern float gBTEyeTwist;
gBTEyeTwist = gBTHudTwist;
}
// TORSO-ELEVATION AIM -> EYE PITCH (issue #3 follow-up; user +
// tester report "pitch does not work"): the Torso sim integrated
// R/F into currentElevation (authored limits/rates) but NOTHING
// consumed it -- the view and the aim ray (camera basis) never
// pitched. The pod's stick-Y aim pitches the EYE (the torso
// geometry does not tilt); compose it per frame with the look-state
// angles into eyepointRotation, which DPLEyeRenderable reads every
// frame (VIEW = baseOffset * R). BTCommitLookState stores the
// look component in gBTLookPitch/Yaw (below); the elevation rides
// the pitch term. Pitch sign PIXEL-CALIBRATED (BT_FORCE_ELEV
// screenshots): elev pitched the view DOWN for a positive axis;
// R (axis +1) must aim UP -> +elev.
{
extern float gBTLookPitch, gBTLookYaw;
extern Scalar BTGetTorsoElevation(Subsystem *);
const float elev = (float)BTGetTorsoElevation(GetTorsoSubsystem());
eyepointRotation = EulerAngles(
Radian(Radian::Normalize(gBTLookPitch + elev)),
Radian(Radian::Normalize(gBTLookYaw)),
Radian(0.0f));
}
}
// task #6 ORDER FIX: the scripted block must run BEFORE the fire-push
@@ -6368,6 +6402,13 @@ int BTWeaponMountIsRear(void *ownerMech, int segIndex)
return rear;
}
// The current look-state eye component (pitch/yaw) -- stored so the per-frame
// eyepoint compose (the HUD tick above) can combine it with the live torso
// elevation. Single-viewpoint state (BTCommitLookState runs for the local
// player's mapper only), same pattern as the other viewpoint globals.
float gBTLookPitch = 0.0f;
float gBTLookYaw = 0.0f;
void BTCommitLookState(void *mech_v, int look_state)
{
Mech *m = (Mech *)mech_v;
@@ -6387,6 +6428,8 @@ void BTCommitLookState(void *mech_v, int look_state)
case 4: /*LookDown*/ pitch = m->lookFrontAngle; break;
default: break; // LookNone: identity
}
gBTLookPitch = (float)pitch; // per-frame compose adds elevation
gBTLookYaw = (float)yaw;
m->eyepointRotation = EulerAngles(
Radian(Radian::Normalize(pitch)),
Radian(Radian::Normalize(yaw)),
+12
View File
@@ -1040,6 +1040,18 @@ Scalar BTGetTorsoTwist(Subsystem *torso)
return torso ? ((Torso *)torso)->CurrentTwist() : 0.0f;
}
//
// Live torso ELEVATION (pitch aim, rad) -- Torso::currentElevation == the
// binary torso+0x1E4. Same complete-type-TU bridge pattern as
// BTGetTorsoTwist above. Consumed by the per-frame eyepoint compose
// (mech4.cpp): the R/F / stick-Y aim pitches the EYE only -- the torso
// geometry does not tilt, exactly like the pod.
//
Scalar BTGetTorsoElevation(Subsystem *torso)
{
return torso ? ((Torso *)torso)->CurrentElevation() : 0.0f;
}
//
// Task #56 bridge -- ADDRESS of the live torso twist for the gyro's external-
// pitch pointer (binary bt_mech stream tail: gyro+0x258 = torso+0x1D8; the gyro