【问题标题】:Deriving axis/angle rotation from two pairs of three points (or, two pairs of two vectors)从两对三点(或两对两个向量)导出轴/角度旋转
【发布时间】:2011-06-07 21:22:45
【问题描述】:

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

我想从两组 3 个点推导出仿射变换(矩阵或四元数+向量形式)。这些可以看作是刚体上的“标记点”,或者是“向前和向上”向量的端点。 平移和旋转是必要的,缩放不是必需的。此外,四元数+矢量解决方案将是一个加号,因为它可以让我将 1/3 的实例塞进绘图批次(8 个制服而不是 12 个)。 其目的是建立一个系统,用于以直观的方式确定(铰接或未铰接的)身体的姿势,而无需维护和行走复杂的层次结构。

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

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

现在...至于旋转矩阵,我知道“三元法”,我理解如下: - 正交化向量对(开始和结束) - 这会产生两个正交基,它们是从“公共参考系”开始和结束的相应旋转矩阵。这到底是什么参考系并不重要,重要的是两者都是相同的。 - S 是从“普通帧”到起始帧的变换,D 是分别到结束帧的变换。 - 因此,S-1 * D * v 将任意点从起点坐标系变换到终点坐标系(通过公共参考系)。 - S-1 == ST 因为它是一个正交矩阵,并且 ST * x = x * S - 因此:ST * D * v = D * S * v

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

有没有更简单、更直接的解决方案?

【问题讨论】:

  • 我相信这是http://math.stackexchange.com/的一个很好的候选人

标签: math


【解决方案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 没有改变,因此可以缓存倒置矩阵。

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

【讨论】:

  • 我必须承认我仍然不能 100% 遵循,即使读了 3 遍,休息一个月,再读一遍(最后一段代码只是矩阵的一列?)。您所描述的似乎与问题中概述的“三元法”相似,只是您没有对基数进行正交归一化(这意味着您可以表示剪切和比例,但逆并不像转置那么简单)。
  • 我的解释可能不够清楚。我实际上要说的是答案就在问题中。也就是说,您想从一个基础转换到另一个基础,并且您拥有两个基础。唯一的复杂性是你的两个碱基不是正交的,对它们进行正交归一化是一种可行的方法。我个人认为在你的第一个基中计算笛卡尔轴的表示在概念上更简单,这样你就可以将它们转换为你的另一个基,但它们可能是等效的方法。
【解决方案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();

我不确定这是否是您想要的解决方案,但代码运行速度惊人。

【讨论】:

  • 看起来很棒,而且看起来应该比我使用矩阵的实现要快得多。不幸的是,我没有机会在圣诞节前尝试实施和测试它。不过肯定会的。
【解决方案3】:

仅处理旋转部分,您的第二种方法将起作用,我怀疑它会起作用。或者,您可以使用这两种方法的混合,这可能会更容易一些。假设您在上面构建了两对两个向量,每一对都在自己的向量空间中。计算每一对的正交基,称它们为一个向量空间中的 X0 和 X1,以及它们对应的向量 Y0 和 Y1 在另一个向量空间中。您现在必须计算两个四元数旋转:

1) q0 旋转 X0 和 X1 到 X'0 和 X'1 分别使得 X'0 = Y0。 X'1 和 Y1 现在应该与平面法线 X'0 = Y0 共面。 p>

2) q1 将 X'1 旋转到 X''1 = Y1。您需要做的就是计算向量之间的角度,因为您已经知道旋转向量将只是 X'1 x Y1 = X'0 = Y0

您可以计算 q = q1 * q0 以一步执行旋转。

【讨论】:

  • 感谢您的回答,尽管我必须承认我不理解您的方法,即使在睡过它并再次阅读之后也是如此。但这可能只是我 :-) 它似乎在计算上并不那么密集,所以也许根本就没有明显更容易(即计算上更便宜)的方法?
  • 我在第一种方法中看到的限制是每个参考空间中的向量不是正交的。这使得计算第二旋转角度更加困难。通过首先对它们进行正交化,然后应用您描述的第一种方法,它可以简化旋转矢量的计算(它只是 +/-Y0)并使旋转角度的计算更容易(只是内积的 cos^-1) .不确定它是否会比其他两种方法中的任何一种表现更好(它们都是恒定时间)......这就是分析的目的。
  • 另一个想法:如果一个人建立两个正交基并使用第一个来“取消旋转”第二个会怎么样。然后,只需在未旋转的第二个碱基上进行矩阵到四元数的转换。这并不便宜(2 个正交归一化、一个矩阵乘法、一个水平加法和几个平方根),但它仍然是合理的......并且可能比其他两种方法便宜。而且,它输出一个四元数,所以只有 4 个浮点数 4 个值,这很好。你的想法?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-12
  • 1970-01-01
  • 1970-01-01
  • 2019-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多