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

C++ 如何为球形物体和三角形地形提供有效的碰撞检测和响应?,c++,collision-detection,computational-geometry,glm-math,C++,Collision Detection,Computational Geometry,Glm Math,我一直在尝试在物体和地形之间进行有效的碰撞检测。对象由移动球体表示,地形由静态三角形组成。 到目前为止,我成功地实现了一个冲突算法,但它存在一些主要问题: 1.这非常耗费资源。 2.碰撞仅适用于三角形的一侧。 3.多个同时发生的碰撞会产生不好的结果。 下面是我的算法。它基于的一篇文章,它使用的是GLM数学库。我简化了循环、变量名、不必要的代码和类成员: //Class definitions: class Sphere { public: float x; fl

我一直在尝试在物体和地形之间进行有效的碰撞检测。对象由移动球体表示,地形由静态三角形组成。
到目前为止,我成功地实现了一个冲突算法,但它存在一些主要问题:
1.这非常耗费资源。
2.碰撞仅适用于三角形的一侧。
3.多个同时发生的碰撞会产生不好的结果。
下面是我的算法。它基于的一篇文章,它使用的是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;
};
使用名称空间glm;
球形Obj;
三角墙;
//假设上面的两个对象是构造的。我没有包括他们的施工人员,因为他们看起来很丑。
浮动rr=对象半径;
vec3a=vec3(Wall.x[0],Wall.y[0],Wall.z[0])-vec3(Obj.x,Obj.y,Obj.z);
vec3b=vec3(Wall.x[1],Wall.y[1],Wall.z[1])-vec3(Obj.x,Obj.y,Obj.z);
vec3c=vec3(Wall.x[2],Wall.y[2],Wall.z[2])-vec3(Obj.x,Obj.y,Obj.z);
vec3 V=交叉(B-A,C-A);
浮动d=点(A,V);
浮点数e=点(V,V);
浮点数di=d;
浮动ei=e;
vec3人工智能;
vec3-Bi;
vec3ci;
vec3-Vi;
如果(!(di*di>rr*ei))
{
浮点数aa=点(A,A);
浮动ab=点(A,B);
浮点数ac=点(A,C);
浮动bb=点(B,B);
浮点数bc=点(B,C);
浮点数cc=点(C,C);
如果(!(aa>rr&&ab>aa&&ac>aa))
如果(!(bb>rr&ab>bb&bc>bb))
如果(!(cc>rr&ac>cc&bc>cc))
{
vec3ab=B-A;
vec3bc=C-B;
vec3ca=A-C;
浮点数d1=ab-aa;
浮点数d2=bc-bb;
浮点数d3=交流cc;
浮点数e1=点(AB,AB);
浮动e2=点(BC,BC);
浮动e3=点(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;
如果(!(圆点(Q1,Q1)>rr*e1*e1和圆点(Q1,QC)>0)
如果(!(dot(Q2,Q2)>rr*e2*e2和dot(Q2,QA)>0)
如果(!(dot(Q3,Q3)>rr*e3*e3和dot(Q3,QB)>0)
{
vec3 ObjectMov=vec3(Obj.xmov、Obj.ymov、Obj.zmov);

如果(dot(ObjectMov,Wall.Normal)假设您称之为“资源消耗”的运行时间太长,则三角形的数量必须非常大。因此,首先要做的是减少要测试的三角形的数量

您提到了oct树。更一般地说,边界体积的层次结构是一种方法。(.)对于百万个三角形来说,加速将是巨大的。在您的特定情况下,我可能会选择边界球体的二叉树


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


关于球体和三角形之间的精确相交测试,恐怕没有免费的午餐。使用“充气/放气”方法,球体的中心可以位于三角形上方的右棱柱、围绕边缘的三个截断圆柱体中的一个或围绕顶点的三个球体中的一个内


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

当你一开始说“三角形地形”时,我以为你的意思是你有一个高度图,并将多边形作为三角形进行管理。这就是你的“三角形墙”的本质吗等于?如果它们相等,我认为通过将其作为高度值网格进行跟踪,可以获得更好的性能。此外,这将允许您对球体相对于地形的位置进行某些假设。不,三角形墙只是定义一个带法线的三角形,然后在算法中使用。I还没有实现高度贴图,但听起来是个好主意。@LoduwijkLike这个伪代码
y0=(int)(sphere.y-sphere.radius);y1=(int)(sphere.y+sphere.radius)+1;对于x0/x1/z0/z1也是这样;对于(y=y0到y1)对于(x=x0到x1)如果(z0)这不是一个精确的检查。这只是一个粗略的初始检查,看看您是否需要仔细检查。这是碰撞检测中有时会做的事情,尽管您可能已经意识到了这一点。@Loduwijk是的。我已经有了一个更广泛的阶段,我没有在示例代码中包括,因为它看起来很难看。Bas从逻辑上讲,整个空间被划分为30×30×30个单元,这些单元存储每个地形块和对象的ID,并且只有来自相同或相邻单元的对象/地形被放入更接近的碰撞阶段。但是,它仍然非常滞后。它占用了相当多的内存,因此我将尝试实现高度贴图。我已经部分实现了“我会检查三角形的边界球。但是我会检查平方距离是否小于半径的平方和,以避免平方根。@约翰:不用说。但是在选择了有效的算法之后,进行了微优化。结果表明,主要的延迟源于渲染对象的模型。我运行了基准测试有20004个对象,没有渲染它们和10000个三角形,它的帧时间约为65毫秒。有200个渲染对象和10000个三角形,它的帧时间约为350毫秒。我应该查看着色器(可能使用较低的多边形模型…)
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];
            }
      }
}