从两对三点(或两对两个矢量)导出轴/角度旋转

时间:2011-01-12 14:46:22

标签: math

请注意,尽管听起来很相似,但这并不是常见的“如何将一个矢量旋转到另一个矢量”这个问题。

我想从两组3个点得到一个仿射变换(矩阵或四元数+矢量形式)。这些可以被视为刚体上的“标记点”,或者作为“向前和向上”向量的端点。 翻译和旋转是必要的,缩放不是必需的。此外,四元数+向量解决方案将是一个加号,因为它将允许我将1/3多个实例塞入绘图批次(8个制服而不是12个)。 目的是建立一个系统,以直观的方式确定(铰接式或非铰接式)尸体的姿态,而无需维护和行走复杂的层次结构。

第一个明显的简化是通过选择一个点并从相应的“开始”点减去“目的地”来消除平移部分。现在我们只需要处理轮换。

有一个众所周知的,计算上廉价的构造四元数的解决方案,它将一个向量旋转到另一个向量,即q(cross(v1,v2); sqrt(v1.len_sq * v2.len_sq)+ dot(v1,v2) ))或q(交叉(v1,v2); 1 +点(v1,v2))用于单位长度矢量。不幸的是,这种方法没有“向上方向”的概念,因此总是在最短的弧上旋转(这将使对象不对齐)。 天真的做法是简单地将这种方法用于两个向量并将四元数相乘,但显然不会那么容易。 需要做的是选择两个向量中的一个(让我们称之为“向前”),并为此创建一个四元数,然后使用此四元数旋转另一个(“向上”)向量,然后构造第二个四元数对于旋转的“向上”向量(和目标“向上”向量),最后将第二个乘以第一个四元数。据我所知,这是正确的,但它也可怕复杂。

现在......至于旋转矩阵,我知道“三元组方法”,我理解如下: - 对矢量对进行正交化(开始和结束) - 这导致两个正交基,它们是从“公共参考系”开始和结束的相应旋转矩阵。这究竟是什么参考框架并不重要,重要的是两者都是相同的。 - S是从“公共帧”到起始帧的变换,D是到结束帧的变换。 - 因此,S -1 * D * v转换从开始到结束坐标系的任何点(通过公共参考系)。 - S -1 == S T 因为它是一个正交矩阵,S T * x = x * S - 因此:S T * D * v = D * S * v

这应该可行,但对于实际上应该非常非常简单的事情来说,它似乎仍然很复杂。

是否有更简单,更直接的解决方案?

3 个答案:

答案 0 :(得分:2)

你的“非常复杂”的四元数解决方案通常不会起作用。您必须在与第一个旋转轴正交的平面上投影第二对矢量,以确保第二个旋转与第一个旋转正交。

如果您有兴趣,我已经在我的博客中描述了这个原则:http://robokitchen.tumblr.com/post/67060392720/finding-a-rotation-quaternion-from-two-pairs-of-vectors

旋转前:u0,v0。轮换后:u2,v2。

Quaternion q2 = Quaternion::fromTwoVectors(u0, u2);
Vector v1 = v2.rotate(q2.conjugate());
Vector v0_proj = v0.projectPlane(u0);
Vector v1_proj = v1.projectPlane(u0);
Quaternion q1 = Quaternion::fromTwoVectors(v0_proj, v1_proj);
return (q2 * q1).normalized();

我不确定这是你想要的解决方案,但代码运行得非常快。

答案 1 :(得分:1)

只处理旋转部件,你的第二种方法会起作用,我怀疑它会很好用。或者,您可以使用两种方法的混合,这可能会更容易一些。假设你在上面构造的两对矢量,每对在它自己的向量空间中。计算每对的正交基,并在一个向量空间中将它们称为X 0 和X 1 ,并将它们对应的向量Y 0 和Y <另一个向量空间中的sub> 1 。您现在必须计算两个四元数旋转:

1)q 0 旋转X 0 ,X 1 旋转X' 0 和X'< sub> 1 分别使得X' 0 = Y 0 。 X' 1 和Y 1 现在应该与平面法线X' 0 = Y 0 共面。

2)q 1 将X' 1 旋转为X'' 1 = Y 1 。您需要做的就是计算向量之间的角度,因为您已经知道旋转向量将只是X' 1 x Y 1 = X' 0 < / sub> = Y 0

您可以计算q = q 1 * q 0 以一步完成旋转。

答案 2 :(得分:1)

我们必须解决这个完全相同的问题。我是这样做的:

调用点P和W,所以我们有P1..P3和W1..W3

在每个空间中构造三个向量,如此

A1 = P2-P1
A2 = P3-P1
A3 = A1 x A2

B1 = W2-W1
B2 = W3-W1
B3 = B1 x B2

这两对三个向量各自构成一个非正交基础,您想要找到如何在一个空间中表示笛卡尔轴(x y和z),以便在另一个空间中找到它们。为此,构造一个矩阵,使其列为上面找到的三个向量。然后反转这个矩阵,如果这个反演失败,那么非正交基不会跨越空间,问题就无法解决。

然后从倒置矩阵中拉出三列。根据非正交基(V1,V2和V3),这些列是笛卡尔坐标轴。由此我们可以重建一个正交基,它将作为从第一个空间到第二个空间的变换矩阵。

如果我们将此矩阵称为R,并将R [row,column]表示为我们的表示法,那么最终转换矩阵的行(或列,取决于您使用矩阵的方式)将是:

B1 * R[0,0] + B2* R[1,0] + B3 * R[2,0]
B1 * R[0,1] + B2* R[1,1] + B3 * R[2,1]
B1 * R[0,2] + B2* R[1,2] + B3 * R[2,2]

现在,因为在反演之前原始矩阵的一列是另外两列的交叉,所以可能优化矩阵的反演。我没有打算这样做 - 特别是因为在我们的例子中,P1..P3的三个点不会改变,因此可以缓存倒置矩阵。

这种方法的优点是,如果你有一个半体面的矩阵/向量库,它实现起来非常简单。并且它不使用角度,这总是一件好事。