Unity在旋转时出现万向节锁的解决方案
关于万向节锁在Unity官方文档中有这样的描述:
欧拉角
在变换坐标中,Unity 使用矢量属性Transform.eulerAngles
X、Y 和 Z 显示旋转。与法线矢量不同,这些值实际上表示绕 X、Y 和 Z 轴旋转的角度(以度为单位)。
欧拉角旋转围绕三个轴执行三个单独的旋转。Unity 依次围绕 z 轴、x 轴和 y 轴执行欧拉旋转。这种旋转方式就是外旋转;旋转发生时原始坐标系不会改变。
要旋转游戏对象,您可以在变换组件中输入您希望每个轴旋转多远的角度值。要使用脚本旋转游戏对象,请使用Transform.eulerAngles
. 如果您转换为欧拉角来进行计算和旋转,则可能会出现万向节锁定问题。
万向节锁
当 3D 空间中的物体失去一定的自由度并且只能在二维空间内旋转时,称为万向节锁。如果两个轴平行,则欧拉角可能会发生万向节锁定。如果您不在脚本中将旋转值转换为欧拉角,则使用四元数应该可以防止万向节锁定。
如果您确实遇到万向节锁定问题,则在用于旋转时可以避免欧拉角Transform.RotateAround
。您还可以Quaternion.AngleAxis
在每个轴上使用并将它们相乘(四元数乘法依次应用每个旋转)。
四元数
四元数为 3D 空间中空间方向和旋转的独特表示提供数学符号。四元数使用四个数字来编码 3D 中绕单位轴旋转的方向和角度。这四个值是复数而不是角度或度数。您可以研究四元数的数学以获取更多信息。
Unity 将旋转值转换为四元数来存储它们,因为四元数旋转计算高效且稳定。Unity 编辑器不会将旋转显示为四元数,因为单个四元数无法表示绕任何轴大于 360 度的旋转。
如果使用Quaternion类就可以直接使用四元数。如果您使用脚本进行旋转,则可以使用四元数类和函数来创建和更改旋转值。您可以将值作为欧拉角应用于旋转,但需要将它们存储为四元数以避免出现问题。
具体的可以参考文档:Unity 中的旋转和方向(https://docs.unity3d.com/cn/current/Manual/QuaternionAndEulerRotationsInUnity.html)
所以尽量避免使用Transform.eulerAngles进行计算旋转,举个例子,鼠标控制相机的旋转你可能会这样写
void CameraRotate(float speed) { Vector3 rot = transform.eulerAngles; rot.z = 0; rot.y -= Input.GetAxis("Mouse X") * speed * Time.deltaTime; rot.x += Input.GetAxis("Mouse Y") * speed * Time.deltaTime; transform.eulerAngles = rot; }
放到Update每帧调用时,你观察Inspector面板会发现在x轴接近90度时,z轴居然不是0,出现这种现象也就是上面所说的万向节锁
那么该怎么避免呢,官方文档也给出了方案,定义一个全局的Vector3,在Start的时候,给Vector3赋值:
Vector3 currentEulerAngles; void Start() { currentEulerAngles = transform.eulerAngles; } void CameraRotate(float speed) { currentEulerAngles.z = 0; currentEulerAngles.y -= Input.GetAxis("Mouse X") * speed * Time.deltaTime; currentEulerAngles.x += Input.GetAxis("Mouse Y") * speed * Time.deltaTime; transform.eulerAngles = currentEulerAngles; }
这样通过累加currentEulerAngles就可以避免出现万向节锁,当然如果你想用Transform.Rotate之类的方法旋转也是可以的,
当时一定不要每帧都去获取transform.eulerAngles,而是定义一个全局的字段,去进行旋转计算赋值等操作
具体的文档可以参考:https://docs.unity3d.com/cn/current/ScriptReference/Transform-eulerAngles.html
https://docs.unity3d.com/cn/current/ScriptReference/Transform.Rotate.html
原创不易,如果觉得有用,留下你的足迹吧,你的鼓励我的动力
博客园Jason_c微信打赏码
如果本篇文档对你有帮助,打赏Jason_c根华子吧,他的私房钱被老婆没收了,呜呜!