【问题标题】:Quaternion to Euler angles algorithm - How to convert to 'Y = Up' and between handedness?四元数到欧拉角算法 - 如何转换为“Y = Up”和左右手之间?
【发布时间】:2012-07-14 14:12:13
【问题描述】:

我有一个在四元数和欧拉角之间转换的算法。

    public static Vector3 ToEulerAngles(this Quaternion q)
    {
        // Store the Euler angles in radians
        Vector3 pitchYawRoll = new Vector3();

        double sqw = q.W * q.W;
        double sqx = q.X * q.X;
        double sqy = q.Y * q.Y;
        double sqz = q.Z * q.Z;

        // If quaternion is normalised the unit is one, otherwise it is the correction factor
        double unit = sqx + sqy + sqz + sqw;
        double test = q.X * q.Y + q.Z * q.W;

        if (test > 0.4999f * unit)                              // 0.4999f OR 0.5f - EPSILON
        {
            // Singularity at north pole
            pitchYawRoll.Y = 2f * (float)Math.Atan2(q.X, q.W);  // Yaw
            pitchYawRoll.X = PI * 0.5f;                         // Pitch
            pitchYawRoll.Z = 0f;                                // Roll
            return pitchYawRoll;
        }
        else if (test < -0.4999f * unit)                        // -0.4999f OR -0.5f + EPSILON
        {
            // Singularity at south pole
            pitchYawRoll.Y = -2f * (float)Math.Atan2(q.X, q.W); // Yaw
            pitchYawRoll.X = -PI * 0.5f;                        // Pitch
            pitchYawRoll.Z = 0f;                                // Roll
            return pitchYawRoll;
        }
        else
        {
            pitchYawRoll.Y = (float)Math.Atan2(2f * q.Y * q.W - 2f * q.X * q.Z, sqx - sqy - sqz + sqw);       // Yaw
            pitchYawRoll.X = (float)Math.Asin(2f * test / unit);                                             // Pitch
            pitchYawRoll.Z = (float)Math.Atan2(2f * q.X * q.W - 2f * q.Y * q.Z, -sqx + sqy - sqz + sqw);      // Roll
        }

        return pitchYawRoll;
    }

此方法仅适用于 Z 轴朝上的右手笛卡尔坐标系。

为了使 Y 轴而不是 Z 轴指向上方,我需要进行哪些更改? (交换 X 和 Z 有用吗?)

如何适应左手坐标系?

编辑:

public static Quaternion CreateFromYawPitchRoll(float yaw, float pitch, float roll)
{
float num = roll * 0.5f;
float num2 = (float)Math.Sin((double)num);
float num3 = (float)Math.Cos((double)num);
float num4 = pitch * 0.5f;
float num5 = (float)Math.Sin((double)num4);
float num6 = (float)Math.Cos((double)num4);
float num7 = yaw * 0.5f;
float num8 = (float)Math.Sin((double)num7);
float num9 = (float)Math.Cos((double)num7);
Quaternion result;
result.X = num9 * num5 * num3 + num8 * num6 * num2;
result.Y = num8 * num6 * num3 - num9 * num5 * num2;
result.Z = num9 * num6 * num2 - num8 * num5 * num3;
result.W = num9 * num6 * num3 + num8 * num5 * num2;
return result;
}

【问题讨论】:

  • 四元数和欧拉角与坐标系的对齐方式和方向性无关。偏航、俯仰和滚动分别定义了围绕 z、y 和 x 轴的旋转。轴的方向无关紧要。
  • 如果我将它与 XNA 的 Quaternion.CreateFromYawPitchRoll 结合使用,那么我不会得到原始的 Quaternion。 msdn.microsoft.com/en-us/library/…
  • 那么函数可能使用不同的偏航/俯仰/滚动到轴的关联。交换欧拉角,使定义匹配。
  • 您能否根据我所做的 EDIT 发布一个示例,该示例现在包括 Quaternion.CreateFromYawPitchRoll?

标签: c# math quaternions


【解决方案1】:

以下是使用相同定义的偏航、俯仰、滚动的更改方法:

public static Quaternion CreateFromYawPitchRoll(float yaw, float pitch, float roll)
{
    float rollOver2 = roll * 0.5f;
    float sinRollOver2 = (float)Math.Sin((double)rollOver2);
    float cosRollOver2 = (float)Math.Cos((double)rollOver2);
    float pitchOver2 = pitch * 0.5f;
    float sinPitchOver2 = (float)Math.Sin((double)pitchOver2);
    float cosPitchOver2 = (float)Math.Cos((double)pitchOver2);
    float yawOver2 = yaw * 0.5f;
    float sinYawOver2 = (float)Math.Sin((double)yawOver2);
    float cosYawOver2 = (float)Math.Cos((double)yawOver2);
    Quaternion result;
    result.X = cosYawOver2 * cosPitchOver2 * cosRollOver2 + sinYawOver2 * sinPitchOver2 * sinRollOver2;
    result.Y = cosYawOver2 * cosPitchOver2 * sinRollOver2 - sinYawOver2 * sinPitchOver2 * cosRollOver2;
    result.Z = cosYawOver2 * sinPitchOver2 * cosRollOver2 + sinYawOver2 * cosPitchOver2 * sinRollOver2;
    result.W = sinYawOver2 * cosPitchOver2 * cosRollOver2 - cosYawOver2 * sinPitchOver2 * sinRollOver2;
    return result;
} 

对于ToEulerAngles(省略奇点):

pitchYawRoll.Y = (float)Math.Atan2(2f * q.X * q.W + 2f * q.Y * q.Z, 1 - 2f * (sqz  + sqw));     // Yaw 
pitchYawRoll.X = (float)Math.Asin(2f * ( q.X * q.Z - q.W * q.Y ) );                             // Pitch 
pitchYawRoll.Z = (float)Math.Atan2(2f * q.X * q.Y + 2f * q.Z * q.W, 1 - 2f * (sqy + sqz));      // Roll 

我进行了以下测试:

var q = CreateFromYawPitchRoll(0.2f, 0.3f, 0.7f);
var e = ToEulerAngles(q);
var q2 = CreateFromYawPitchRoll(e.Y, e.X, e.Z);

结果如下;

e = (0.3, 0.2, 0.7) //pitch, yaw, roll
q2 = q

来源:Wikipedia

【讨论】:

  • 很好的答案,谢谢。奇点是否像最初写的那样正确?
  • if (test &gt; 0.4999f * unit) // 0.4999f OR 0.5f - EPSILON { // Singularity at north pole pitchYawRoll.Y = 2f * (float)Math.Atan2(q.Y, q.W); // Yaw pitchYawRoll.X = PI * 0.5f; // Pitch pitchYawRoll.Z = 0f; // Roll return pitchYawRoll; }
  • 刚刚检查,PI 没有产生正确的结果。例如FromYawPitchRoll((float)Math.PI, 0f, 0f)
  • test 必须是 = q.X * q.Z - q.W * q.Y。但是,我不确定奇异值。你最好尝试一下。
  • “测试”等式不可能正确。它为 (0, 0, 0) 和 (PI, 0, 0) 生成一个值 0。
猜你喜欢
  • 1970-01-01
  • 2013-01-05
  • 2012-06-21
  • 1970-01-01
  • 2019-07-26
  • 1970-01-01
  • 2019-10-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多