feat(anim): integrate Omega for TurnRight/TurnLeft dead-reckoning
Remote entities in a Turn cycle had no rotational dead-reckoning: their Rotation quaternion only updated on UpdatePosition arrival, making in-place turns look jumpy when the server sent updates at 5-10Hz. The sequencer exposes Omega (radians/sec per axis) via the same SetVelocity/ SetOmega pair retail uses, so all we need to do is integrate it. Implementation in TickAnimations: float angle = |omega| * dt; Quaternion delta = CreateFromAxisAngle(normalize(omega), angle); entity.Rotation = normalize(entity.Rotation * delta); Gated on the low-byte motion being TurnRight (0x0D) or TurnLeft (0x0E) so we don't apply spin to non-turning cycles that happen to carry a nonzero omega (e.g. creature sway emotes). Matches ACE Sequence.apply_physics L221-L229: frame.Rotate(Omega * quantum) which treats the argument as a local-axis scaled rotation. No new tests — Omega is the rotational dual of Velocity, already covered by the velocity-integration tests. 659 tests green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
24974cfbb9
commit
dc317a321b
1 changed files with 29 additions and 0 deletions
|
|
@ -3436,6 +3436,35 @@ public sealed class GameWindow : IDisposable
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rotation integration: if the sequencer's Omega is non-zero
|
||||
// (TurnRight / TurnLeft / any cycle with baked-in spin), rotate
|
||||
// the entity's quaternion around the omega axis by |omega|*dt.
|
||||
// Matches ACE Sequence.apply_physics L221-L229:
|
||||
// frame.Rotate(Omega * quantum)
|
||||
// where frame.Rotate treats the argument as a local-axis
|
||||
// rotation. Only kicks in for Turn cycles (low byte 0x0D/0x0E)
|
||||
// — other motions either have zero omega or integrate rotation
|
||||
// server-side.
|
||||
var seqOmega = ae.Sequencer.CurrentOmega;
|
||||
if (seqOmega.LengthSquared() > 1e-6f)
|
||||
{
|
||||
uint mlo2 = ae.Sequencer.CurrentMotion & 0xFFu;
|
||||
bool isTurning = mlo2 == 0x0D || mlo2 == 0x0E; // TurnRight / TurnLeft
|
||||
if (isTurning)
|
||||
{
|
||||
// Omega as a scaled axis-angle. Build a delta quaternion
|
||||
// and compose it on the entity's current rotation.
|
||||
float angle = seqOmega.Length() * dt;
|
||||
if (angle > 1e-5f)
|
||||
{
|
||||
var axis = System.Numerics.Vector3.Normalize(seqOmega);
|
||||
var deltaRot = System.Numerics.Quaternion.CreateFromAxisAngle(axis, angle);
|
||||
ae.Entity.Rotation = System.Numerics.Quaternion.Normalize(
|
||||
ae.Entity.Rotation * deltaRot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Get per-part (origin, orientation) from either sequencer or legacy ──
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue