如何准确地将四元数转换为Euler?

时间:2017-02-06 10:09:04

标签: python-3.x opengl

出于效率原因,我的后端使用Euler旋转 (万向节锁不是一个因素,所以请不要评论它)。

如果给定数据提供四元数,我怎么能将其转换为准确的Euler?

我见过的大多数方法都使用asin作为Y轴,但是建议的方法是使用3 atan2函数来提高准确度。

另外我应该提一下,我按照OpenGL术语进行轴表示,其中Z是您的监视器深度,关系式:

{ X: width, Y: height, Z: depth }

因此,如果您提供示例代码,请提供以下内容:

{ X: pitch, Y: yaw, Z: roll }

1 个答案:

答案 0 :(得分:1)

这个概念并非微不足道,而是寻求开源。在您之前,有很多人已经实现了这一点: Quaternion.java 行:289,toAngles。事实上,它主要是数学应该可以很容易地转换为您的偏好语言。角度也恰好按照你要求的顺序(俯仰,偏航,滚动)

public float[] toAngles(float[] angles) {
    if (angles == null) {
        angles = new float[3];
    } else if (angles.length != 3) {
        throw new IllegalArgumentException("Angles array must have three elements");
    }

    float sqw = w * w;
    float sqx = x * x;
    float sqy = y * y;
    float sqz = z * z;
    float unit = sqx + sqy + sqz + sqw; // if normalized is one, otherwise
    // is correction factor
    float test = x * y + z * w;
    if (test > 0.499 * unit) { // singularity at north pole
        angles[1] = 2 * FastMath.atan2(x, w);
        angles[2] = FastMath.HALF_PI;
        angles[0] = 0;
    } else if (test < -0.499 * unit) { // singularity at south pole
        angles[1] = -2 * FastMath.atan2(x, w);
        angles[2] = -FastMath.HALF_PI;
        angles[0] = 0;
    } else {
        angles[1] = FastMath.atan2(2 * y * w - 2 * x * z, sqx - sqy - sqz + sqw); // roll or heading 
        angles[2] = FastMath.asin(2 * test / unit); // pitch or attitude
        angles[0] = FastMath.atan2(2 * x * w - 2 * y * z, -sqx + sqy - sqz + sqw); // yaw or bank
    }
    return angles;
}