MP: FIX peer spin hang/divergence -- exact quaternion integration + frequent orientation (task #50)
Answers 'how did the original handle this?' from the decomp (subagent hunt):
the 1995 binary's replicant reckoner (FUN_004ab1c8 -> FUN_00409f58, part_000.c:9359)
integrates heading EXACTLY: build a unit axis-angle rotation quaternion from
angularVelocity*dt ({axis*sin(t/2), cos(t/2)}) and Hamilton-multiply it onto the
heading (FUN_00409d9c) -- exact for any timestep, stays on the unit sphere. It
further carries the full orientation quaternion in the FREQUENT pose record
(FUN_0040a938, 7-float pose), so the dead-reckon gap stays tiny.
Our reconstruction diverged two ways, both fixed:
1. ReconQuatIntegrate (mechrecon.hpp) -- the reconstruction of FUN_00409f58 -- was
STUBBED as , a crude small-angle VECTOR add. Restored to
the real exact axis-angle composition. (A 'no stand-ins' violation: the comment
even wrongly claimed Quaternion::Add == FUN_00409f58.)
2. The engine Mover reckoner (MOVER.cpp AcceleratedDeadReckoner/LinearDeadReckoner)
also did the vector Add on projectedOrigin.angularPosition -> over a long peer
record gap it diverged to ~180deg then snapped (the reported spin HANG/hesitation).
Routed both through a new ExactAngularProject() helper (same exact math).
3. Orientation only rode the sparse type-4 resync; during a PURE spin the linear
dense-send never fires (not translating), so the gap ballooned (~1.6s) and the now-
exact projection sat far ahead -> the slerp jumped. Added an ANGULAR dense-send
(resync every frame while |yawRate|>0.1), mirroring the original's frequent-
orientation model -> gap stays tiny -> smooth.
Verified live-autonomous (BT_AUTODRIVE+BT_FORCE_TURN + BT_RENDHDG render-rate probe):
the ~180deg divergence + multi-radian snaps are GONE (rendered maxStep 0.05-0.10 rad,
no jumps). User confirms: no frame hang/hesitation. MOVER.cpp change is strictly
more correct (exact==crude for the small per-frame master case; only large-gap peer
extrapolation changes), so walking is unaffected.
KNOWN REMAINING (separate, smaller): the turn-STEP leg animation (trn clip, mech2.cpp
advance_normally) runs at a FIXED idleStrideScale cadence that does not scale with the
rotation rate, so the legs lag/skip vs the (now-correct) body rotation. Next.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9eff043973
commit
a8eb8a427f
+32
-8
@@ -11,6 +11,34 @@
|
||||
#include "line.h"
|
||||
#include "app.h"
|
||||
#include "notation.h"
|
||||
#include <math.h>
|
||||
|
||||
//
|
||||
// EXACT axis-angle rotation composition -- matches the 1995 BT binary's angular
|
||||
// integrator (FUN_00409f58): build a unit rotation quaternion from the rotation
|
||||
// VECTOR `rotVec` (angle = |rotVec|, axis = rotVec/angle) as { axis*sin(angle/2),
|
||||
// cos(angle/2) } and Hamilton-multiply it onto `base`. The dead-reckoner previously
|
||||
// did `out.Add(base, rotVec)` -- adding a scaled angular-velocity vector to the heading
|
||||
// quaternion. That is only a small-angle approximation: fine per-frame (tiny angle),
|
||||
// but over a long replicant dead-reckon gap it DIVERGES (the heading drifts to ~180deg
|
||||
// then snaps -- the spinning-peer hesitation). This composition is exact for any angle
|
||||
// and stays on the unit sphere.
|
||||
//
|
||||
static void ExactAngularProject(Quaternion &out, const Quaternion &base, const Vector3D &rotVec)
|
||||
{
|
||||
const Scalar ang = rotVec.Length();
|
||||
if (ang > 1.0e-6f)
|
||||
{
|
||||
const Scalar h = 0.5f * (Scalar)fmodf((float)ang, 6.2831853f); // half of angle mod 2pi
|
||||
const Scalar s = (Scalar)(sinf((float)h) / ang); // sin(angle/2)/angle
|
||||
const Quaternion dq(rotVec.x * s, rotVec.y * s, rotVec.z * s, (Scalar)cosf((float)h));
|
||||
out.Multiply(base, dq); // base (X) dq
|
||||
}
|
||||
else
|
||||
{
|
||||
out = base;
|
||||
}
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//############################### Mover #################################
|
||||
@@ -395,10 +423,8 @@ Logical
|
||||
//-------------------------------
|
||||
//
|
||||
position_delta.Multiply(updateVelocity.angularMotion, time_slice);
|
||||
projectedOrigin.angularPosition.Add(
|
||||
updateOrigin.angularPosition,
|
||||
position_delta
|
||||
);
|
||||
ExactAngularProject(projectedOrigin.angularPosition, // was .Add (diverging vector-add)
|
||||
updateOrigin.angularPosition, position_delta);
|
||||
projectedVelocity = updateVelocity;
|
||||
|
||||
Check_Fpu();
|
||||
@@ -460,10 +486,8 @@ Logical
|
||||
updateVelocity.angularMotion,
|
||||
time_slice
|
||||
);
|
||||
projectedOrigin.angularPosition.Add(
|
||||
updateOrigin.angularPosition,
|
||||
position_delta
|
||||
);
|
||||
ExactAngularProject(projectedOrigin.angularPosition, // was .Add (diverging vector-add)
|
||||
updateOrigin.angularPosition, position_delta);
|
||||
|
||||
//
|
||||
//-----------------------------------
|
||||
|
||||
Reference in New Issue
Block a user