Computing two vectors that are perpendicular to third vector in 3D
计算两个与第三个向量(X)垂直且彼此垂直的向量的最佳(最快)方法是什么?
这是我现在如何计算这些向量:
1 2 3 4 | // 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轴(第二列和第三列)。众所周知,所有轴必须彼此垂直。
如果
然后将向量归一化。
1 2 3 | [ 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 |
这称为向量的空空间。
如果
有一种方法可以找到一个好的HELPER(确实-准备好成为您的y_axis)。
让我们的X =(ax,ay,az)。选择2个大小更大的元素,交换它们,并取反其中之一。设置为零的第三元素(幅度最小)。此向量垂直于X。
示例:
如果(ax <= ay)和(ax <= az)然后HELPER =(0,-az,ay)(或(0,az,-ay))
X * HELPER = 0 * 0-ay * az az * ay = 0
如果(ay <= ax)和(ay <= az)然后HELPER =(az,0,-ay)
这是执行此操作的方法。
这也可能是唯一的方法。任何其他方式在数学上都是等效的。
通过打开crossProduct计算并确保您多次进行相同的乘法运算,可以节省几个周期,但这确实与微优化领域相去甚远。
您应该注意的一件事当然是HELPER向量。它不仅不必与X平行,而且还很不错,它与X绝对不平行。如果X和HELPER甚至在某种程度上平行,则您的浮点计算将是不稳定且不准确。您可以测试一下,看看X和HELPER的点积是否为0.9999。
为获得良好的HELPER向量:找到具有最小绝对值的X坐标,并使用该坐标轴:
1 2 3 4 5 6 7 8 9 10 11 12 | 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的答案非常相似:取具有最小坐标轴的叉积等于将最小坐标设置为零,交换大的两个坐标,然后取一个负的坐标。
我认为单位向量中所有元素的最小最大魔方总是大于0.577,因此您可以逃避此操作:
->通过查找魔方大于例如0.5的任何元素,然后忽略其他元素(在其位置使用0)并将其垂直应用于,将找到3D向量和2D向量的垂直向量的问题减少。其余元素中的2D矢量公式(对于2D x轴=(ax,ay)-> y轴=(-ay,ax))
1 2 3 4 5 6 7 8 9 10 11 | 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") } |