如何高效地在3D空间中找到无限线和AABB之间的最近点?
我有一个朴素的解决方案,涉及找到AABB的所有12条边到该线的最近点并选择最近的一对,这个方法是有效的,但不够快。我需要更快速的方法适用于我的使用场景。
在我的搜索过程中,我发现了很多关于查找线与AABB之间碰撞的文献以及朴素算法的几种实现方式。但是否有更好的解决方法呢?
如何高效地在3D空间中找到无限线和AABB之间的最近点?
我有一个朴素的解决方案,涉及找到AABB的所有12条边到该线的最近点并选择最近的一对,这个方法是有效的,但不够快。我需要更快速的方法适用于我的使用场景。
在我的搜索过程中,我发现了很多关于查找线与AABB之间碰撞的文献以及朴素算法的几种实现方式。但是否有更好的解决方法呢?
我的(也很天真)解决方案是选择距离AABB中心最近的线上点,并从该点向外工作,按照此处的示例进行迭代: https://math.stackexchange.com/questions/2133217/minimal-distance-to-a-cube-in-2d-and-3d-from-a-point-lying-outside
然后沿着该线迭代,直到距离不再减小(必须向每个方向扫过去)。
这将在线与面或边平行的情况下非常快,但我不知道它是否比您的天真解决方案更快,对于没有与AABB平行方面的线条。
(当然,来自数学堆栈交换的解决方案需要从伪代码适应到您选择的语言,并且在找到最短路径后,您必须计算矢量的坐标以获得您的点。)
现在,最靠近该线的边将是该顶点所属的3条边之一。
这将比您的算法快四分之一。
你的线将类似于 cv + p,其中 v 是方向向量,p 是它经过的点。
从线到你的盒子上最近点的方向将垂直于该线,因此获取一对法向量 v
,称为 n
和 m
。
实际上最接近的点将是 n
和 m
的线性组合,并带有线上的一个点。(你从线上的一个点开始,沿着某个垂直于该线的方向前往目标点,每个垂直于该线的方向都是通过该点的法向量的线性组合。)
因此解决 an + bm + cv + p = s
,其中 s
是你的盒子的每个角落。
不失一般性,我们可以假设 v
在其前两个分量中没有零。(如果有一个,则重新排列索引使其成为第三个。如果有两个,则这变成了一个更简单的问题,我们可以单独解决。)
这意味着我们可以取 n = (1, 0, N)
和 m = (0, 1, M)
。
由于 n * v = 0
和 m * v = 0
,我们可以找到 N = -v1/v3
和 M = -v2/v3
。我们不需要进行所有这些替换,只需要知道这些是数字而不是变量即可。
现在我们想要解决 an + bm + cv = s - p
。我们可以使用普通代数来完成。我们得到
c = (s3 - p3 - N(s1 - p1)- M(s2 - p2))/(v3 - N v1 - M v2)
而cv + p
则是你的线上最接近那个角落的点。
同时我们还有:
b = s2 - p2 - v2 c
a = s1 - p1 - v1 c
该直线距离您的角落的距离为|an + bm|
,因此距离的平方是
D^2 = (an + bm) * (an + bm) = (a^2 + b^2 + (aM + bM)^2)
当你看角落时,可以考虑到你有一个盒子。选择一个角落并前往邻居,然后去到把你对角线的邻居。如果这三个值中有一个比同一方向上的另外两个更远,则最近点不在通往该点的边上。这就排除了所有与该点相关的边缘。由于直线可能穿过您的盒子,因此可能不会发生这种情况。但这种情况非常不可能。
对于每对(未被排除的)构成一条边的角落,我们有一个 c 值范围xc0 +(1-x)c1
,其中x在[0,1]
表示最接近边缘的线上最接近点的范围。
相应的a和b值是:
a = s1-p1-v2(x c0 + (1-x)c1) = s1-p1-v2-(c0-c1)v2 x
b = s2-p2-v1(x c0 + (1-x)c1) = s2-p2-v1-(c0-c1)v1 x
再次强调,只要常量是已知的,我们就可以将其写成:
a = A0 + A1x
b = B0 + B1x
现在,从上面来看
D^2 = (a^2 + b^2 + (aN + bM)^2)
这样我们就可以用x的术语得到平方距离。
D^2 = (A0 + A1 x)^2 + (B0 + B1 x)^2 +
(A0 N + A1 Nx)^2 + (B0 M + B1 MX)^2
x = -(A0 A1 + B0 B2 + (NA0 A1 + MB0 B1))/
(A1^2 + B1^2 + (A1 N + B1 M)^2)
当x
在0和1之间时,你会有一个最小值或最大值。通过比较这些结果,你应该能够丢弃最大值。
如果最小值在面上而不是边缘上,那么你将有太多的符合条件的值。在这种情况下,答案显然是零——线条碰到了盒子。
x
的进一步计算>”。如果这意味着您正在运行12次最小化例程,则可能无法满足提问者比其12个边缘检查更快的要求。如果您能澄清您的答案在性能方面意味着什么,那将是很好的。 - Salmonstrikes