unreal里Actor的旋转
unreal里Actor的旋转
小保哥 发表于1年前
unreal里Actor的旋转
  • 发表于 1年前
  • 阅读 110
  • 收藏 0
  • 点赞 0
  • 评论 0

移动开发云端新模式探索实践 >>>   

仅以Actor为例子。Components与之一样。

仅描述Rotation,不讲Location与Scale。

2个API
> * GetActorRotation(取的是world系)
> * SetActorRotation(设的是world系)

两个重点:
1. unreal里四元数乘法A*B,代表先执行B旋转,再在新的姿态下执行A旋转。这一条与是否局部或全局坐标系没关系,它就是恒成立。
2. 从零姿态开始构建旋转。

讲2个例子。紧紧的围绕着上述真理来思考unreal里的变换,不要想多。

> 例子一:父和子两个物体。要求子物体在当前姿态的基础上,绕自身坐标轴旋转。

> 分析:当前姿态X通过GetActorRotation可以获取。绕自身坐标轴的旋转为N。很自然的,我们可能认为这个旋转需求可以通过N*X来实现。没错,这是正确的,满足上面说的从零姿态运动到X姿态,再执行N旋转得到最终姿态。但问题是,这个N不像我们以为的那样容易描述,因为这个N必须是在子物体处于当前X姿态的世界系中描述的,而它的坐标轴此时很可能不是0、1、0三个数。所以,我们必须变通一下。我们先在子物体处于world零姿态时描述一下N,这时的N是很容易描述的,在执行N旋转后, 再执行X旋转,所得的效果也满足需求。即X*N为所求。这里的X、N均为world系描述。(20170522补充:其实在姿态X的前提下,要描述绕自身坐标轴的旋转N,可以这么求,,其中Local是绕自身坐标轴旋转的世界系描述<此时说是局部系描述也对>,求出的N是在姿态X的前提下,绕自身坐标轴旋转的世界系描述,进而变换合成为,这个推理表明:在某个确定的变换后,要让物体绕自身坐标轴旋转,等价于,先让物体绕自身坐标轴旋转,再做那个确定的变换。不过,这句话里的两个绕自身坐标轴旋转的变换矩阵是不一样的。参考下一篇文章。)(20170531补充:这里其实并没有交换旋转顺序,而是在求N在世界系的描述。如果若干旋转是绕同样的轴,那么这些旋转可以任意交换旋转顺序,不影响最终的姿态结果;但如果这些旋转是绕不同的轴进行,那么它们的合成必须按照旋转发生的顺序连乘,不能交换顺序。)

> 与此同类型的一个重要问题:如何将物体在局部坐标系下进行旋转。

> 答案很简单:X*N即为所求。

> 这里的X是父节点的world系姿态Parent,N为局部旋转描述Local。即Parent*Local即为所求。注意:因为我们是从world系零姿态开始,先描述的N,在这个时候,局部旋转等价于全局旋转描述,但是从数学上来说,N、Local是world系描述。

 

> 例子二:父和子两个物体。要求子物体在当前姿态的基础上,执行已给出world系数值描述的旋转N。

> 分析:当前姿态X通过GetActorRotation可以获取。然后执行新的旋转N,最终姿态N*X即为所求。这个问题其实是例子一的一般化。如果例子一中的绕自身坐标轴的旋转也给出了子物体在姿态X的前提下的world系数值描述,那最终结果就是N*X即可。

 

> 最后说一句,我们求出X*N或者N*X之后,需要将这个值传给SetActorRotation函数来执行它代表的旋转。

 

==============2017.05.05 更新=================

父节点为世界系姿态X时,对子节点SetActorRotation(X*N)等价于SetActorRelativeRotation(N).   N仍为父子物体均处world系零姿时开始构建。

若已知X*N与X,则N=(X^-1) * (X * N),即子物体相对于父物体的RelativeRotation=(Parent(world)^-1) * Child(world).

