【问题标题】:Computing two vectors that are perpendicular to third vector in 3D计算垂直于 3D 中第三个向量的两个向量
【发布时间】:2012-05-28 22:45:13
【问题描述】:

计算垂直于第三个向量 (X) 并且彼此垂直的两个向量的最佳(最快)方法是什么?

这就是我现在计算这些向量的方式:

// HELPER - unit vector that is NOT parallel to X
x_axis = normalize(X);
y_axis = crossProduct(x_axis, HELPER);
z_axis = crossProduct(x_axis, y_axis);

我知道对此有无数种解决方案,我不在乎哪一种会是我的解决方案。

这个问题的背后是什么:我需要构建变换矩阵,我知道 X 轴(矩阵中的第一列)应该指向哪个方向。我需要计算 Y 轴和 Z 轴(第二列和第三列)。众所周知,所有轴都必须相互垂直。

【问题讨论】:

  • here 的算法有你需要的吗?他们关注以稳健有效的方式生成 y_axis。
  • 这是一个几乎相同的问题:[stackoverflow.com/questions/19649452/… 使用一个正交向量,只需叉积即可产生第二个。

标签: math vector 3d


【解决方案1】:

我做了什么,前提是X<>0或Y<>0是

  1. A = [-Y, X, 0]
  2. B = [-X*Z, -Y*Z, X*X+Y*Y]

然后对向量进行归一化。

[ X,Y,Z]·[-Y,X,0] = -X*Y+Y*X = 0
[ X,Y,Z]·[-X*Z,-Y*Z,X*X+Y*Y] = -X*X*Z-Y*Y*Z+Z*(X*X+Y*Y) = 0
[-Y,X,0]·[-X*Z,-Y*Z,X*X+Y*Y] = Y*X*Z+X*Y*Z = 0

这称为向量的 nullspace。

如果X=0 和Y=0 则A=[1,0,0]、B=[0,1,0]。

【讨论】:

  • 引入了另一种数学精确但数值不稳定的计算。
  • 请解释“不稳定”。如果失败,您能否提供一个(非零)示例?
  • 例如,如果 X 和 Y 的大小不同,则对它们进行平方往往会产生虽然代数正确但数值不正确的结果。当 Y 与 X 相比足够大时,XX + YY 减少为 Y*Y。
  • 输入向量根据 OP 进行归一化,因此最坏的情况是 [1, ε, 0],其中 ε 是机器精度。结果将是[-ε,1,0] 和[0,0,1],它们仍然是nullspace。我真的一点也不明白你的意思(在这种情况下)。
  • 您可能认为[ε,ε,1] 案例失败了,但是当结果在最后一步标准化时,它可以正常工作。不要伪造现代计算机在内部使用 80 位浮点数进行计算,但最终只显示 32 或 64 位。
【解决方案2】:

这就是这样做的方法。
这也可能是唯一的方法。任何其他方式在数学上都是等效的。
通过打开 crossProduct 计算并确保您不会多次执行相同的乘法运算,可以节省几个周期,但这对于微优化领域来说真的很遥远。

您应该注意的一件事当然是 HELPER 向量。它不仅必须与 X 不平行,而且它与 X 非常不平行也是一个好主意。如果 X 和 HELPER 甚至有点平行,那么您的浮点计算将不稳定且不准确.您可以测试一下,如果 X 和 HELPER 的点积为 0.9999 左右会发生什么。

【讨论】:

  • 感谢您的回复。是的,HELPER 远不能与 X 平行。我正在为 android 平台开发,我希望有一些技巧来计算至少第一个并行向量更便宜一些。我会给这个问题一些时间,如果没有更好的答案,我会接受这个作为答案。
  • 没有。这不是唯一的方法,也不一定是最好的方法,这取决于 HELPER 的价值。
【解决方案3】:

有一种方法可以找到一个好的 HELPER(真的 - 它已准备好成为您的 y_axis)。

让我们 X = (ax, ay, az)。选择2个量级较大的元素,交换它们,取反其中一个。将第三个元素设置为零(幅度最小)。这个向量垂直于 X。

例子:

如果 (ax

X*HELPER = 0*0 - ay*az + az*ay = 0

如果 (ay

【讨论】:

    【解决方案4】:

    对于一个好的 HELPER 向量:找到具有 最小绝对值的 X 坐标,并使用该坐标轴:

    absX = abs(X.x); absY = abs(X.y); absZ = abs(X.z);
    if(absX < absY) {
      if(absZ < absX)
        HELPER = vector(0,0,1);
      else // absX <= absZ
        HELPER = vector(1,0,0);
    } else { // absY <= absX
      if(absZ < absY)
        HELPER = vector(0,0,1);
      else // absY <= absZ
        HELPER = vector(0,1,0);
    }
    

    注意:这实际上与@MBo 的答案非常相似:取坐标轴最小的叉积相当于将最小坐标设置为零,交换较大的两个,然后取反。

    【讨论】:

      【解决方案5】:

      我认为单位向量中所有元素的最小最大幅度总是大于 0.577,所以你也许可以摆脱这个:

      -> 通过找到幅度大于 0.5 的任何元素,然后忽略不同的元素(在其位置使用 0)并将垂直线应用于剩余元素中的 2D 向量公式(对于 2D x-axis=(ax,ay) -> y-axis=(-ay,ax))

      let x-axis be represented by (ax,ay,az)
      
      if (abs(ay) > 0.5) {
        y-axis = normalize((-ay,ax,0))
      } else if (abs(az) > 0.5) {
        y-axis = normalize((0,-az,ay))
      } else if (abs(ax) > 0.5) {
        y-axis = normalize((az,0,-ax))
      } else {
        error("Impossible unit vector")
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-29
        • 1970-01-01
        • 2020-07-17
        • 2023-02-13
        • 2023-04-01
        • 2017-06-18
        相关资源
        最近更新 更多