如何为球形物体和三角形地形提供高效的碰撞检测和响应?

How to provide efficient collision detection and response for spherical objects and triangular terrain?

我一直在尝试在物体和地形之间进行有效的碰撞检测。对象由移动球体表示,地形由静态三角形组成。
到目前为止,我成功地实现了一个碰撞算法,但它有一些主要问题:
1. 非常耗资源
2.碰撞只对三角形的一侧有效
3. 多次同时碰撞会产生不良结果。
下面是我的算法。它基于 realtimecollisiondetection.net 的一篇文章,并且使用了 GLM 数学库。我简化了循环、变量名、不必要的代码和 class 成员:

//Class definitions:  
class Sphere
{
     public:
     float x;
     float y;
     float z;
     float radius;
     float sqradius;
     float xmov;
     float ymov;
     float zmov;
};
class TriangularWall
{
     public:
     float x[3];
     float y[3];
     float z[3];
     glm::vec3 Normal;
};
using namespace glm; 
Sphere Obj;
TriangularWall Wall;
//Assume that the 2 objects above are constructed. I didn't include their constructors because they looked ugly. 
float rr=Obj.sqradius;  
vec3 A=vec3(Wall.x[0], Wall.y[0], Wall.z[0])-vec3(Obj.x, Obj.y, Obj.z);  
vec3 B=vec3(Wall.x[1], Wall.y[1], Wall.z[1])-vec3(Obj.x, Obj.y, Obj.z);
vec3 C=vec3(Wall.x[2], Wall.y[2], Wall.z[2])-vec3(Obj.x, Obj.y, Obj.z);  
vec3 V=cross(B-A, C-A);  
float d=dot(A, V);  
float e=dot(V, V);  
float di=d;  
float ei=e;
vec3 Ai;
vec3 Bi;
vec3 Ci;
vec3 Vi;
if(!(di*di>rr*ei))
{
      float aa=dot(A, A);
      float ab=dot(A, B);
      float ac=dot(A, C);
      float bb=dot(B, B);
      float bc=dot(B, C);
      float cc=dot(C, C);
      if(!(aa>rr && ab>aa && ac>aa))
      if(!(bb>rr && ab>bb && bc>bb))
      if(!(cc>rr && ac>cc && bc>cc))
      {
            vec3 AB=B-A;
            vec3 BC=C-B;
            vec3 CA=A-C;
            float d1=ab-aa;
            float d2=bc-bb;
            float d3=ac-cc;
            float e1=dot(AB, AB);
            float e2=dot(BC, BC);
            float e3=dot(CA, CA);
            vec3 Q1=A*e1-d1*AB;
            vec3 Q2=B*e2-d2*BC;
            vec3 Q3=C*e3-d3*CA;
            vec3 QC=C*e1-Q1;
            vec3 QA=A*e2-Q2;
            vec3 QB=B*e3-Q3;
            if(!(dot(Q1, Q1)>rr*e1*e1 && dot(Q1, QC)>0)
            if(!(dot(Q2, Q2)>rr*e2*e2 && dot(Q2, QA)>0)
            if(!(dot(Q3, Q3)>rr*e3*e3 && dot(Q3, QB)>0)
            {
                  vec3 ObjectMov=vec3(Obj.xmov, Obj.ymov, Obj.zmov);
                  if(dot(ObjectMov, Wall.Normal)<0)
                  ObjectMov-=dot(ObjectMov, Wall.Normal);
                  Obj.xmov=ObjectMov [0];
                  Obj.ymov=ObjectMov [1];
                  Obj.zmov=ObjectMov [2];
            }
      }
}

对于第三期,我重新做了上面的算法(如果仍然发生碰撞,只需将物体停在相应的轴上)。但是,这会显着加载程序,并且不会产生很好的效果。
我也知道我可以对上面的算法进行一些性能调整,但我没有看到任何可以显着提高性能的东西。
我知道我也可以使用八叉树,但是它们对我来说似乎很复杂,而且我也担心它们在某些情况下会造成很多延迟。
因此,有什么方法可以改进我使用的算法以解决其主要问题吗?或者我应该尝试使用另一个?

假设你所说的"resource consuming"太高了运行-时间,那么三角形的数量肯定是很大的。所以首先要做的是减少要测试的三角形的数量。

你提到了八叉树。更一般地说,边界体积的层次结构是可行的方法。 (https://en.wikipedia.org/wiki/Bounding_volume_hierarchy.)百万个三角形的加速将是巨大的。在您的特定情况下,我可能会选择边界球的二叉树。


注意,在实现这个之前,你已经通过预先计算每个三角形的边界球来获得加速(球的中心是外接圆的中心,即中介平面与平面的交点三角形)。然后通过比较中心之间的距离与半径之和来检测非相交三角形。


关于球体与三角形的精确交集测试,恐怕天下没有免费的午餐。使用 "inflating/deflating" 方法,球体的中心可以位于三角形上方的直棱柱内、边缘周围的三个截短圆柱体之一或顶点周围的三个球体之一。

无论采用何种方法,您都必须处理案例分析的复杂性。