前置知识,能理解欧拉角的旋转过程和它的万向节死锁。
1)优点:
可以避免万向节锁现象;
只需要一个4维的四元数就可以执行绕任意过原点的向量的旋转,方便快捷,在某些实现下比旋转矩阵效率更高;
可以提供平滑插值;
2)缺点:
比欧拉旋转稍微复杂了一点点,因为多了一个维度;
理解更困难,不直观;
接下来带着四元数的优点和缺点去理解四元数会更加有的放矢。
1)这里面东西太多了,贴几个比较好的帖子大家去看看。
https://krasjet.github.io/quaternion/quaternion.pdf
不过最推荐的还是这个,看着会比较舒服:图形学笔记 - 知乎
2)大致总结一下比较重要的概念:
四元数的虚部与实部、单位四元数、纯四元数、四元数的点积、乘积、叉积、四元数的共轭与逆、四元数表示旋转、四元数的插值。感觉这些概念看懂应该就算入门四元数了吧。
可以参考一下这个: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函数。
该部分主要参考自:
【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));
- }