我想知道两个3D凸包(A
与B
)之间碰撞位置的大约3D位置和 3D法线。
括号中的CPU显示了我完成的程序所需的相对CPU时间。
第一步,我使用一种非常便宜的算法-separation axis theorem。
例如,我将15 axis用于2个多维数据集。 (在实际情况下,形状会更复杂。)
如果至少有1个可分离的轴,则return "no-collide"
。
否则,请执行下一部分。
A
的每个顶点-是否在B
内。 B
的每个顶点-是否在A
内。 有一个奇怪的情况,例如https://gamedev.stackexchange.com/questions/75437/collision-detection-3d-rectangles-using-sat。我从那里偷了图像:-
因此,我还需要 edge 和 edge 。
A
的边上找到最接近B
边的点。检查顶点是否在B
内部。 A
内部。 哇,这是很多计算。
但是,还没有结束。
报告的碰撞位置不太准确(左:当前,右:希望):-
为解决这个问题,我考虑过要生成一个新的凸形= A intersect B
。
有一些免费的C ++库(例如OpenMesh),但我认为它过于占用CPU资源。
请注意,我不需要准确无误。
有时它还会报告错误的正常信息(左:当前,右:希望):-
^通过添加(A)的 edge 和B的 face 可以解决此问题,但这会使整个碰撞检测更加昂贵。
看起来(从中复制)互联网上的常见算法只能识别微特征。
恕我直言,顶点体积/边缘算法专注于拓扑结构,而不是两个形状都是 solid 体积的事实。
哪种算法更准确(第一优先)并且可能更便宜?
我的方法在基础级别上可能是错误的。
为了加快速度,我已经进行了一些修剪,例如仅选择一对靠近的边A和B。
参考文献:-
Algorithms for Collision Detection between Arbitrarily sized Convex Polygons仅检查是否发生碰撞。
https://pybullet.org/Bullet/BulletFull/btBoxBoxDetector_8cpp_source.html:激发Bullet Physics库中盒与盒碰撞检测的完整代码-很难理解。
https://math.stackexchange.com/questions/397413/determine-direction-of-minimum-overlap-of-convex-polygons尚未解决的数学问题,与此非常相似。
现在,我可以找到所有相交的凸点(该凸点被描绘为粉红色三角形/矩形):
这是我找到法线的方法。
对于每个分离轴(全部= 15轴),我投影该轴上的粉红色凸起。
产生最短投影距离(粉红色箭头)的轴应为法线方向。
我的上述假设通常是正确的(例如,左),但有时是错误的(例如,右)。
如何便宜地改善它?
答案 0 :(得分:1)
游戏引擎通常会模拟一系列离散步骤的时间。结果,由于相互渗透(您的情况)或事物快速移动,碰撞系统可能陷入困难的(通常是昂贵的)情况下-在步骤N中,A位于B的一侧,而完全位于B的另一侧,因此隧道发生碰撞在步骤N + 1。如果您需要处理多体接触或连续接触或非凸形,接缝或软物体,则更加困难。 kes!我们正在模拟整个世界。
您想进行“游戏物理学”并使用近似值来回购帧速率... 最后,您可以用一堆烟雾或火光掩盖很多错误。 :-)
有一类算法,明确考虑了模拟时间以帮助碰撞系统。有很多方法可以实现“连续碰撞检测”系统。您可以从这里开始,但是在提交代码之前,应该先广泛阅读。幸运的是,关于碰撞的文献很多。 这是一个很好的起点 https://docs.unity3d.com/Manual/ContinuousCollisionDetection.html https://pybullet.org/Bullet/phpBB3/viewtopic.php?t=20
这是一种建议的启发式方法,可能在您现有的系统中起作用。 这种启发式技术可能会在诸如星体3d这样的游戏中起作用,其中物体可以在太空中自由漂浮。这可能足以满足您的需求。
每个对象的图像都存储其当前状态向量(位置,方向,速度,加速度,旋转...)以及上一个时间步的先前状态向量。
假设您在时间=当前检测到对象A和B之间潜在的碰撞。
对于time = previous,假设A和B没有接触。
使用A和B的先前状态向量分别在time = prev处计算A和B的表面上的最接近点。 (closestA,closestB)。
线段(closestA,closestB)在time = previous时将具有非零长度。 您可以只使用closestB作为位置和法线,但是它会与线段的长度成比例。
通过查找A任意接近B的时间,也可以及时进行二进制搜索,并最大程度地减少错误。 在每次搜索时,将搜索时间步长减小一半。 0.5、0.25、0.125 ..直到(closestA,最近的B)的长度低于错误阈值或您放弃。
对于简单情况,这应该为您提供可接受的近似解决方案...
您还说过,您正在使用分离轴定理作为“第一检查”。如果这真的是“第一眼检查”,那对我来说确实听起来很昂贵。
最快的计算是您不需要的计算,因此快速的碰撞意味着大量的便宜的预测试并避免了昂贵的情况。
您可以考虑使用诸如粗糙的空间网格之类的空间技术,并且仅检查已经知道的彼此靠近的对象。
此外,球面测试是一种非常快速的预测试,可以查看两个凸物体的边界球是否均匀重叠。
答案 1 :(得分:0)
我会这样做:
定义
让2个三角3D凸包A,B
。它们每个都定义了中心pc
和表面点列表p0,p1,p2,...
和三角形列表t0,t1,t2,...
。每个三角形还应该计算出其法线n0,n1,n2,...
指出的位置。
计算最多的内部生命值q
因此,让我们测试A是否击中B。只需遍历所有点A.p[i]
,并记住位于B
内且最接近B.pc
的最里面的点(如果有多个)。假设您的模拟有足够小的时间步长dt
,因此插值位置不会错过命中率。如果没有,则必须使用另一种方法。
计算位移d
为此,我们需要知道相对于A
的运动方向B
。可以这样计算:
dir = (A.pc-B.pc) - (A'.pc-B'.pc)
其中A'.pc,B'.pc
是最后一次迭代的位置...这里是相对热值的图像(因为B会静止不动):
现在要计算位移,只需从q
向-dir
方向投射光线,并测试命中B
的哪个三角形。交点q'
是您要寻找的命中点。排量:
d = q'-q
您需要翻译A
以便仅触摸B
而不是相交。
由此,您可以计算反射r
,因为B
的命中三角形具有自己的法线:
所以现在只需将A
转换为r
,这样您的A
就可以在反射后找到位置(因此,在撞击过程中不会浪费时间)...也来自{{1} }大小和d
之间的相对速度,您可以估算撞击时间并通过降低速度和A,B
来增加撞击摩擦力。不要忘记也反映r
的速度。您还可以对A
进行碰撞物理。
B
和q'
还可用于在两个d
上创建旋转扭矩,但是模拟3D旋转非常困难,通常只是被欧拉角所伪造...我理解是刚体可以具有任意数量的旋转,而不仅仅是3 ...但是其中一些旋转可以组合或抵消,因此,为了模拟一个物体,需要动态列出所涉及的旋转,这将是缓慢而困难的在上面实现东西。
看看:
您可以在A,B
测试中找到我对point
的实现,甚至在convex_mesh
中也可以找到更多...在较新的版本中,我实现了更多的基元和凸面壳,但可以t将其增长到35 KB(已超过30 KB的限制)后再发布。
为加快测试速度,您还可以在每个AABB,OBB
之前为每个convex_hull
添加外切球体,并测试它们是否相交...您知道A,B线性路径之间的垂直距离必须小于convex_hull
...适用于简单的线/线最近点测试,该测试也在上面的链接中实现。