游戏中的数学:高等向量数学(下)

英文原文地址:Docs » Math » Advanced vector math

转载请注明出处

一些平面的例子

这是一个展示平面用途的简单例子。试想一下,你有一个凸多边形(convex polygon)。例如,矩形,梯形,三角形或者任何不包含凹陷面的多边形。

我们求得通过多边形的每一个面片的平面,以获得一个平面的列表,这时我们就可以爽歪歪了,比如我们可以一个点是否在多边形内部。

我们遍历每一个面,只要我们能找到一个平面到点的距离是正的,那么这个点就在多边形外,否则点在多边形内部。

image

示意代码如下:

var inside = true
for p in planes:
 # check if distance to plane is positive
 if (p.distance_to(point) > 0):
 inside = false
 break # with one that fails, it's enough

是不是很酷?但是这个更厉害!再稍稍努力一点,相似的逻辑,我们还可以判断两个凸多边形是否重叠。这招叫做分离轴检测法(Separating Axis Theorem 简写为SAT),大多数物理引擎用SAT进行碰撞检测。

对于一个点,我们只需检查是否有一个平面返回正距离就足以告诉我们这个点是否在平面外。对于一个多边形,我们必须找到一个平面对于另一个多边形上所有的点都返回一个正距离。这个检测先要对A的所有平面对B的所有点进行,然后再对B的所有平面对A的所有点进行:

image

示意代码如下:

var overlapping = true
​
for p in planes_of_A:
 var all_out = true
 for v in points_of_B:
 if (p.distance_to(v) < 0):
 all_out = false
 breakif (all_out):
 # a separating plane was found
 # do not continue testing
 overlapping = false
 breakif (overlapping):
 # only do this check if no separating plane
 # was found in planes of A
 for p in planes_of_B:
 var all_out = true
 for v in points_of_A:
 if (p.distance_to(v) < 0):
 all_out = false
 breakif (all_out):
 overlapping = false
 breakif (overlapping):
 print("Polygons Collided!")

如你所见,平面是非常有用的,并且这仅仅是冰山一角。你可能会好奇对于非凸多边形会怎样。对于非凸多边形(即凹多边形)一般是把它分为若干小的凸多边形,或者使用类似BSP技术(现在不常用了)。

3D碰撞检测

以下是对你耐心学习这个漫长教程的另一个奖励。这是另一种智慧。我们未必能够直接用到它(因为Godot已经很好地实现了碰撞检测)但几乎所有物理引擎和碰撞检测库都会用它:)

记住,把一个2D空间中的凸多边形转换为一个2D平面的数组对于碰撞检测是非常有用的!你可以检测一个点是否在某一个凸多边形内部,或者两个2D凸多边形是否重叠。

好的,这个方法在3D中也是有效的,如果两个3D多面体正发生碰撞,那么你不可能找到一个独立平面,如果你找到了一个独立平面,那么他们肯定没有发生碰撞。

重申一下,**独立平面(separating plane)**意味着多边形A的所有顶点在它的一侧,而多边形B的所有顶点在它的另一侧。这个平面一定是多边形A或B的某个面平面(face-plane)。

在3D中,这个方法会存在一个问题,即存在这样的可能,有时我们会无法找到一个独立平面。下面就是一个例子:

image

为了避免这种情况,我们要将一些额外的平面视为分离器,这些平面是多边形A的边于多边形B的边的叉乘。

image

最终示意代码如下:

var overlapping = true
​
for p in planes_of_A:
 var all_out = true
 for v in points_of_B:
 if (p.distance_to(v) < 0):
 all_out = false
 breakif (all_out):
 # a separating plane was found
 # do not continue testing
 overlapping = false
 breakif (overlapping):
 # only do this check if no separating plane
 # was found in planes of A
 for p in planes_of_B:
 var all_out = true
 for v in points_of_A:
 if (p.distance_to(v) < 0):
 all_out = false
 breakif (all_out):
 overlapping = false
 breakif (overlapping):
 for ea in edges_of_A:
 for eb in edges_of_B:
 var n = ea.cross(eb)
 if (n.length() == 0):
 continue
​
 var max_A = -1e20 # tiny number
 var min_A = 1e20 # huge number# we are using the dot product directly
 # so we can map a maximum and minimum range
 # for each polygon, then check if they
 # overlap.for v in points_of_A:
 var d = n.dot(v)
 max_A = max(max_A, d)
 min_A = min(min_A, d)
​
 var max_B = -1e20 # tiny number
 var min_B = 1e20 # huge numberfor v in points_of_B:
 var d = n.dot(v)
 max_B = max(max_B, d)
 min_B = min(min_B, d)if (min_A > max_B or min_B > max_A):
 # not overlapping!
 overlapping = false
 breakif (not overlapping):
 breakif (overlapping):
  print("Polygons collided!")

猜你喜欢

转载自blog.csdn.net/hello_tute/article/details/107856078