将欧拉角添加到四元数

9
我想要将一个欧拉角添加到现有的四元数中。这是我得到的代码:
Quaternion oldTransform = transform.Rotation;

float YawRotation = mouseDiff.x *  RotationSpeed;
Quaternion YawRotationQuaternion = new Quaternion();
YawRotationQuaternion.CreateFromAxisAngle (0, 1, 0, YawRotation);

float PitchRotation = mouseDiff.y * RotationSpeed;
Quaternion PitchRotationQuaternion = new Quaternion();
PitchRotationQuaternion.CreateFromAxisAngle ( 1, 0, 0, PitchRotation);

Quaternion result = oldTransform * YawRotationQuaternion * PitchRotationQuaternion;
transform.Rotation = result;

我希望只有偏航和俯仰旋转。旧的变换已具备此属性。我添加的欧拉角也仅包含俯仰和偏航旋转。当我进行乘法运算时,旧变换所描述的旋转会引入横滚旋转。
然后我尝试了:
Quaternion result = YawRotationQuaternion * oldTransform * PitchRotationQuaternion;

这不会引入滚动旋转。这个选项甚至更糟,因为当旧变换(oldTransform)将偏航轴旋转到俯仰轴时,它会出现万向节锁定(gimbal lock)。

现在我可以想象的是,从oldTransform获取旧的偏航和俯仰旋转,并修改偏航和俯仰轴,使它们不再是(0,1,0)和(1,0,0)。这里的问题是,当我从四元数中提取欧拉角时,也会出现万向节锁定。

那么如何将特定轴的欧拉角添加到四元数中呢?


突然间,我感到很笨。 - Bill Gregg
对不起,那不是我的意图... - jsf
当然不是,这不是你的错。好问题。 - Bill Gregg
2
万向节锁定是在使用俯仰/偏航/滚转或欧拉角时发生的。你无法避免这种情况。这就是为什么要使用四元数的原因之一。你实际上想要做什么? - Nico Schertler
这篇文章很好地解释了你的问题:http://math.stackexchange.com/questions/8980/euler-angles-and-gimbal-lock - Tilo
1个回答

7
解决方案:
改变您的转换顺序。
Quaternion result = PitchRotationQuaternion * oldTransform * YawRotationQuaternion;

Explanation:

您有一个带有本地参考系的对象。我将说+x_o朝向对象的右侧,-z_o是“前进”,而+y_o是相对于对象的“上方”。该对象存在于世界的参考系中。世界有自己的坐标轴:(x_w,y_w,z_w),其中+y_w是世界的上方。当对象改变方向时,您希望它进行俯仰(围绕x_o旋转),并进行偏航(围绕y_w旋转)。

在您的代码中,您创建了两个四元数。应用它们的方式表示围绕x_wy_w旋转。如果已经应用了任何偏航到变换中,则x_o不再与x_w对齐;因此,您将获得一些翻滚。幸运的是,对于您正在应用的变换,万向节锁定不是问题。如果您俯仰90度,则万向节锁定会在这里表现为偏航翻滚变成相同的事情。但是您没有使用翻滚;所以这不重要。

您的变换始终可以表示为围绕x_w旋转,然后是围绕y_w旋转。将新的“俯仰四元数”放在旧变换的左侧会将其添加到其他累积的俯仰中。保持“偏航四元数”在右侧会将其添加到累积的偏航中。因此,如果您将最终四元数表示为一堆乘法,则它将是一串纯粹围绕x_w旋转的字符串,后跟一串围绕y_w旋转的字符串。只要对象从x_o平行于x_w开始,这样做就可以实现您想要的效果。


1
可以了,谢谢!我花了一些时间才找到答案。现在我的问题是需要在某个地方反转旋转的顺序。但这是另一个话题了。问题已经解决 :) - jsf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接