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

Math 从两对三点(或两对两个向量)导出轴/角度旋转,math,Math,请注意,尽管听起来很相似,但这不是常见的“如何将一个向量旋转到另一个向量”问题 我想从两组3个点导出仿射变换(矩阵或四元数+向量形式)。这些可以被视为刚体上的“标记点”,或“向前和向上”向量的端点。 需要平移和旋转,不需要缩放。此外,四元数+向量解决方案将是一个加号,因为它允许我在一个绘图批中再填充1/3个实例(8个而不是12个)。 其目的是建立一个系统,以直观的方式确定(关节或非关节)ridid身体的姿势,而无需维持和行走复杂的层次结构 第一个明显的简化是通过选取一个点并从相应的“起点”减去“

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

我想从两组3个点导出仿射变换(矩阵或四元数+向量形式)。这些可以被视为刚体上的“标记点”,或“向前和向上”向量的端点。 需要平移和旋转,不需要缩放。此外,四元数+向量解决方案将是一个加号,因为它允许我在一个绘图批中再填充1/3个实例(8个而不是12个)。 其目的是建立一个系统,以直观的方式确定(关节或非关节)ridid身体的姿势,而无需维持和行走复杂的层次结构

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

有一种众所周知的、在计算上廉价的方法来构造一个向量旋转到另一个向量的四元数,即单位长度向量的q(交叉(v1,v2);sqrt(v1.len_sq*v2.len_sq)+dot(v1,v2))或q(交叉(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

这应该是可行的,但对于一些实际上应该非常非常简单的事情来说,它仍然显得相当复杂


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

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

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

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


你可以计算q=q1*q0,在一个步骤中执行旋转。

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

调用点p和W,我们有P1..P3和W1..W3

在每个空间中构造三个向量,如下所示

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

这两对三个向量各自构成一个非正交基,您需要了解如何在一个空间中表示笛卡尔轴(xy和z),以便在另一个空间中找到它们。为此,构造一个矩阵,使其列为上述三个向量。然后将该矩阵求逆,如果该求逆失败,则非正交基不跨越空间,问题无法解决

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

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

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不会改变,所以倒矩阵可以被缓存

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

你的“极其复杂”的四元数解通常不起作用。必须将第二对向量投影到与第一个旋转轴正交的平面上,以确保第二个旋转与第一个旋转正交

如果您感兴趣,我已经在我的博客中描述了该原则:

旋转前: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();

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

我相信这是
http://math.stackexchange.com/<
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();