四元数 Quaternion
有一个轴V,某个向量P与V之间的夹角为a,它绕V进行旋转b度角,这个旋转被记录为四元数
具体推导:
https://www.bilibili.com/video/BV1Gi4y1q7Bh/?spm_id_from=333.337.search-card.all.click&vd_source=436e1882d94925de09cd95044b65f90a
四元数的运算推导
https://www.bilibili.com/video/BV1mu41167je/?spm_id_from=333.337.search-card.all.click&vd_source=436e1882d94925de09cd95044b65f90a
13分可以解释上面的运算
有一些没看太明白
有四元数q = {x,y,z,w}
它的几何意义为:
1.x,y,z构成了这个旋转的轴
2.w是绕轴旋转了 θ = 2arccos(w)
交互式工具
https://quaternions.online/ 可视化四元数旋转
四元数的出现解决了欧拉角的万向节锁的问题,以及矩阵变换的繁琐。
unity中四元数的一些方法:
来自ds:
一、基础旋转操作
- 设置物体朝向
// 直接设置四元数旋转
transform.rotation = Quaternion.identity; // 重置为初始朝向
transform.rotation = Quaternion.Euler(30f, 45f, 0f); // 欧拉角转四元数
- 绕轴旋转
// 绕Y轴旋转90度
transform.rotation = Quaternion.AngleAxis(90f, Vector3.up);
二、旋转插值(平滑过渡)
- 线性插值(Lerp)
// 从当前旋转平滑过渡到目标旋转
public Quaternion targetRotation;
void Update() {
transform.rotation = Quaternion.Lerp(
transform.rotation,
targetRotation,
Time.deltaTime * 5f // 插值速度
);
}
- 球面插值(Slerp)
更适合大角度旋转,保持恒定角速度:
transform.rotation = Quaternion.Slerp(
currentRotation,
targetRotation,
Time.deltaTime * 2f
);
线性插值,是从某个点到目标点作连线,因此,他会表现为开始和末尾速度较快,中间速度较慢
球面插值,可保持恒定速度。
三、方向计算
- 看向目标(替代LookAt)
// 使物体Z轴指向目标位置
Vector3 direction = target.position - transform.position;
transform.rotation = Quaternion.LookRotation(direction);
// 带倾斜控制的版本
transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
- 相对旋转
// 计算从A指向B的旋转
Quaternion relativeRot = Quaternion.FromToRotation(
transform.forward,
enemy.position - transform.position
);
四、实用技巧
- 旋转叠加
// 在当前旋转基础上叠加Y轴旋转
transform.rotation *= Quaternion.Euler(0, 10f * Time.deltaTime, 0);
- 避免过度旋转
// 限制旋转角度(如相机俯仰角不超过80度)
float currentPitch = transform.eulerAngles.x;
float clampedPitch = Mathf.Clamp(currentPitch, -80f, 80f);
transform.rotation = Quaternion.Euler(clampedPitch, transform.eulerAngles.y, 0);
- 四元数与向量配合
// 用四元数旋转向量
Vector3 movedDirection = transform.rotation * Vector3.forward;
五、高级应用
- 物理模拟旋转
// 给刚体施加旋转力
Rigidbody rb;
public float rotationSpeed = 10f;
void FixedUpdate() {
Quaternion deltaRot = Quaternion.Euler(0, rotationSpeed * Time.fixedDeltaTime, 0);
rb.MoveRotation(rb.rotation * deltaRot);
}
- 动画混合
// 混合两个动画姿势
Quaternion blendRot = Quaternion.Lerp(
animator.GetBoneTransform(HumanBodyBones.Head).rotation,
targetHeadRotation,
0.5f
);
- 网络同步压缩
// 压缩四元数传输(每个分量用16位表示)
QuaternionCompressor.Compress(transform.rotation);
六、调试可视化
// 在Scene视图绘制旋转轴
void OnDrawGizmos() {
Gizmos.color = Color.red;
Gizmos.DrawRay(transform.position, transform.rotation * Vector3.forward * 2f);
}
七、性能优化建议
-
避免频繁转换
尽量保持四元数形式,减少与欧拉角的相互转换// 错误做法(每帧转换) transform.eulerAngles += new Vector3(0, speed, 0); // 正确做法 transform.rotation *= Quaternion.Euler(0, speed, 0); -
缓存四元数
对需要重复使用的旋转进行缓存:private Quaternion _initialRotation; void Start() { _initialRotation = transform.rotation; }
关键总结:
- 优先使用
Quaternion而非eulerAngles处理旋转 - 大角度插值用
Slerp,小角度用Lerp - 组合旋转使用四元数乘法(注意顺序)
- 在物理更新中使用
MoveRotation
浙公网安备 33010602011771号