计算垂直于第三个向量(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 轴(第二列和第三列(。众所周知,所有轴必须彼此垂直。
我做了什么,前提是X<>0
或Y<>0
是
-
A = [-Y, X, 0]
-
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
这称为向量的零空间。
如果X=0
和Y=0
则A=[1,0,0]
,B=[0,1,0]
。
这是这样做的方法。
这也可能是唯一的方法。任何其他方式在数学上都是等价的。
通过打开 crossProduct 计算并确保您不会多次执行相同的乘法,可以节省几个周期,但这确实远远超出了微优化领域。
当然,您应该注意的一件事是 HELPER 向量。它不仅必须不与X平行,而且它与X非常不平行也是一个好主意。如果 X 和 HELPER 在某种程度上是平行的,那么你的浮点计算将是不稳定和不准确的。您可以测试并查看如果 X 和 HELPER 的点积类似于 0.9999 会发生什么。
有一种方法可以找到一个好的助手(真的 - 它已经准备好成为你的y_axis(。
让我们 X = (ax, ay, az(。选择2个幅度更大的元素,交换它们,并否定其中一个。设置为零第三元素(具有最小幅度(。此向量垂直于 X。
例:
如果 (ax <= ay( 和 (ax <= az( 则 HELPER = (0, -az, ay( (或 (0, az, -ay((
X*助手 = 0*0 - ay*az+ az*ay = 0
如果 (ay <= ax( 和 (ay <= az( 则 HELPER = (az, 0, -ay(
对于一个好的 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的答案非常相似:取具有最小坐标轴的叉积等效于将最小坐标设置为零,交换较大的两个,并取反一个。
我认为单位向量中所有元素的最小最大放大倍数总是大于 0.577,所以你可以侥幸逃脱:
-> 通过查找放大倍数大于 0.5 的任何元素,减少查找垂直向量到 3D 向量到 2D 向量的问题,然后忽略不同的元素(在其位置使用 0(并在其余元素中应用垂直于 2D 向量公式(对于 2D x 轴=(ax,ay( -> y 轴=(-ay,斧头((
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")
}