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



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

//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];
}
}
}

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

假设您所说的"资源消耗"的运行时间太高,那么三角形的数量一定很大。因此,首先要做的是减少要测试的三角形的数量。

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


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


关于球体和三角形之间的精确相交测试,恐怕没有免费的午餐。使用"膨胀/收缩"方法,球体的中心可以位于三角形上方的右棱柱内,也可以位于边缘周围的三个截头圆柱体中的一个,或者位于顶点附近的三个球体之一。

无论你采取什么方法,你都必须处理案例分析的复杂性。

最新更新