欧拉角和四元数

Unity 中欧拉角与四元数使用指南

1. 四元数基础

四元数可以表示旋转,形式为:

q = [cos(β/2), sin(β/2) * x, sin(β/2) * y, sin(β/2) * z]
  • β:旋转角度(弧度)
  • (x, y, z):旋转轴单位向量

单位四元数

Quaternion q = Quaternion.identity; // 物体初始朝向(无旋转)

2. 欧拉角与四元数在Unity中的表现以及相互转换

欧拉角与四元数在Unity中的表现

✔ 欧拉角(EulerAngles)在 Unity 中:范围是 0° 到 360°(循环)
✔ 四元数表示的角度范围是 -180° 到 180°(归一化后的角度)
当我们想要使用欧拉角旋转角度时,最好不要使用小于0的角度来控制,当使用小于0的angle时,会自动修正为360+angle

this.transform.eulerAngles = new Vector3(-10, 0, 0);
float f = Mathf.Clamp(this.transform.eulerAngles.x, -20, 20);
this.transform.eulerAngles = new Vector3(f, 0, 0);
//Unity编辑器中观察物体的旋转结果为(20, 0, 0);

欧拉角转四元数

Vector3 eulerAngles = new Vector3(30, 45, 60);
Quaternion q = Quaternion.Euler(eulerAngles);

四元数转欧拉角

Vector3 eulerAngles = q.eulerAngles;

注意:使用欧拉角旋转容易出现万向节死锁(Gimbal Lock),例如 X 旋转 90° 时,Y 和 Z 轴旋转会耦合。


3. 常用旋转操作

3.1 欧拉角旋转(会造成万向节死锁)

//常用的Rotate三种重载
//重载一
//参数 eulers 可以分解为 angleX,angleY,angleZ 表示绕物体自身X轴/Y轴/Z轴 每帧旋转angleX度/angleY度/angleZ度 
this.transform.Rotate(Vector3 eulers);
//绕物体局部坐标系的Y轴 每帧旋转1度
this.transform.Rotate(Vector3.up);
//等价于 (不常用)
this.transform.Rotate(0, 1, 0)

//重载二
//以物体的局部坐标系 将参数eulers转换为物体的旋转轴 围绕eulers向量旋转轴每帧旋转angle度
this.transform.Rotate(Vector3 eulers, float angle)
//绕物体局部坐标系的y轴每帧旋转10度
this.transform.Rotate(Vector3.up, 10)

//重载三
//Space是一个枚举类enum,有两个枚举成员:World和Self 分别表示以世界坐标系算出eulers旋转轴方向 以物体局部坐标系算出eulers旋转轴方向
//不填写Space参数时 默认使用的是Self 即物体局部坐标系
this.transform.Rotate(Vector3 eulers, float angle, Space relativeTo)
//绕世界坐标系的y轴每帧旋转10度
this.transform.Rotate(Vector3.up, 10, Space.World);

3.2 四元数旋转(推荐,避免万向节死锁)

  • 围绕局部坐标轴旋转
//直接赋值旋转 
this.transform.rotation = Quaternion.AngleAxis(float angle, Vector3 Axis);
//让物体的AngleZ直接等于 -20° (旋转不是的顺时针旋转 而是符合左手 左手大拇指朝向旋转轴朝向 四指旋转方向就是物体旋转方向)
this.transform.rotation = Quaternion.AngleAxis(-20, Vector3.forward);

//累加旋转
this.transform.rotation *= Quaternion.AngleAxis(float angle, Vector3 Axis); 
//在物体本身的旋转基础上 绕物体的z轴旋转-20°
transform.rotation *= Quaternion.AngleAxis(-20, Vector3.forward); // 每帧旋转 1 度
  • 使物体面向目标
    方法一:
//重载一 forward表示物体到目标的向量
this.transform.rotation = Quaternion.LookRotation(Vector3 forward);
this.transform.rotation = Quaternion.LookRotation(target.transform.position - this.transform.position);
//重载二 指定upwards为物体的y轴朝向 防止forward轴朝向相同时,up轴和right轴朝向不符合需求
Quaternion.LookRotation(Vector3 forward, Vector3 upwards);

方法二:

//方式一 直接使用 = 
this.transform.rotation = Quaternion.FromToRotation(this.transform.position,target.transform.position);
//方式二 使用 *=
this.transform.rotation *= Quaternion.FromToRotation(this.transform.position,target.transform.position);

注意:
在Update里不要使用法向量和物体向量相减,猜测:法向量和物体的向量相减存在误差
cube.transform.rotation = Quaternion.LookRotation(info.normal - cube.transform.up)
上述代码的目的是让cube的y轴重合 法线,但是在Update中,每一帧差值运算结果不会相等。当法线为-45度时,可能左右翻转的原因是:

  • 每帧绝对赋值 → 四元数 ±A 取值切换,欧拉角表现为 180° 翻转。
    ✅ 解决方法:
//方法一:使用叉乘获取cube的x轴朝向,LookRotation直接操作x轴旋转没有误差,
//注意:LookRotation中使用第二个参数info.normal,不然斜面沿物体的z轴倾斜时,物体的y轴和法线不会重合
Vector3 forward = Vector3.Cross(cube.transform.right, info.normal);
cube.transform.rotation = Quaternion.LookRotation(forward, info.normal);

//方法二:使用*=以及FromToRotation,暂时不知道为什么可以解决,直接使用 `=` 会出现抖动  需要使用 `*=`
cube.transform.rotation *= Quaternion.FromToRotation(cube.transform.up, info.normal)
  • 平滑旋转到目标物体角度
Quaternion.Slerp(Quaternion a, Quaternion b, float t)
//想要物体慢慢旋转到和目标物体的角度一样时
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, target.transform.rotation, speed*Time.deltaTime);
//想要物体慢慢旋转到看向物体的角度时
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, 
                                      Quaternion.LookRotation(target.transform.position-this.transform.rotation), 
                                      speed*Time.deltaTime);

3.3 四元数与向量旋转

  • 四元数乘向量
Vector3 forward = Vector3.forward; // (0,0,1)
Vector3 newForward = Quaternion.AngleAxis(45, Vector3.up) * forward; // 旋转 45 度后的方向
  • 注意顺序问题
    1. 标准写法:Quaternion * Vector3
    2. Vector3 * Quaternion 在 Unity 中虽然重载支持,但内部仍使用 Quaternion * Vector3 计算
    3. 数学上顺序不交换,两个顺序结果不等价

4. 总结与建议

  1. 尽量使用四元数进行旋转,避免欧拉角带来的万向节死锁。
  2. Quaternion.AngleAxis 可实现任意轴旋转,支持局部旋转累积。
  3. Quaternion.LookRotation 是物体对准目标方向的标准方法。
  4. Quaternion.Slerp 用于平滑旋转,常用于摄像机跟随或物体面向目标。

posted @ 2025-11-29 18:22  高山仰止666  阅读(22)  评论(0)    收藏  举报