将Euler Angles从World Axises转换为Local

时间:2014-08-07 21:22:20

标签: algorithm opengl-es 3d

我正在尝试使用iPhone的运动管理器对象创建VR应用程序。通过VR我的意思是一个在相机上显示位置的应用程序。

我可以使用Z - >>使用偏航,俯仰和滚动成功地显示iPhone方向。 X - > Y轮换订单。

这是我迄今为止所做的事情的照片:

enter image description here enter image description here

所以我可以旋转设备,它会在我为监控创建的Windows应用程序中正确旋转。 这是正确的,我稍后会显示它的代码。但这不是我想要做的。

我想要做的事实上与此相反。我不希望设备移动。我希望它周围的世界旋转。因此,如果用户将设备的摄像头指向东方,他应该看到“东方标志”,如果他将方向改为北方,他应该在屏幕上看到“北方标志”。但准确。不像其他应用程序那样可以移除滚动。

问题在于,当我将设备从放置在桌面上移动到纵向模式时,向右和向左旋转会导致旋转不正确。如果我将它置于横向模式,那么从上到下旋转是不正确的。换句话说,旋转基于世界轴,只有当设备放置在地面上时它们才能正常工作。因为它是我认为的参考框架。

我想问的是如何转换这些角度所以我看到了我期望的结果。应该有一种基于三角学的方法。

这些是我用来计算旋转矩阵的函数:

    private static Matrix4 CreateRotationMatrix(char axis, float radians, bool rightHanded = true)
    {
        float c = (float)Math.Cos(radians);
        float s = (float)Math.Sin(radians) * (rightHanded ? 1 : -1);
        switch (axis)
        {
            case 'X':
                return new Matrix4(
                    new Vector4(1.0f, 0.0f, 0.0f, 0.0f),
                    new Vector4(0.0f, c, -s, 0.0f),
                    new Vector4(0.0f, s, c, 0.0f),
                    new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
            case 'Y':
                return new Matrix4(
                    new Vector4(c, 0.0f, s, 0.0f),
                    new Vector4(0.0f, 1.0f, 0.0f, 0.0f),
                    new Vector4(-s, 0.0f, c, 0.0f),
                    new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
            case 'Z':
                return new Matrix4(
                    new Vector4(c, -s, 0.0f, 0.0f),
                    new Vector4(s, c, 0.0f, 0.0f),
                    new Vector4(0.0f, 0.0f, 1.0f, 0.0f),
                    new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
            default:
                return Matrix4.Identity;
        }
    }

    public static Matrix4 MatrixFromEulerAngles(
        Vector3 euler,
        string order,
        bool isRightHanded = true,
        bool isIntrinsic = true)
    {
        if (order.Length != 3) throw new ArgumentOutOfRangeException("order", "String must have exactly 3 charecters");
        // X = Pitch
        // Y = Yaw
        // Z = Roll
        return isIntrinsic
                   ? CreateRotationMatrix(order[2], GetEulerAngle(order[2], euler), isRightHanded)
                     * CreateRotationMatrix(order[1], GetEulerAngle(order[1], euler), isRightHanded)
                     * CreateRotationMatrix(order[0], GetEulerAngle(order[0], euler), isRightHanded)
                   : CreateRotationMatrix(order[0], GetEulerAngle(order[0], euler), isRightHanded)
                     * CreateRotationMatrix(order[1], GetEulerAngle(order[1], euler), isRightHanded)
                     * CreateRotationMatrix(order[2], GetEulerAngle(order[2], euler), isRightHanded);
    }

    private static float GetEulerAngle(char angle, Vector3 euler)
    {
        switch (angle)
        {
            case 'X':
                return euler.X;
            case 'Y':
                return euler.Y;
            case 'Z':
                return euler.Z;
            default:
                return 0f;
        }
    }

这就是我将矩阵应用于OpenGL的方法:

 Matrix4 projectionMatrix = Helper.MatrixFromEulerAngles(new Vector3(pitch, yaw, roll), "YXZ", true, true);
 GL.LoadMatrix(ref projectionMatrix);

1 个答案:

答案 0 :(得分:0)

好的,反转是答案的一部分。它帮助了很多。感谢@dari和@Spektre的建议。

但完整的答案是,改变旋转方向(右手 - >左手),改变旋转顺序(YXZ - > ZXY,换句话说,Intrinsic to Extrinsic)和反转结果矩阵。 在询问之前,我曾单独尝试过这三个,但从未想过将它们全部一起使用。

所以:

Matrix4 projectionMatrix = Helper.MatrixFromEulerAngles(new Vector3(pitch, yaw, roll), "YXZ", false, false);
projectionMatrix.Invert();
GL.LoadMatrix(ref projectionMatrix);