Skip to content

fix(grab): Euler-extract gimbal-lock tolerance — actual fix for the reported grab inversion#205

Merged
JRickey merged 1 commit into
mainfrom
agent/grab-trace-logging
May 24, 2026
Merged

fix(grab): Euler-extract gimbal-lock tolerance — actual fix for the reported grab inversion#205
JRickey merged 1 commit into
mainfrom
agent/grab-trace-logging

Conversation

@JRickey
Copy link
Copy Markdown
Owner

@JRickey JRickey commented May 24, 2026

Summary

Real fix for the "victim upside-down with torso clipped into ground" grab-hold bug. Supersedes PR #204 (which landed earlier today based on the TC fork's stale-FTParts-transform-cache diagnosis and turned out to be a no-op for the offline reproducer — kept as defensive coverage).

JR reproduced the bug after PR #204 merged: Pikachu → Samus on Dreamland, ~50° tilt visible on the held victim. Live trace under `SSB64_GRAB_TRACE=1`:

  • `root_cache_pre = 0` and `hand_cache_pre = 0` on every one of 975 traced frames → PR fix(grab): port engine-only subset of TC grab-coupling geometry fixes #204's invalidate had nothing to clear.
  • Actual hand world matrix's X-axis row: `(0.0025, -0.0030, 0.9999923110)`.
  • `func_ovl2_800EDA0C` (`gm/gmcollision.c:285`) gimbal-lock branch uses exact float equality `dst[0][2] == 1.0F`. `0.9999923 != 1.0F` → general branch fires → `atan2(-0.003, 0.0025) = -0.866` extracted as `rotate.z` from quantization noise → ~50° spurious roll → tilted victim.

The check was always fragile; IDO/MIPS rounding lands at exact `1.0F` often enough that vanilla N64 works; modern toolchains' float math doesn't.

Fix

One-line tolerance under `#ifdef PORT` in `func_ovl2_800EDA0C`:

```c
#ifdef PORT
if ((dst[0][2] <= -0.9999F) || (dst[0][2] >= 0.9999F))
#else
if ((dst[0][2] == -1.0F) || (dst[0][2] == 1.0F))
#endif
```

`0.9999F` ≈ within 0.81° of pure ±90° yaw — narrow gimbal-lock window, doesn't trip for real rotations. After fix, trace shows `victim_out_rot.z = 0.000000` across the entire hold. Visual repro confirmed corrected by JR.

Also covers `scSubsysFighterOpeningProcUpdate` (Master Hand opening movie) which uses the same extraction pattern.

Files

Decomp commit `055659e35` on `JRickey/ssb-decomp-re#port-patches`.

Test plan

  • Build clean (`cmake --build build --target ssb64 -j 4`), no new warnings
  • Manual: Pikachu → Samus on Dreamland — victim upright in hold, no tilt (JR confirmed in-app)
  • Trace confirms `victim_out_rot.z = 0.0` across 975 ticks of held grab
  • Sanity: other grabber/victim pairs still hold correctly (no new tilt introduced by the tolerance widening — should be safe given 0.9999 = 0.81° band)
  • Sanity: Master Hand opening movie still poses fighter models correctly (shares the `func_ovl2_800EDA0C` path)

🤖 Generated with Claude Code

… reported grab inversion

Bumps the decomp pointer to pull a one-line tolerance change in
func_ovl2_800EDA0C that's the actual fix for the "victim upside-down
during grab hold" symptom several Windows/Linux reporters hit (and
which JR confirmed reproducible on macOS with Pikachu→Samus on
Dreamland after PR #204 landed but did NOT correct the visual).

PR #204's stale-FTParts-transform-cache work landed earlier today
based on the TC fork handoff doc's diagnosis. Live tracing in the
grab path with PR #204 active showed root_cache_pre=0 and
hand_cache_pre=0 on every one of 975 traced frames — the invalidate
had nothing to clear. Looking at the actual matrix the Euler-extract
function received gave 0.9999923 for dst[0][2] (X-axis row's Z
component), missing the exact-equality gimbal-lock branch by ~8e-6 of
float noise. atan2 on the remaining tiny components extracted ~50°
of garbage roll → tilted, "upside-down" victim.

Full investigation, repro trace methodology, and audit-hook for
similar precision-sensitive matched-decomp patterns in
docs/bugs/grab_pose_eulerextract_gimbal_2026-05-23.md. The
preceding stale-cache fix is kept (defensive, harmless) but marked
"PARTIALLY APPLIES (defensive); not the offline-bug fix" in the bug
index so future readers don't chase the same wrong tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant