Unreal Engine 中的旋转表示:FQuat 与 FRotator 全面解析

在 Unreal Engine 的 3D 开发中,旋转(Rotation) 是最基础也最容易让人困惑的概念之一。Unreal 提供了两种主要的旋转表示方式:FRotator(欧拉角)FQuat(四元数)。它们各有优劣,适用于不同场景。本文将系统梳理它们的定义、相互转换、使用场景及常用方法,帮助你写出更健壮、高效的旋转逻辑。


一、基本定义

1. FRotator ------ 欧拉角(Euler Angles)

  • 结构 :由三个 float 值组成:Pitch(俯仰,绕 Y 轴)、Yaw(偏航,绕 Z 轴)、Roll(翻滚,绕 X 轴)。
  • 单位度(Degrees),不是弧度!
  • 可读性 :高。例如 (0, 90, 0) 表示向右转 90 度,直观易懂。
  • 范围
    • 默认范围:[-360, 360]
    • 可通过 GetNormalized() 归一化到 [-180, 180]
cpp 复制代码
FRotator Rot(30.0f, 45.0f, 0.0f); // Pitch=30°, Yaw=45°, Roll=0°

⚠️ 注意 :Unreal 的坐标系是 左手坐标系 ,Z 轴朝上,因此 Yaw 是绕 Z 轴旋转(与 Unity 等右手系不同)。


2. FQuat ------ 四元数(Quaternion)

  • 结构 :由四个 float 值组成:X, Y, Z, W,满足 X² + Y² + Z² + W² = 1(单位四元数)。
  • 本质:一种数学上更优雅的旋转表示,避免了欧拉角的"万向节死锁(Gimbal Lock)"。
  • 可读性 :低。FQuat(0, 0, 0.707, 0.707) 对人类来说毫无意义。
  • 优势
    • 插值平滑(Slerp)
    • 组合旋转高效(四元数乘法)
    • 无奇异性(不会死锁)
cpp 复制代码
FQuat Quat = FQuat::MakeFromEuler(FVector(0, 90, 0)); // 从欧拉角构造

二、相互转换

1. FRotatorFQuat

cpp 复制代码
FRotator Rot(0, 90, 0);
FQuat Quat = Rot.Quaternion(); // 推荐方式
// 或
FQuat Quat2 = FQuat(Rot);      // 隐式转换(内部调用 Quaternion())

2. FQuatFRotator

cpp 复制代码
FQuat Quat = ...;
FRotator Rot = Quat.Rotator(); // 推荐方式

重要提示

四元数到欧拉角的转换不是一一对应的 !多个四元数可能对应同一个欧拉角(因为旋转有周期性)。因此,不要期望 Quat.Rotator().Quaternion() == Quat 恒成立


三、使用场景对比

场景 推荐类型 原因
编辑器输入 / 蓝图暴露 FRotator 用户友好,直观可调
角色控制 / 摄像机旋转 FRotator 逻辑清晰(如"角色面向 Yaw 方向")
动画 / 物理 / 插值 FQuat 避免死锁,插值平滑
组合多个旋转 FQuat 四元数乘法比欧拉角叠加更准确
网络同步旋转 FQuat 数据更紧凑,无角度跳变问题
数学计算 / 变换矩阵 FQuat FTransform 内部一致

四、常用方法与技巧

1. FRotator 常用方法

cpp 复制代码
// 归一化到 [-180, 180]
FRotator Normalized = Rot.GetNormalized();

// 获取方向向量(常用于角色朝向)
FVector Forward = Rot.Vector(); // 等价于 FRotationMatrix(Rot).GetUnitAxis(EAxis::X)

// 旋转一个向量
FVector NewDir = Rot.RotateVector(OriginalDir);

// 插值(注意:可能经过长路径!)
FRotator Interp = FMath::Lerp(RotA, RotB, Alpha);
FRotator InterpShort = FMath::RInterpTo(RotA, RotB, DeltaTime, InterpSpeed); // 自动选短路径

⚠️ FMath::LerpFRotator 不会自动选择最短路径 !可能绕远路。建议使用 FMath::RInterpTo 或先转四元数插值。


2. FQuat 常用方法

cpp 复制代码
// 从轴角构造
FQuat Quat = FQuat::MakeFromAxisAngle(FVector::UpVector, FMath::DegreesToRadians(90));

// 从两个向量构造(将 From 向量旋转到 To 向量)
FQuat Quat = FQuat::FindBetweenVectors(FromDir, ToDir);

