基于两个向量创建旋转矩阵

5

当我传入一个向量(V),我希望你能帮我创建一个旋转矩阵(M),其中M * [0,0,1] (向前) = V

我之所以要这样做,是因为我希望使用这个矩阵来乘以其他向量,以将它们放置在本地空间中(不确定这是否是正确的术语,但希望您能理解)。

V = [0, 1, 0]
M = ?
Result = M * V = [0, 0, -1]

如果[0,0,1]通过乘以矩阵M后向上旋转90度变成了[0,1,0],那么这个M是什么呢?


相关问题:http://stackoverflow.com/q/15618304/380384 - John Alexiou
旋转矩阵的列对应于本地 x、y、z 轴的分量。 - John Alexiou
4个回答

5
三维旋转很难思考,更难以文字解释。但是,你可以把左手变成类似于三维坐标轴的形状。看看下面这个维基百科页面,它描述了弗莱明左手法则;特别是看第二张图,指出了手指的标签为 I、B 和 F:http://en.wikipedia.org/wiki/Fleming's_left-hand_rule_for_motors 用自己的手做同样的动作,不要给手指标上 I、B 和 F 的标签,让我们称它们为 x、y 和 z。而且,我们会说这三个手指在手掌相遇的地方是原点,即点 (0 0 0),向这些手指/拇指的指尖移动是正方向。
向量 v = (0 1 0) 是沿着您的食指(我们称其为 y)的一个点。我们想将此点旋转以形成点 (0 0 -1)。这个点位于 z 轴(拇指),但是它是负数,所以它位于原点的"下方"一单位,朝向从拇指尖端到原点的方向。
因此,为了将点 (0 1 0) 旋转为 (0 0 -1),我们需要沿着 x 轴(中指)旋转它。想象一下,在您的中指上放置一个光盘,将其推向由指数和拇指定义的平面 - (x, y) 平面 - 并在距离其中心一单位的位置上标记。现在想象将该标记与您的食指对齐,以使该标记位于点 (0 1 0)。您可以沿着中指旋转光盘,以使标记位于点 (0 0 -1)。因此,所需的旋转是绕 x 轴旋转。
下面这个维基百科页面为你提供了围绕 x、y 和 z 轴进行三维空间旋转的方程:rotations in three-dimensional space around the x, y, and z axes。绕 x 轴旋转的矩阵如下:
/1     0        0   \
|0   cos θ    -sin θ|
\0   sin θ     cos θ/

如果您使用右手旋转盘,则矩阵被定义为θ的负值对应于您的右手顺时针运动(反之亦然,正值对应逆时针运动)。我们需要旋转的角度是负四分之一圈,因此所需的矩阵如下:
/1    0     0\
|0    0     1|
\0   -1     0/

记住角度可以用度或弧度表示,因此如果您在代码中实现更通用的旋转,需要检查您的数学库期望什么。


1

我也曾经遇到过同样的问题。但是如果有人需要,我在这里找到了一种适当的方法来解决这个问题 [https://math.stackexchange.com/questions/180418/calculate-rotation-matrix-to-align-vector-a-to-vector-b-in-3d/]

以下是c++中的计算方法。

  Eigen::Vector3f a(34, 0, 1);
  Eigen::Vector3f b(2, 2, 1);
  a = a/a.norm();
  float b_norm = b.norm();
  b = b/b_norm;

  Eigen::Vector3f v = a.cross(b);
  float s = v.norm();
  float c = a.dot(b);
  Eigen::Matrix3f vx;
  vx << 0, -v[2], v[1], v[2], 0, -v[0], -v[1], v[0], 0;
  Eigen::Matrix3f r = Eigen::Matrix3f::Identity(3,3);
  if(s != 0 ){
    r = r + vx + vx*vx*((1-c)/std::pow(s, 2));
  }else{
    std::cout<< "doesn't work if a == -b"<< std::endl;
  }

  std::cout<<"Testing..."<< std::endl;
  std::cout << "b: " << b.transpose() << std::endl;
  std::cout << "After projected: b: "<< (r*a).transpose() << std::endl;

注意:如果a=-b,则会失败


1

给定本地 z-轴 V=(vx,vy,vz) 和本地 x-轴指向 U=(ux,uy,uz),其中UV单位向量:

本地 y-轴为 W=Normalized(Cross(V,U))。现在如果 U 不完全垂直于 V,则需要使用 U=Normalized(Cross(W,V)) 进行校正。

3×3 旋转矩阵为

    | Ux  Wx  Vx |
M = | Uy  Wy  Vy |
    | Uz  Wz  Vz |

请注意,Cross(A,B) = (Ay*Bz-Az*By, Az*Bx-Ax*Bz, Ax*By-Ay*Bz)是叉积运算符,Normalized(A) = (Ax,Ay,Az)/SQRT(Ax*Ax+Ay*Ay+Az*Az)创建一个单位向量。

1
即使手动,也很容易。仅通过检查,可以看到M基本上交换了y和z轴,保持x不变。
这个数组可以完成任务:
    [1  0  0]
M = [0  0  1]
    [0 -1  0]

M * [0, 1, 0] = [0, 0, -1]

请注意,这个解决方案在对那两个特定向量产生相同影响的变换矩阵集合中并不唯一。事实上,有无限多个这样的矩阵。以下是其中一个:
     [sqrt(2)/2     0    sqrt(2)/2]
M2 = [sqrt(2/2)     0   -sqrt(2)/2]
     [0            -1         0   ]

1
值得指出的是,虽然存在无限多个转换矩阵可以将向量 (0 1 0) 映射到 (0 0 -1),但并非所有这些矩阵都是旋转矩阵。此外,那些是旋转矩阵的矩阵所执行的旋转必须是绕 y 轴和 z 轴进行的整数圈自然旋转,加上绕 x 轴进行的整数圈自然旋转再加上一个四分之一圈(以适当的方向)。 - Chris

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