stonstad 发表于 2022-3-28 09:05

Unity 旋转:欧拉角与万向死锁

Unity API

Transform.Rotate

Declaration

public void Rotate(float xAngle, float yAngle, float zAngle, Space relativeTo = Space.Self);
Description

Applies a rotation of eulerAngles.z degrees around the z-axis, eulerAngles.x degrees around the x-axis, and eulerAngles.y degrees around the y-axis (in that order).
Rotate takes a Vector3 argument as an Euler angle. The second argument is the rotation axes, which can be set to local axis (Space.Self) or global axis (Space.World). The rotation is by the Euler amount.
注意事项

如果填 3 个值 x、y、z,那么应用的顺序为 z、x、y,而且一句 API 是一次旋转,一次旋转内的相对轴是不变的(或者说一次旋转内使用的相对轴是旋转之前的)。
比如,若是Space.World:
public void Action01()
{
    transform.Rotate(90f, 0f, 0f, Space.World);
    transform.Rotate(0f, 90f, 0f, Space.World);
    transform.Rotate(0f, 0f, 90f, Space.World);
}

public void Action02()
{
    transform.Rotate(90f, 90f, 90f, Space.World);
}
Action01 是在世界坐标系将物体以 x、y、z 的顺序分别转 90°;Action02 是在世界坐标系将物体以 z、x、y 的顺序分别转 90°。
若是Space.Self:
public void Action01()
{
    transform.Rotate(90f, 0f, 0f, Space.Self);
    transform.Rotate(0f, 90f, 0f, Space.Self);
    transform.Rotate(0f, 0f, 90f, Space.Self);
}

public void Action02()
{
    transform.Rotate(90f, 90f, 90f, Space.Self);
}
Action01 是在物体坐标系将物体以 x、y、z 的顺序分别转 90°,注意每句 API 调用之后自身的物体坐标系就会改变;Action02 是在物体坐标系将物体以 z、x、y 的顺序分别转 90°,由于是一句 API,转 x、y、z 时都是以这句 API 调用之前的自身物体坐标系为基准旋转的。
Transform.eulerAngles

Description

The rotation as Euler angles in degrees.
Transform.eulerAngles represents rotation in world space. When viewing the rotation of a GameObject in the Inspector, you may see different angle values from those stored in this property. This is because the Inspector displays local rotation, for more information see Transform.localEulerAngles.
Euler angles can represent a three dimensional rotation by performing three separate rotations around individual axes. In Unity these rotations are performed around the Z axis, the X axis, and the Y axis, in that order.
You can set the rotation of a Quaternion by setting this property, and you can read the Euler angle values by reading this property.
Transform.localEulerAngles

The rotation as Euler angles in degrees relative to the parent transform's rotation.
Euler angles can represent a three dimensional rotation by performing three separate rotations around individual axes. In Unity these rotations are performed around the Z axis, the X axis, and the Y axis, in that order.
You can set the rotation of a Quaternion by setting this property, and you can read the Euler angle values by reading this property.
Unity 欧拉旋转讲解

按照 z、x、y 的顺序可理解为父子结构 y、x、z 的嵌套,即三层物体嵌套:顶层只动 y 轴,中层只动 x 轴,底层只动 z 轴。
所以,中层的 x 轴转动了 90° 之后,底层的 z 轴就会与顶层的 y 轴相重合,就产生了万向死锁。
详细点说就是,底层的 z 轴在上层的其它轴旋转后,再想去动它就是相等于动物体坐标系下的 z 轴,然而这个物体坐标系下的 z 轴已经与顶层世界坐标系下的 y 轴重合了,于是就产生了万向死锁,即不管怎么转 z、y 轴都只是在一个轴打转,无法过渡到另一姿态,要动的话只能再去改 x 轴。
从矩阵角度来看的话,这种等效的三层物体嵌套的矩阵就是(列向量,参考 OpenGL):

https://www.zhihu.com/equation?tex=M_Y+%5Ccdot+M_X+%5Ccdot+M_Z+%5Ccdot+Position
以如何解决这个问题呢?如果只是要保证物体在任意姿态都可过渡到另一姿态的话,一个简单的方法就是,既然变换顺序是 z、x、y,那么动过的轴(变换矩阵),就不要再动它了,因为它已经是物体坐标系下的了,要动就在世界坐标系下动。
这个方法用矩阵来说就是,在最右边再加矩阵 https://www.zhihu.com/equation?tex=M_N 。即:

https://www.zhihu.com/equation?tex=M_N+%5Ccdot+M_Y+%5Ccdot+M_X+%5Ccdot+M_Z+%5Ccdot+Position
用物体嵌套的角度来说就是在顶层的 y 轴物体上再加一个父物体 N,然后修改物体 N 的旋转。
用传统的陀螺仪机械结构来说的话,若中间的环转了 90° 导致最外层与最内层的环重合的话,那就在最外侧再加一个环。
当然这种方案在实际机械上是不可行的,但是矩阵连乘方面则有一定的价值。
参考链接

https://blog.csdn.net/AndrewFan/article/details/60866636
https://blog.csdn.net/AndrewFan/article/details/60981437
https://blog.csdn.net/fengya1/article/details/50721768
https://www.bilibili.com/video/BV1YJ41127qe/
页: [1]
查看完整版本: Unity 旋转:欧拉角与万向死锁