(Unreal Engine的Editor中,Transform里设置Rotation时,注意x和y值(即Roll和Pitch)的正负定义与一般的左手法则相反,z值(即Yaw)的正负定义与一般的左手法则一致。这一点从FRotator的头文件定义中可以清楚的看到。当FRotator转换成FQuat时,从转换函数里能看到x和y项均加了负号进行修正,以使得四元数的旋转正负定义与一般的左手法则一致。所以,最好以四元数来思考旋转,这样从不同的系统进行坐标变换时,按照一般的左右手法则就能得到正确的结果。)

 

==============更新2017.05.11=================

有一个比较常见也比较重要的例子值得分析一下,就是Unreal里AnimationNode的动画数据。

在AnimationNode插件中,一般会有下面这行代码:

NewRotation = CTParentWorldRotation.Inverse() * NewRotation * WorldRotations[BoneIndex];

代码里的WorldRotations是骨骼的Reference Pose中的原始数据。我面临的现实是:在maya中做好的模型导入到unreal中时,勾选了Import Reference Pose,那么FPoseContext中读取的这个Reference Pose其旋转数值是不为零的。

讲一下正确的处理方法:

首先,很重要的一点是模型的正确导入。模型导入到场景之后是否正确,我认为有一个标准:这里涉及两个坐标系,一个产生数据的坐标系(动捕系统或其他),一个展示数据的坐标系(unreal等)。你可以自己定义这两个坐标系的前方,但是一旦你确定之后,那么在数据源坐标系中面对前方的零姿态必须与展示坐标系中模型面对前方的零姿态一致。如果用数据源的零姿态驱动模型时,模型不是处于面向前方的零姿态,那么这个模型就算导入失败了。用加父节点旋转等等纠正的方式不是万能的,建议果断删掉重新导入。模型导入unreal时,会出现一个Import属性窗口,里面有个Transform栏,这个就是做纠正用的,在这里做完修正,模型导入后,其零姿态肯定是你想要的。这里的修正量就是第一次导入不正确时的offset,这个在第一次导入时要关注一下。

其实模型导入正确后,后面的数据接入就比较容易了。如果在错误模型导入的基础上做数据变换,有时现实会打脸打得很残酷。不要太过于自信。一定要在正确的基础上,做下一步的事情。外部欧拉角进unreal时,其实很简单,抓住Pitch、Yaw、Roll三个概念来对,Pitch和Pitch对上,Yaw和Yaw对上,Roll和Roll对上。然后再来看符号。符号这样确定,unreal是左手系,伸出左手,握住Yaw即竖直轴,大拇指向上,其余四指抓握的绕向就是unreal里Yaw的正方向,如果数据源的Yaw(具体哪个手,视具体情况而定)的正方向也是这个绕向,那么,两个Yaw符号相同。剩余两轴同此操作过程,但是一定要注意:unreal里握住Pitch或Roll轴,且大拇指朝向两根轴的正方向时,其余四指抓握的绕向分别为Pitch和Roll的负方向。不要问为什么这么奇怪,它实践上就是如此。三个轴对应上,且符号也正确后,最后调用FRotator(Pitch, Yaw, Roll)即可拿到正确的旋转。后续如果还需要对这个旋转进行修正的话,一定不要修改这个已对好的Rotator,而应该构造新的旋转施加到这个Rotator上,来达到最终的目的。

如果你非要在一个错误的模型上变换。那你还不如像下面这样,在unreal里建一个带轴向的小方块,用数据驱动它,只要它对了,数据肯定就对了。剩下的再视情况导入正确的模型或者在正确的旋转上额外加变换,来达到变态的目的。

 

==================2017.09.10补充 ↓====================

Unreal里的这些变换类太好使了,以至于都快忘了下面这些东西了:

在ZED中就没有unreal那么方便,还得根据上图里的这些东西来计算矩阵,麻烦。

 

  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 5
博文 35
码字总数 34829
×
小保哥
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: