fix(movement): correct facing direction quaternion convention
AC heading convention: 0=West, 90=North, 180=East, 270=South. Our internal yaw: 0=+X (East), PI/2=+Y (North). Conversion: heading_deg = 180 - yaw_degrees, then holtburger's from_heading formula: theta=(450-heading).toRad, w=cos(θ/2), z=sin(θ/2). Previously sent raw Yaw as axis-angle rotation which was ~90° off. Other clients now see correct facing direction. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5634e7114b
commit
6523c7199b
1 changed files with 29 additions and 2 deletions
|
|
@ -1896,8 +1896,7 @@ public sealed class GameWindow : IDisposable
|
||||||
float localY = result.Position.Y - (lbY - _liveCenterY) * 192f;
|
float localY = result.Position.Y - (lbY - _liveCenterY) * 192f;
|
||||||
uint wireCellId = ((uint)lbX << 24) | ((uint)lbY << 16) | (result.CellId & 0xFFFFu);
|
uint wireCellId = ((uint)lbX << 24) | ((uint)lbY << 16) | (result.CellId & 0xFFFFu);
|
||||||
var wirePos = new System.Numerics.Vector3(localX, localY, result.Position.Z);
|
var wirePos = new System.Numerics.Vector3(localX, localY, result.Position.Z);
|
||||||
var wireRot = System.Numerics.Quaternion.CreateFromAxisAngle(
|
var wireRot = YawToAcQuaternion(_playerController.Yaw);
|
||||||
System.Numerics.Vector3.UnitZ, _playerController.Yaw);
|
|
||||||
|
|
||||||
if (result.MotionStateChanged)
|
if (result.MotionStateChanged)
|
||||||
{
|
{
|
||||||
|
|
@ -1956,6 +1955,34 @@ public sealed class GameWindow : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert our internal yaw (math convention: 0=+X East, PI/2=+Y North)
|
||||||
|
/// to AC's quaternion heading convention.
|
||||||
|
/// AC heading: 0=West, 90=North, 180=East, 270=South.
|
||||||
|
/// Formula from holtburger Quaternion::from_heading.
|
||||||
|
/// </summary>
|
||||||
|
private static System.Numerics.Quaternion YawToAcQuaternion(float yaw)
|
||||||
|
{
|
||||||
|
// Our yaw → AC heading in degrees:
|
||||||
|
// yaw=0 → East → AC 180°, yaw=PI/2 → North → AC 90°
|
||||||
|
// heading_deg = 180 - yaw_degrees
|
||||||
|
float yawDeg = yaw * (180f / MathF.PI);
|
||||||
|
float headingDeg = 180f - yawDeg;
|
||||||
|
if (headingDeg < 0f) headingDeg += 360f;
|
||||||
|
if (headingDeg >= 360f) headingDeg -= 360f;
|
||||||
|
|
||||||
|
// holtburger from_heading: theta = (450 - heading_deg) in radians
|
||||||
|
float theta = (450f - headingDeg) * (MathF.PI / 180f);
|
||||||
|
float halfTheta = theta * 0.5f;
|
||||||
|
float w = MathF.Cos(halfTheta);
|
||||||
|
float z = MathF.Sin(halfTheta);
|
||||||
|
|
||||||
|
// Canonicalize: w must be non-negative
|
||||||
|
if (w < 0f) { w = -w; z = -z; }
|
||||||
|
|
||||||
|
return new System.Numerics.Quaternion(0f, 0f, z, w);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnCameraModeChanged(bool isFlyMode)
|
private void OnCameraModeChanged(bool isFlyMode)
|
||||||
{
|
{
|
||||||
if (_input is null) return;
|
if (_input is null) return;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue