Plocal =(Pworld - PA)* OAT
同样使用,前向变换来转换方向向量
Dworld = Dlocal * OA
Dworld * OAT = Dlocal * OA * OAT Dlocal = Dworld * OAT
同样方向
Oworld = Olocal * OA
Oworld * OAT= Olocal * OA * OAT Olocal = Oworld * OAT
现在我们将物体B的位置转化到A的局部坐标空间中
PB’ =(PB - PA)* OAT DB’ =(DB - DA)* OAT OB’ =(OB)* OAT
同样,当我们测试分离轴时,需要注意的是我们还在局部坐标中,并且需要将分离轴从B的局部坐标中转换到A的局部坐标空间中。并且为了计算物体B的局部间隔,使用转化到物体A的局部坐标空间的轴,我们需要将其反向转化到B的坐标空间中。
这些会使你觉得迷惑,另一个解决方案基本上不会被局部坐标所迷惑,即所有的操作都在全局坐标中完成。这个方法的确定就是你不得不保持一个多边形的副本,因为每一个多边形需要分别在世界坐标中计算一次。好处是你不需要再每次处理碰撞
的时候重新计算变换。这个对2D游戏来数是非常好的,但是在3D中,你不会想在每一帧中变换一次物体仅仅为了碰撞检测的目的,尤其是当物体存储在树中并有一个非常复杂的形状的时候。
六、计算触点
为了动态的移动刚体,我们需要精确计算两个碰撞多边形之间的触点。对于2D来说这并不复杂,但是在3D场景中会变得非常复杂。在2D情况下,可以考虑两种情况,点和边的相交或者是边和边的相交。
这个处理过程几乎不需要教程,但是它非常适合于一个可视化的演示
这里,我只考虑交叠的情况,这个原理也适用于碰撞的情况。 现在给出一个碰撞的法向,在点边接触的情况下,如何求得触点?
对于接触点A,它是直接向前的。我们需要调用一个支撑映射函数,他将返回多边形在制定方向上的最低点,非常类似于第一个例子中的CalculateInterval()函数
int FindSupportPoints(const Vector& N,float t, const Vector* A, intAnum, const Vector& PA,const Vector& VA, constMatrix& OA, Vector* S) {
Vector Norm = N ^ OA; float d[32]; float dmin;
dmin = d[0]= A[0]* Norm;
for(int i =1; i < Anum; i ++) {
d[i]= A[i]* Norm; if(d[i]< dmin) {
dmin = d[i]; } }
int Snum =0;
constfloat threshold =1.0E-3f; for(int i =0; i < Anum; i ++) {
if(d[i]< dmin + threshold) {
S[Snum++]= Transform(A[i], if(Snum ==2)
return Snum; } }
return Snum;
}
, VA,, t); PA OA这里,函数的第一部分找到多边形的最小值。第二部分简单的找到接近最小值的所有点,因此如果碰撞法线垂直于一条边,将返回两个点。这两个点将以世界坐标存贮,变换函数将确保多边形的触点被转化为世界坐标,并且如果是一个未来的碰撞,这个点将被转化为碰撞时刻的
Vector Transform(const Vector& Vertex,const Vector& P,const Vector& V, constMatrix& xOrient,float t) {
// 转换点到世界空间
Vector T = P +(Vertex * xOrient); // 在与时间的碰撞,需要转化为瞬间的碰撞 if(t >0.0f)
T += V * t; return T;
}
对于B上的点,你只需要简单地在反方向找到一个支撑点,在以后的处理中我们需要一对位于两个物体上的支撑点来做物理模拟推力并使物体旋转,你可以从上图中发现在不同的碰撞情况下你需要得到的一对触点。
现在,调用FindSupportPoint()函数在每个物体上返回一个或两个触点。在一对一触点的情况下,不需要做任何事情,现在,还不支持一对一的接触,但是它能够非常容易的扩展到分离轴算法中。
在一对二接触的情况下,它是一个简单的点对边的碰撞,如上图中的第一个图
在二对一接触的情况下,可以同样运用上述情况,除了物体被交换外 在二对二接触的情况下,他是一个边边碰撞,你需要找到两个边的交叠区域。
首先对于点边碰撞,在这种情况下,一对碰撞点可以简单的通过将A上的碰撞点投影到B的边上来实现,或者说是B的边上最接近A触点的点
Vector FindClosestPoint(const Vector& V,const Vector& A,const Vector& B,
float* pt)
{
Vector AV = V - A; Vector AB = B - A;
float t =(AV * AB)/(AB * AB); if(t <0.0f) t =0.0f; else
if(t >1.0f) t =1.0f; if(pt)*pt = t;
Vector P = A + t * AB; return P;
}
在边对边碰撞的情况下,处理过程非常类似。只是你需要沿着沿着碰撞法线的垂直方向排序点,并得到两个中间点。然后,将它们投影到另外的边上以便得到一对触点。