返回首页DA系统C#IDE文件同步服务屏保 今天是: 2026-05-05    "立夏"  夏季的第一个节气,表示盛夏时节的正式开始

搜索
热搜: linux 技术
Hi~登录注册
查看: 2333|回复: 0

[原创] 【原创】三维数学-欧拉角与四元数的讲解

[复制链接]
发表于 2021-8-2 16:35:19 | 显示全部楼层 |阅读模式
本帖最后由 da11 于 2021-9-7 12:18 编辑

     * 欧拉角
     * · 使用三个角度来保存方位。
     * · X与Z沿自身坐标系旋转,Y沿世界坐标系旋转。重点 !!
     * · API:Vector3 EnulerNum = this.transform.eulerAngles;
     *
     * 欧拉角的优点:
     * · 仅使用三个数字表达方位,占用空间小。
     * · 沿坐标轴旋转的单位为角度,复合人的思考方式。
     * · 任意三个数字都是合法的,不存在不合法的欧拉角。
     * 欧拉角的缺点:(方位的表达方式不唯一)
     * · 对于一个方位,存在多个欧拉角描述,因此无法判断多个欧拉角代表的角位移是否相同。
     * · 例如:
     *      --角度0,5,0 与 角度 0,365,0
     *      --角度0,-5,0 与 角度 0,355,0
     *      --角度255,0,0 与 角度 290,180,180
     * · 为了保证任意方位都只有独一无二的表示,Unity引擎限制了角度范围,既沿X轴旋转限制在-90到90之间,沿Y与Z轴旋转限制在0到360之间。重点!!
     * 欧拉角的缺点:(万向节死锁)
     * · 物体沿X轴旋转正负90度,自身坐标系Z轴与世界坐标系Y轴将重合,此时再沿Y或Z轴旋转时,将失去一个自由度。
     * · 在万向节死锁情况下,规定沿Y轴完成绕竖直轴的全部旋转,既此时Z轴旋转为0。

     *
     *
     *
     * 四元数
     * · Quaternion 在3D图形学中代表旋转,由一个三维向量(X/Y/Z)和一个标量(W)组成。
     * · 旋转轴为V,旋转弧度为θ,如果使用四元数表示,则四个分量为:
     *   x = sin(θ/2) * V.x      y = sin(θ/2) * V.y
     *   z = sin(θ/2) * V.z      w = cos(θ/2)
     *  


     * · X、Y、Z、W的取值范围是-1到1.
     * · API:Quaternion qt = this.tranform.rotation;
     *
     * 四元数与向量相乘
     * · 四元数左乘向量,表示将该向量按照四元数表示的角度旋转。
     * · 例如:
     *   Vector3 point = new Vector3(0,0,10);
     *   Vector3 newPoint = Quaternion.Euler(0,30,0) * point;
     *
     * 与四元数相乘
     * · 两个四元数相乘可以组合旋转效果。
     * · 例如:
     *   Quaternion r1 = Quaternion.Euler(0,30,0) * Quaternion.Euler(0,20,0);
     *   Quaternion r2 = Quaternion.Euler(0,50,0);
     *   结果r1和r2相同。

   
     *   
     *
     * 四元数的优点:
     * 避免万向节死锁
     * · this.tranform.rotation *= Quaternion.Euler(0,1,0); -- 可使物体沿自身坐标Y轴旋转。  --重点
     * · this.tranform.Rotate(Vector3 eulerAngles) -- 内部就是使用四元数相乘实现。--重点
     *
     * 四元数的缺点:
     * · 难于使用,不建议单独修改某个数值。
     * · 存在不合法的四元数。


    //欧拉角讲解,测试已注释,如需使用请取消注释
    /*
    private void OnGUI()
    {
        if (GUILayout.RepeatButton("按x轴旋转"))
        {
            Vector3 EnuNum = this.transform.eulerAngles;
            //注意:欧拉角,没有方向,没有大小概念
            //因为三维向量,包含x,y,z,所以在Unity中,欧拉角使用了三维向量的数据类型
            //欧拉角的x,y,z,表示各个轴向上的旋转角度。

            //Vector3 Pos = this.transform.position;
            //位置,有方向(从世界原点指向当前位置),和大小(当前位置到世界原点间距)
            //向量的x,y,z,表示各个轴向上的有向位移。
            //和欧拉角是不同的

            //各分量相加,欧拉角的x轴增加1度
            this.transform.eulerAngles += new Vector3(1, 0, 0);
        }

        if (GUILayout.RepeatButton("按反x轴旋转"))
        {
            this.transform.eulerAngles += new Vector3(-1, 0, 0);
        }

        if (GUILayout.RepeatButton("按y轴旋转"))
        {
            //Vector3.up等于向量的(0,1,0),等同于 EnuNum = EnuNum + new Vector3(0,1,0);
            this.transform.eulerAngles = this.transform.eulerAngles + Vector3.up;
        }

        if (GUILayout.RepeatButton("按z轴旋转"))
        {
            //Vector3.forward等于向量的(0,0,1),等同于 EnuNum = EnuNum + new Vector3(0,0,1);
            this.transform.eulerAngles = this.transform.eulerAngles + Vector3.forward;
        }
    }

    */




    //四元数讲解方法
    private void OnGUI()
    {
        if (GUILayout.Button("设置物体旋转角度"))
        {
            //使用四元数旋转角度需创建以下代码(需明确旋转轴和旋转弧度)---原理性代码

            Quaternion ObjRotation = new Quaternion();   //定义Quaternion类

            //旋转轴
            Vector3 ZX = Vector3.up; //按y轴旋转

            //旋转弧度
            float RadNum = 50 * Mathf.Deg2Rad;

            /*
            ObjRotation.x = Mathf.Sin(RadNum / 2) * ZX.x;
            ObjRotation.y = Mathf.Sin(RadNum / 2) * ZX.y;
            ObjRotation.z = Mathf.Sin(RadNum / 2) * ZX.z;

            ObjRotation.w = Mathf.Cos(RadNum / 2);

            this.transform.rotation = ObjRotation;
            */

            //使用以下方法可以更快的使用四元数旋转物体,原理和上方的代码一致,为常用方法。
            //欧拉角转换为四元数
            this.transform.rotation = Quaternion.Euler(0, RadNum * Mathf.Rad2Deg, 0);

        }

        /*
        if (this.transform.gameObject.activeInHierarchy == true)
        {
            Debug.Log("数学方法宿主方块激活中!!");
        }
        */


        //以下为没有万向结死锁的通用旋转方法
        if (GUILayout.RepeatButton("按反x轴旋转"))
        {
            this.transform.rotation *= Quaternion.Euler(-1, 0, 0);
            //其实this.transform.Rotate(-1, 0, 0); 是和上面的语句一样的,以下同。

        }


        if (GUILayout.RepeatButton("按x轴旋转"))
        {
            this.transform.rotation *= Quaternion.Euler(-Vector3.left);
        }

        if (GUILayout.RepeatButton("按y轴旋转"))
        {
            //Vector3.up等于欧拉角的(0,1,0);
            this.transform.rotation *= Quaternion.Euler(Vector3.up);
        }

        if (GUILayout.RepeatButton("按z轴旋转"))
        {
            //Vector3.forward等于欧拉角的(0,0,1);
            this.transform.rotation *= Quaternion.Euler(Vector3.forward);
        }

        if (GUILayout.RepeatButton("设置物体旋转默认值"))
        {
            this.transform.rotation = Quaternion.Euler(0,0,0);
        }

       if (GUILayout.RepeatButton("计算右前方10米处坐标位置"))
        {
            float DistanceLocalPointVarNum = 10; //定义并赋值远端距离变量

            Vector3 DistanceLocalPoint = new Vector3(0,0,DistanceLocalPointVarNum);  //定义远端的三维向量位置

            Vector3 LocalPoint = this.transform.position;  //定义本地位置

            //计算本地旋转四元数 与 以Y轴为圆心,旋转30度的欧拉度四元数相乘,后乘以 本地坐标加上远端位置坐标,即可达到计算右前方10米处坐标位置的目的,无论物体怎么旋转,对应的都是右前方10米处坐标位置!!
            DistanceLocalPoint = (this.transform.rotation * Quaternion.Euler(0, 30, 0)) * (LocalPoint + DistanceLocalPoint);

            //将位置使用Debug.DrawLine调试画出来
            Debug.DrawLine(LocalPoint, DistanceLocalPoint);
        }


    }


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册成为修仙之旅的少年~

x
 楼主| 发表于 2021-9-7 12:26:52 | 显示全部楼层
附上联动帖子--三维数学-四元数类详细讲解:



回复 支持 反对

使用道具 举报

游客
回复
*滑块验证:

DA论坛飞机票来了~
快速回复 返回顶部 返回列表