// 球面线性插值(Slerp)------ 平滑旋转
FQuat Interp = FMath::QInterpTo(QuatA, QuatB, DeltaTime, InterpSpeed);

// 组合旋转:先 A 再 B
FQuat Combined = QuatB * QuatA; // 注意顺序!Unreal 是右乘

// 旋转一个向量
FVector NewDir = Quat.RotateVector(OriginalDir);

// 获取旋转轴和角度
FVector Axis;
float Angle;
Quat.ToAxisAndAngle(Axis, Angle); // Angle 是弧度!

🔁 旋转顺序注意

在 Unreal 中,QuatB * QuatA 表示 先应用 A,再应用 B(与矩阵乘法一致)。


五、常见陷阱与最佳实践

❌ 陷阱 1:直接对 FRotator 做 Lerp

cpp 复制代码
// 错误!可能从 179° 跳到 -179°,导致旋转 358° 而不是 2°
FRotator BadInterp = FMath::Lerp(RotA, RotB, Alpha);

正确做法

cpp 复制代码
FQuat GoodInterp = FMath::QInterpTo(RotA.Quaternion(), RotB.Quaternion(), DeltaTime, Speed);
FRotator Result = GoodInterp.Rotator();

❌ 陷阱 2:混淆旋转顺序

cpp 复制代码
// 想让物体先绕自身 Y 轴转,再绕世界 Z 轴转?
// 错误写法:
FQuat LocalYaw = FQuat(FRotator(DeltaYaw,0 , 0)); // Pitch,Yaw,Roll -> Y,Z,X
FQuat WorldRoll = FQuat(FRotator(0, DeltaRoll, 0));
Comp->SetRelativeRotation(WorldRoll * LocalYaw); // 顺序可能不对!

明确顺序 :通常局部旋转用 SetRelativeRotation,世界旋转用 AddWorldRotation


✅ 最佳实践

  1. 内部计算用 FQuat,对外接口用 FRotator

    ------ 例如:Actor 的 GetActorRotation() 返回 FRotator,但内部 FTransform 存储的是 FQuat

  2. 插值一律转四元数

    ------ 避免角度跳变问题。

  3. 网络同步优先传 FQuat

    ------ 更稳定,且 FQuat 可压缩(如 CompressedRotation)。

  4. 不要手动修改 FQuat 的 X/Y/Z/W

    ------ 除非你非常清楚自己在做什么,否则容易破坏单位长度。


六、引擎内部如何存储?

  • USceneComponentRelativeRotationComponentToWorld 中的旋转,底层都是 FQuat
  • FRotator 仅作为用户友好接口 存在,每次设置 SetRelativeRotation(FRotator) 时,引擎会立即转为 FQuat 存储。

总结

特性 FRotator FQuat
可读性 ⭐⭐⭐⭐⭐
插值质量 ⭐⭐ ⭐⭐⭐⭐⭐
组合旋转 ⭐⭐ ⭐⭐⭐⭐⭐
万向节死锁 有风险
适合场景 用户输入、简单逻辑 动画、物理、数学计算

记住一句话
"用 FRotator 思考,用 FQuat 计算。"

掌握这两者的区别与转换,你就能在 Unreal 的旋转世界中游刃有余,写出既直观又健壮的代码。

相关推荐
霜绛20 小时前
Unity:Json笔记——Json文件格式、JsonUtlity序列化和反序列化
学习·unity·json·游戏引擎
开发游戏的老王1 天前
虚幻引擎虚拟制片入门教程 之 创建项目及启用插件
游戏引擎·虚幻
qq_428639611 天前
虚幻基础:NPC制作
虚幻
L X..1 天前
Unity反射调用 ReactiveProperty<T>(泛型类型)内部方法时崩溃
unity·c#·游戏引擎·.net
开发游戏的老王1 天前
虚幻引擎虚拟制片入门教程 之 3D渲染基础知识:模型、材质、贴图、UV等
3d·虚幻·材质·模型·着色器·uv
开发游戏的老王1 天前
虚幻引擎虚拟制片入门教程 之 模型资源的导入
java·游戏引擎·虚幻
向宇it2 天前
【推荐100个unity插件】将您的场景渲染为美丽的冬季风景——Global Snow 2
unity·游戏引擎·风景
浅丿忆十一2 天前
关于unity一个场景中存在多个相机时Game视图的画面问题
unity·游戏引擎
WLJT1231231232 天前
方寸之间见天地:新兴高端印章的当代破局与价值重构
unity·游戏引擎