四元数 - 旋转到

时间:2012-10-22 15:46:05

标签: c++ math quaternions

我在世界空间中有一些物体,让我们说在(0,0,0)并且想要将它旋转到面(10,10,10)。

我如何使用四元数?

4 个答案:

答案 0 :(得分:8)

这个问题没有多大意义。你说你希望一个对象“面对”一个特定的点,但这并不能提供足够的信息。

首先,面对这个方向意味着什么?在OpenGL中,这意味着本地参考帧中的 -z 轴与某些外部参照系中的指定方向对齐。为了实现这种对齐,我们需要知道对象的相关轴当前“面向”的方向。

但是,仍然没有定义唯一的转换。即使您知道使 -z 轴点成为什么方向,该对象仍然可以自由旋转围绕该轴。这就是函数gluLookAt()要求您提供'at'方向'up'方向的原因。

我们需要知道的下一件事是最终结果需要采用什么格式?对象的方向通常以四元数格式存储。但是,如果要以图形方式旋转对象,则可能需要旋转矩阵。

所以让我们做一些假设。我假设您的对象位于世界点 c 的中心,并且具有默认对齐方式。即,对象的 x y z 轴与世界的 x y对齐 z 轴。这意味着对象相对于世界的方向可以表示为单位矩阵或标识四元数:[1 0 0 0](使用四元数约定,其中 w 首先出现)。

如果您想要最短的旋转将对象的 -z 轴与点 p := [px py pz]对齐,那么您将围绕轴旋转φ的一个即可。现在我们将找到这些价值观。首先,我们通过对矢量 pc 进行归一化,然后使用单位长度 -z 向量的交叉积来找到轴 a ,然后再次归一化:

a = normalize(crossProduct( -z ,规范化( p-c )));

通过取其点积的反余弦得到的这两个单位向量之间的最短角度:

φ= acos(dotProduct( -z ,规范化( p-c )));

不幸的是,这是两个矢量形成的角度的绝对值的量度。当围绕 a 旋转时,我们需要弄清楚它是正还是负。必须有一种更优雅的方式,但想到的第一种方法是找到第三个轴,垂直于 a -z ,然后从中取出符号它与我们的目标轴的点积。可见:

b = crossProduct( a -z );

if(dotProduct( b ,normalize( p-c ))< 0)φ=-φ;

一旦我们获得了轴和角度,将其转换为四元数很容易:

q = [cos(φ/ 2)sin(φ/ 2) a ];

这个新的四元数表示对象的新方向。它可以转换为矩阵用于渲染目的,或者如果需要,可以使用它直接旋转对象的顶点,使用四元数乘法规则。

答案 1 :(得分:1)

可以在Ogre::Vector3 class的OGRE源代码中找到计算表示两个向量之间旋转的四元数的示例。

答案 2 :(得分:1)

为了回应你的澄清并回答这个问题,我无耻地复制了一个非常有趣和简洁的算法,用于找到两个向量之间的quat,看起来像我以前从未见过here。在数学上,它似乎是有效的,因为你的问题是关于它背后的数学,我相信你将能够将这个伪代码转换为C ++。

quaternion q;
vector3 c = cross(v1,v2);
q.v = c;
if ( vectors are known to be unit length ) {
    q.w = 1 + dot(v1,v2);
} else {
    q.w = sqrt(v1.length_squared() * v2.length_squared()) + dot(v1,v2);
}
q.normalize();
return q;

如果您需要帮助澄清该伪代码的任何位,请告诉我。应该是直截了当的。

dot(a,b) = a1*b1 + a2*b2 + ... + an*bn

cross(a,b) = well, the cross product. it's annoying to type out and
can be found anywhere.

答案 3 :(得分:0)

您可能想要使用SLERP(球面线性插值)。请参阅此article以获取有关如何在c ++中执行此操作的参考