APSchmidt 发表于 2022-11-3 09:46

为什么Unity3d旋转默认采用了有万向节死锁的欧拉角,而不 ...

主要疑问是为什么默认使用欧拉角,而不用四元数,是这两者在应用应用场景上,特别是unity,有特殊区别吗?比XX场景欧拉角比四元数表现更出色。
Unity3d场景中,object的旋转会出现万向节死锁,开发者还需要自己做一番操作去解决死锁。既然这样,为什么Unity3d对于这个死锁,为什么不直接从底层解决,避免死锁,提高开发者的开发效率?
特别在场景中直接操作object旋转的时候经常出现旋转乱翻让人砸电脑的想法,而在其它软件如3d max操作旋转并未不会出现...

ChuanXin 发表于 2022-11-3 09:52

内部是四元数,只是inspector上是欧拉角方便人工编辑。

mastertravels77 发表于 2022-11-3 09:59

问题不存在,Unity用的就是四元数。

unityloverz 发表于 2022-11-3 09:59

Unity 没有提供任何基于欧拉角的运算方法。

xiangtingsl 发表于 2022-11-3 10:02

好的时隔一年...这篇回答重写...
首先呢...
Unity的底层是通过四元数记录物体旋转的,并通过矩阵和四元数实现物体的旋转及插值



但在上层Unity提供了,向欧拉角进行转换输出,并能够通过欧拉角进设置物体旋转的功能



呃...没错就是这个属性,但你要知道这是从底层的四元数转换来的



多翻翻脚本API嘛...

一些本通过四元数进行旋转/插值计算的方法,在上层也是通过欧拉角输入对应旋转值



比如说这个方法虽然输入的是欧拉角

但毕竟transform.rotation是一个四元数,因而这个方法底层实现也是通过四元数(应该吧...也有可能用的HPB矩阵,反正不是用欧拉角做的)



这是由于相较矩阵和四元数,欧拉角是最接近人类直观思维的一种3D旋转表达模式,我是说你应该不想通过输入矩阵或者四元数来旋转物体吧...(除非你是神仙)
在底层通过矩阵/四元数,记录完成旋转,避免万向锁,但在上层提供欧拉角的转换输出和旋转设定,这应该说是当下大多数3D架构都普遍采用的一种模式
Unity就是这样做的,所以不要再说它用了什么屑欧拉角,那是为了照顾我们这些上层开发的凡人
<hr/>此外还要提两点的

一是,限制欧拉角
由于存在 四元数--->欧拉角 这样的底层到上层的转换输出,因而就需要引入限制欧拉角规则
这是由于三角函数是一个周期函数,因而我们进行反三角函数运算的时候,要将输出值限制在一定的范围内,否则会有无穷多解
其实这也是由于欧拉角的一大缺点之一,因为±360度角度值相同,导致对于同一3D方位/角位移会有无数种表示
Unity中的欧拉角采用 Y(Heading)-->X(Pitch)-->Z(Bank) 的轴顺序,对应的限制规则,是将Y和Z轴的旋转数值限制在[-180,180],中间X轴旋转数值限制在[-90,90]
总之就是内外转轴360度全域,中间转轴只有180度半域
这里给出四元数(x,y,z,w)对应HPB的转换方法是下面这样


其实我们的限制欧拉角规则就已经包含在了转换方法中,因为asin的值域是[-pi/2,pi/2],而atan2的值域是[-pi,pi]
所以你通过transfrom.eulerAngle获取到的欧拉角值就是经过限制后的值
transfrom.eulerAngle.y/z 直接输出值是在
transfrom.eulerAngle.x 输出值是 U
如果你进行±360度,映射回[-180,180],Y和Z轴转值正好填满[-180,180]而,X轴就变为了[-90,90]
嘛总归是YZ 360度全域,X只有180度半域没错啦

这种限制欧拉角就导致了一些情况下,transfrom.eulerAngle获取到的旋转角,尤其是针对X轴和预期的有些出入
并且特别提醒,transfrom.eulerAngle获取到的值,和你在Inspector窗口的Transfrom组件中看到的旋转数值又是不一样的,Unity编辑器又经过了额外的封装





没错,transfrom.eulerAngle和这里是不一样的,这里是Unity编辑器又经过一次封装产生的效果,允许超限角度的显示输出和设定

二是,Unity对万向锁的两个处理
虽然底层通过四元数记录完成旋转,但由于提供了transfrom.eulerAngle属性,因而需要对通过该属性设置旋转角,可能遇到的万向锁时的情况进行相应的处理
首先是阻止通过transfrom.eulerAngle角度设定插值,使物体转过万向锁的位置(像是有一道锁阻止了物体旋转)
这是因为Unity中已经通过四元数进行了旋转的记录和完成,因而不提供欧拉角的旋转插值过渡的计算方法



比如这段代码通过欧拉角来使物体发生绕X轴的旋转



可以看到飞机的旋转在正上方时停止,无法划过正上方

一些使用欧拉角进行旋转插值的架构(例如3dMax),需要对欧拉角的插值运算数值进行相应的处理,但受到万向锁时自由度丢失的影响会产生卷绕效应



这里在发生万向锁位置附近,物体超丢失自由度的方向进行360度旋转,受卷绕效应的影响,姿态发生了突变

其次是,当Pitch正好为±90度时,四元数--->欧拉角 的转换就变为了



如果你推过矩阵/四元数 在Pitch为正负90度的转换,就知道此时只有(H+B)项

这种情况下,又出现了欧拉角不唯一的问题,转换推导只有(H+B)的sin/cos项,因而我们不得不令其中一个为0,将旋转完全用另一方表示
Unity中,是将Z轴(Bank)旋转归0,从而推导出Y轴(Heading)的旋转值
此时如果我们通过欧拉角旋转Z轴,就会产生类似旋转实际被应用到Y轴上的效果



我们通过ongui展示transfrom.eulerAngle,编辑器直接设置X轴旋转值为90度,来到发生万向锁位置,Z轴转置归0,输出Y轴旋转数据



此时我们通过编辑器进行Z轴旋转,可以看到transfrom.eulerAngle.z始终为0,而Y轴旋转数值发生变化,旋转可以看作被应用到了Y轴上

<hr/>如果你想了解更多有关矩阵/四元数/欧拉角进行3D方位/角位移表示的知识,那么推荐阅读这篇笔记的对应章节
Randy:学习笔记-《3D游戏数学基础:图形与游戏开发》如果你了解更多有关万向锁的知识,看看使用欧拉角进行旋转插值的架构,在发生万向锁时,产生卷绕效应的实际表现,我向您推荐这篇文章,里面有很多精心制作的动图

欧拉角与万向锁
顺带强烈建议您阅读这篇文章!!!

Randy:矩阵变换的本质 --- 欧拉角与矩阵与万向锁问题
感谢您的阅读
这里是Randy
Rise above.Focus on science.
2020/04/27
16:39

ainatipen 发表于 2022-11-3 10:03

四元数是给人看的吗?你直接用矩阵多好?
四元数两个关键帧能插值大于180度的动画吗?
四元数能只看数字调单独某个轴的动画吗?
感觉这问题像第一天学动画知道有万向节锁死这个事
再说欧拉角又不是随随便便就锁死了
一般情况都能正常工作,最主要是很直观啊
页: [1]
查看完整版本: 为什么Unity3d旋转默认采用了有万向节死锁的欧拉角,而不 ...