四元数 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:
一、基础旋转操作

  1. 设置物体朝向
// 直接设置四元数旋转
transform.rotation = Quaternion.identity; // 重置为初始朝向
transform.rotation = Quaternion.Euler(30f, 45f, 0f); // 欧拉角转四元数
  1. 绕轴旋转
// 绕Y轴旋转90度
transform.rotation = Quaternion.AngleAxis(90f, Vector3.up);

二、旋转插值(平滑过渡)

  1. 线性插值(Lerp)
// 从当前旋转平滑过渡到目标旋转
public Quaternion targetRotation;
void Update() {
    transform.rotation = Quaternion.Lerp(
        transform.rotation, 
        targetRotation, 
        Time.deltaTime * 5f // 插值速度
    );
}
  1. 球面插值(Slerp)
    更适合大角度旋转,保持恒定角速度:
transform.rotation = Quaternion.Slerp(
    currentRotation, 
    targetRotation, 
    Time.deltaTime * 2f
);

线性插值,是从某个点到目标点作连线,因此,他会表现为开始和末尾速度较快,中间速度较慢
球面插值,可保持恒定速度。

三、方向计算

  1. 看向目标(替代LookAt)
// 使物体Z轴指向目标位置
Vector3 direction = target.position - transform.position;
transform.rotation = Quaternion.LookRotation(direction);

// 带倾斜控制的版本
transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
  1. 相对旋转
// 计算从A指向B的旋转
Quaternion relativeRot = Quaternion.FromToRotation(
    transform.forward, 
    enemy.position - transform.position
);

四、实用技巧

  1. 旋转叠加
// 在当前旋转基础上叠加Y轴旋转
transform.rotation *= Quaternion.Euler(0, 10f * Time.deltaTime, 0);
  1. 避免过度旋转
// 限制旋转角度(如相机俯仰角不超过80度)
float currentPitch = transform.eulerAngles.x;
float clampedPitch = Mathf.Clamp(currentPitch, -80f, 80f);
transform.rotation = Quaternion.Euler(clampedPitch, transform.eulerAngles.y, 0);
  1. 四元数与向量配合
// 用四元数旋转向量
Vector3 movedDirection = transform.rotation * Vector3.forward;

五、高级应用

  1. 物理模拟旋转
// 给刚体施加旋转力
Rigidbody rb;
public float rotationSpeed = 10f;

void FixedUpdate() {
    Quaternion deltaRot = Quaternion.Euler(0, rotationSpeed * Time.fixedDeltaTime, 0);
    rb.MoveRotation(rb.rotation * deltaRot);
}
  1. 动画混合
// 混合两个动画姿势
Quaternion blendRot = Quaternion.Lerp(
    animator.GetBoneTransform(HumanBodyBones.Head).rotation,
    targetHeadRotation,
    0.5f
);
  1. 网络同步压缩
// 压缩四元数传输(每个分量用16位表示)
QuaternionCompressor.Compress(transform.rotation);

六、调试可视化

// 在Scene视图绘制旋转轴
void OnDrawGizmos() {
    Gizmos.color = Color.red;
    Gizmos.DrawRay(transform.position, transform.rotation * Vector3.forward * 2f);
}

七、性能优化建议

  1. 避免频繁转换
    尽量保持四元数形式,减少与欧拉角的相互转换

    // 错误做法(每帧转换)
    transform.eulerAngles += new Vector3(0, speed, 0);
    
    // 正确做法
    transform.rotation *= Quaternion.Euler(0, speed, 0);
    
  2. 缓存四元数
    对需要重复使用的旋转进行缓存:

    private Quaternion _initialRotation;
    void Start() {
        _initialRotation = transform.rotation;
    }
    

关键总结

  • 优先使用 Quaternion 而非 eulerAngles 处理旋转
  • 大角度插值用 Slerp,小角度用 Lerp
  • 组合旋转使用四元数乘法(注意顺序)
  • 在物理更新中使用 MoveRotation
posted @ 2025-06-13 18:53  木土无心  阅读(121)  评论(0)    收藏  举报