Unity 中的旋转和朝向

本文深入探讨Unity中旋转和朝向的实现方式,重点对比欧拉角和四元数的特点与应用场景。揭示了Unity为何选择四元数作为内部表示,同时解释了欧拉角在编辑器中的优势。此外,文章还提供了编程中使用四元数和欧拉角的正确实践,以及在动画处理中避免旋转限制的方法。

Rotation and Orientation in Unity

官方文档地址:Rotation and Orientation in Unity

Unity中的旋转,通常用四元数和欧拉角来表示。它们都有优缺点。Unity内部用四元数,在Inspector中显示欧拉角形式,因为该方法已于理解和编辑。

欧拉角和四元数

欧拉角

欧拉角由按照顺序在x,y,z轴上进行的旋转表示,当将一个欧拉角应用到一个GameObject时,每个轴上的旋转都会被分别应用。

  • 好处:欧拉角对于人来说时可读的,可以跟读欧拉角在脑海建立旋转概念。
  • 好处:欧拉角可以表达超过180度的旋转,对应的,四元数会“寻找”旋转的最短路径,但是有时可能逻辑上是不正确的,比如对于一个不能以360度旋转的炮塔,从最左旋转到最有,对端路径会打破旋转限制。
  • 限制:欧拉角受限于万向锁 Gimbal Lock,当在3个轴上旋转时,可能第一次或第二次旋转导致第三次旋转轴指向跟前面旋转的轴同样的方向,叫做“degree of freedom”(旋转自由度)丢失,因为第三个旋转值无法应用到对应的轴上,也可以理解为丢失了一个旋转轴。

四元数

四元数可以被用来表示旋转或对象的朝向。该数学模型,用4个数来表示(x,y,z,w),然而这些数字既不表示旋转轴,也不表示旋转角度,无法理解,所以我们不能直接修改xyz分量的值(w表示角度,可能会发生错误。除非你非常了解这背后的数学原理。

小秘密:轴和角度藏在四元数中。假设沿着轴(nx,ny,nz)旋转,角度为A度,则四元数为:

[w, x, y, z] = [cos(A/2), sin(A/2)nx, sin(A/2)ny, sin(A/2)nz]

Vector3可以表示位置和方向(当表示方向时,时原点在000点),一个四元数可以表示朝向和旋转,当表示旋转时,是从identity开始的旋转。四元数不能表达超过180度的旋转。

  • 好处:没有万向锁问题
  • 限制:不能表达超过180度的旋转,四元数用-180到180来表示360度的旋转。
  • 限制:不可读,无法直接理解值的含义。

Unity用四元数来存储GameObject的旋转,因为四元数更加健壮。

但是在Inspector面板上,显示的旋转是用欧拉角来表示的,因为欧拉角是可读可编辑的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1KdbpY1X-1580048145871)(https://docs.unity3d.com/uploads/Main/InspectorRotationEulerAngles.png)]

所以,可以看到,如果我们可以在Inspector中设置x:0,Y:365,Z:0来设置对象的旋转,因为四元数无法表达该旋转,因此,启动游戏后,会变成X:0,Y:5,Z:0。效果相同。

编程中

当在脚本中处理旋转时,应该用四元数来创建或修改旋转值。当然有些情况下,使用欧拉角也是有效的,但是要牢记,要使用四元数接口来处理欧拉角,从四元数获取,修改,重新应用欧拉角到四元数,可能会产生错误的结果。

直接创建和操作四元数

Unity提供了接口,用来创建和操作四元数,而且不需要欧拉角的参与。例如

创建
操作
欧拉角使用注意

然而,有时我们希望在代码中使用欧拉角,这时,要将角度存储到自己定义的变量中,并且用这些变量更新旋转。因为以获取->修改->应用欧拉角的流程写代码,会出错,因为每次取得的欧拉角,是临时从四元数计算出来的,每次计算可能返回不同的欧拉角,可能会导致万向锁问题。

// 正确
float x;
void Update () 
{
	x += Time.deltaTime * 10;
	transform.rotation = Quaternion.Euler(x,0,0);
}

// 错误
void Update () 
{
	var angles = transform.rotation.eulerAngles;
 	angles.x += Time.deltaTime * 10;
	transform.rotation = Quaternion.Euler(angles);
}

动画中

很多3D创作插件,以及Unity内部,都有自己的动画窗口,来用欧拉角编辑动画的旋转。

这些旋转,经常超过四元数表达的范围,比如旋转720度,欧拉角是没问题的,但是对于四元数来说,等于没有旋转。

Unity 的 Animation Window

Unity内部的动画编辑窗口,提供了设置选项,来决定如何进行插值,用四元数或欧拉角。通过指定使用欧拉角,可以告诉Unity我们想要在完整的运动范围内插值。如果用四元数,则会限制在限定的范围内(-180,180),并用四元数插值。

导入的动画数据

导入的外部动画资源,文件通常会使用欧拉角记录旋转。默认Unity会重新进行采样动画生成新的四元数动画帧,以避免旋转超出四元数有效范围。

例如,想象有2帧动画,相隔6帧。第一帧旋转x=0,第二帧(6帧后)旋转是270。如果直接用四元数在这两帧之间进行插值,则动画会沿着最短路径旋转,即向相反方向旋转90度。但是通过重新采样,将旋转定义为6帧,没帧是45度,这样在进行四元数插值时,就正确了。

有时候,通过重新采样,也不能达到跟原始动画完全重合,这时,可以在动画导入设置中,关闭重新采样选项(Resample Curves),在运行时使用欧拉角进行插值。

### 控制 Spine 骨骼动画的朝向Unity 中,可以通过多种方式来控制 Spine 骨骼动画的朝向。一种常见的方式是通过修改 `SkeletonGraphic` 组件的 `localScale` 属性来实现角色的反向显示[^4]。 下面是一个具体的例子: ```csharp using Spine.Unity; using UnityEngine; public class AdjustSkeletonGraphicDirection : MonoBehaviour { public SkeletonGraphic skeletonGraphic; void Start() { if (skeletonGraphic != null) { // 获取当前缩放值并反转 X 轴方向 Vector3 scale = skeletonGraphic.transform.localScale; scale.x = -Mathf.Abs(scale.x); skeletonGraphic.transform.localScale = scale; } else { Debug.LogError("SkeletonGraphic component not assigned."); } } } ``` 这段代码展示了如何通过脚本改变 `SkeletonGraphic` 的局部缩放属性,从而达到翻转角色的目的。当 `scale.x` 设置为负数时,角色会沿 X 轴镜像翻转,即改变了角色的朝向。 除了上述方法外,还可以考虑使用旋转的方式来调整骨骼动画的方向。不过需要注意的是,在某些情况下,直接操作 `transform.rotation` 可能会影响骨骼之间的相对位置关系,因此建议优先尝试通过缩放来进行简单的水平翻转处理。 对于更复杂的朝向变化需求,则可能涉及到对特定骨头(bone)的操作或是利用 Mecanim 动画控制器配合 `SkeletonAnimator` 来完成更加精细的动作控制[^1]。 #### 注意事项 - 修改 `localScale` 是最简单的方法之一,适用于只需要做左右翻转的情况。 - 如果需要连续变换角度而非单纯的水平翻转,则需探索其他解决方案,比如基于物理引擎的应用或自定义算法计算新的姿态矩阵等高级技术。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值