四元数与其在Unity中的简单应用

前置知识,能理解欧拉角的旋转过程和它的万向节死锁。

一、四元数的基本介绍

1.四元数的特点与缺点

1)优点:
可以避免万向节锁现象;
只需要一个4维的四元数就可以执行绕任意过原点的向量的旋转,方便快捷,在某些实现下比旋转矩阵效率更高;
可以提供平滑插值;

为什么可以平滑插值可参考:如何通俗地解释欧拉角?之后为何要引入四元数? - 知乎

补充:大概原因就是因为其最后的角度可以表示成一个欧拉公式形式,在均匀插值的时候只要不断乘以\Delta \theta对应的四元数的指数形式即可(指数相乘即指数相加,四元数不断叠乘即旋转角度叠加)。而欧拉角只能在x、y、z各自的方向上进行均匀插值,无法做到任意角均匀插值。
2)缺点:
比欧拉旋转稍微复杂了一点点,因为多了一个维度;
理解更困难,不直观;

接下来带着四元数的优点和缺点去理解四元数会更加有的放矢。

2.四元数的基本运算规律

1)这里面东西太多了,贴几个比较好的帖子大家去看看。

四元数——基本概念 - 知乎

https://krasjet.github.io/quaternion/quaternion.pdf

四元数(Quaternions) - 知乎

不过最推荐的还是这个,看着会比较舒服:图形学笔记 - 知乎

2)大致总结一下比较重要的概念:

四元数的虚部与实部、单位四元数、纯四元数、四元数的点积、乘积、叉积、四元数的共轭与逆、四元数表示旋转、四元数的插值。感觉这些概念看懂应该就算入门四元数了吧。

3.能大致理解四元数运算的几何含义

可以参考一下这个:https://jingyan.baidu.com/article/4ae03de3dbbac83eff9e6b00.html

里面提出的四元数可以表示状态和动作的这种说法感觉很赞,对理解记忆四元数有帮助。

二、四元数与欧拉角的相互转化

这可以当成四元数的一个理论理解的练习,推导过于麻烦了,就直接贴出参考链接,这四个链接给出了不错的推导过程,需要注意的就是在unity中欧拉角的旋转顺序。

三维旋转:欧拉角、四元数、旋转矩阵、轴角之间的转换 - 知乎

四元数与欧拉角(RPY角)的相互转换 - XXX已失联 - 博客园

四元数与欧拉角(Yaw、Pitch、Roll)的转换_xiaoma_bk的博客-CSDN博客_四元数与欧拉角

Unity 四元数与欧拉角的相互转换及推导_晒网君的博客-CSDN博客_unity 欧拉角转四元数

接下来我就直接贴出相互转化的测试代码了

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class QuaternionRotate : MonoBehaviour
{

    void Start()
    {
        Quaternion q=Quaternion.Euler(60,60,60);
        Debug.Log("原始欧拉角    " + new Vector3(60, 60, 60));
        Debug.Log("原始四元数    "+q);
        Debug.Log("转换的欧拉角    " + QuaternionToEuler(q.x, q.y, q.z, q.w));
        Debug.Log("转换的四元数    " + EulerToQuaternion(60,60,60));
    }

    public Quaternion EulerToQuaternion(float xx, float yy, float zz)
    {

        float X = xx / 180 * Mathf.PI;
        float Y = yy / 180 * Mathf.PI;
        float Z = zz / 180 * Mathf.PI;
        float x = Mathf.Cos(Y / 2) * Mathf.Sin(X / 2) * Mathf.Cos(Z / 2) + Mathf.Sin(Y / 2) * Mathf.Cos(X / 2) * Mathf.Sin(Z / 2);
        float y = Mathf.Sin(Y / 2) * Mathf.Cos(X / 2) * Mathf.Cos(Z / 2) - Mathf.Cos(Y / 2) * Mathf.Sin(X / 2) * Mathf.Sin(Z / 2);
        float z = Mathf.Cos(Y / 2) * Mathf.Cos(X / 2) * Mathf.Sin(Z / 2) - Mathf.Sin(Y / 2) * Mathf.Sin(X / 2) * Mathf.Cos(Z / 2);
        float w = Mathf.Cos(Y / 2) * Mathf.Cos(X / 2) * Mathf.Cos(Z / 2) + Mathf.Sin(Y / 2) * Mathf.Sin(X / 2) * Mathf.Sin(Z / 2);
        Quaternion quataion = new Quaternion(x, y, z, w);
        return quataion;
    }
    public Vector3 QuaternionToEuler(float xx, float yy, float zz, float ww)
    {
        float X = Mathf.Asin(2 * (ww * xx - yy * zz));
        float Y = Mathf.Atan2(2 * (ww * yy + xx * zz), 1 - 2 * (xx * xx + yy * yy));
        float Z = Mathf.Atan2(2 * (ww * zz + yy * xx), 1 - 2 * (xx * xx + zz * zz));
        Vector3 euler = new Vector3(X * 180f / Mathf.PI, Y * 180f / Mathf.PI, Z * 180f / Mathf.PI);
        return euler;
    }

}

 上面的EulerToQuaternion函数对应unity中的Quaternion.Euler函数,QuaternionToEuler函数对应unity中的q.eulerAngles函数。

三、以Unity举例四元数的使用

该部分主要参考自:

【100个 Unity实用技能】| 游戏中使技能或装备跟随角色环绕,持续旋转_呆呆敲代码的小Y的博客-CSDN博客_unity 技能

四元数主要就是旋转和旋转插值用,用下面的代码可以做出一个某个物体一直跟随另一个物体旋转(跟随旋转)的效果。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Saber : MonoBehaviour {
    public Transform targetPos;//旋转中心对象
    public float speed = 200f;//旋转速度
    public float distance;//旋转半径
    Vector3 dir;
    
    void Start()
     {
        dir = transform.position - targetPos.position;
    }
 
    void Update() {
        //更新跟随物体的位置
        transform.position = targetPos.position + dir.normalized * distance;
        //围绕角色旋转
        transform.RotateAround(targetPos.position, Vector3.up, speed * Time.deltaTime);
        //更新方向向量
        dir = transform.position - targetPos.position;
    } 
}

参考RotateAround函数的源码,可以看出里面对四元数的使用。

        public void RotateAround(Vector3 point, Vector3 axis, float angle)
        {
            Vector3 vector = position;
            Quaternion quaternion = Quaternion.AngleAxis(angle, axis);
            Vector3 vector2 = vector - point;
            vector2 = quaternion * vector2;
            vector = (position = point + vector2);
            RotateAroundInternal(axis, angle * ((float)Math.PI / 180f));
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值