在线上找一点
要获得 2 个平面的交点,您需要在线上的一个点以及该线的方向。
找到那条线的方向真的很容易,只需穿过相交的 2 个平面的 2 个法线即可。
lineDir = n1 × n2
但是那条线穿过原点,沿着你的平面交叉点延伸的线可能不会。因此,Martinho's 的回答为在相交线上找到一个点(基本上是两个平面上的任何点)提供了一个很好的开始。
如果您想了解如何解决这个问题的推导,这里是它背后的数学:
首先让 x=0。现在我们在 2 个方程中有 2 个未知数,而不是在 2 个方程中有 3 个未知数(我们任意选择了一个未知数)。
那么平面方程是(由于我们选择 x=0,所以消除了 A 项):
B1y + C1z + D1 = 0
B2y + C2z + D2 = 0
我们希望 y 和 z 使得对于给定的 B1、C1,这些方程都能正确求解 (=0)。
所以,只需将顶部 eq 乘以 (-B2/B1) 即可得到
-B2y + (-B2/B1)*C1z + ( -B2/B1)*D1 = 0
B2y + C2z + D2 = 0
添加等式得到
z = ( (-B2/B1)*D1 - D2 ) / (C2 * B2/B1)*C1)
现在将您找到的 z 放入第一个等式中以找到 y
y = (-D1 - C1z) / B1
注意 best 变量使 0 是具有 最低 系数的变量,因为它无论如何都不携带任何信息。因此,如果 C1 和 C2 都为 0,则选择 z=0(而不是 x=0)会是更好的选择。
如果 B1=0(这不太可能),上述解决方案仍然会出错。您可以添加一些 if 语句来检查 B1=0,如果是,请务必改为求解其他变量之一。
使用 3 个平面相交的解决方案
来自user's的回答,3个平面相交的封闭形式解决方案实际上在Graphics Gems 1中。公式为:
P_intersection = (( point_on1 • n1 )( n2 × n3 ) + ( point_on2 • n2 )( n3 × n1 ) + ( point_on3 • n3 )( n1 × n2 )) / det(n1,n2,n3)
实际上point_on1 • n1 = -d1(假设你写你的平面Ax + By + Cz + D=0,而不是=-D)。因此,您可以将其重写为:
P_intersection = (( -d1 )( n2 × n3 ) + ( -d2 )( n3 × n1 ) + ( -d3 )( n1 × n2 )) / det(n1,n2,n3)
一个与 3 个平面相交的函数:
// Intersection of 3 planes, Graphics Gems 1 pg 305
static Vector3f getIntersection( const Plane& plane1, const Plane& plane2, const Plane& plane3 )
{
float det = Matrix3f::det( plane1.normal, plane2.normal, plane3.normal ) ;
// If the determinant is 0, that means parallel planes, no intn.
if( det == 0.f ) return 0 ; //could return inf or whatever
return ( plane2.normal.cross( plane3.normal )*-plane1.d +
plane3.normal.cross( plane1.normal )*-plane2.d +
plane1.normal.cross( plane2.normal )*-plane3.d ) / det ;
}
证明它有效(黄点是 rgb 平面的交点)
获取线路
一旦你有了两个平面的共同交点,这条线就可以了
P + t*d
其中P是交点,t可以从(-inf, inf)出发,d是方向向量,是两个原始平面法线的叉积。
红色和蓝色平面的交线如下所示
高效稳定
据我统计,“稳健”(第二种方式)需要 48 个基本操作,而第一种方式(x,y 的隔离)使用 36 个基本操作。这两种方式之间需要在稳定性和 # 计算之间进行权衡。
在 B1 为 0 并且您没有检查的情况下,从第一种方式的调用中返回 (0,inf,inf) 将是非常灾难性的。因此,添加if 语句并确保第一种方式不除以0 可能会以代码膨胀和添加的分支(这可能非常昂贵)为代价来为您提供稳定性。 3 平面相交法几乎是无分支的,不会给你无穷大。