基于2D多边形的碰撞检测和响应(三)

三、对快速移动的物体做进一步扩展
上述方法处理慢速移动物体时会取得非常好的效果。但是当物体移动的非常快时,碰撞系统将失去准确性,丢失碰撞,或者允许物体之间相互穿越,这可不是我们所期望的。
 
这里我们还是使用分离坐标轴的方法,并进一步扩展,并使用该算法检测未来某时刻的碰撞和交叠。
 
原理还是相同的,可以使用下面的图片解释:

现在需要使用投影数学。如果投影间隔没有相交,将速度投影到分离轴上,并计算两个间隔的碰撞时间。
 
相对于静态分离轴算法,我们需要测试一个扩展的轴。显然这个是速度矢量轴。
 
那么我们现在有3个选择:
1.  间隔交叠
2.  间隔不相交,但是将在未来某个时刻发生碰撞
3.  间隔不相交,并且不会在未来发生碰撞
第三种可能性意味着物体不会在该帧处发生碰撞,而且分离轴真正分离了物体。因此物体不会发生碰撞。
 
AxisSeparatePolygons()函数将反映这种现象,并返回重叠量或者碰撞时间。为了区别两者,当检测到交叠时,将返回一个负值。如果检测到未来的碰撞,将返回一个正值。该函数看起来如下:
 

bool AxisSeparatePolygons(Vector Axis, Polygon A, Polygon B, Vector Offset, Vector Vel, float& t, float tmax);

这里Offset是多边形A和多边形B之间的相对距离,并且Vel是多边形A相对于多边形B的相对速度。
 
求解碰撞平面的算法与MTD非常相似。只是碰撞将优于交叠,如果检测到未来的碰撞,将选择最新的一个。
 
如果没有发现碰撞并且只检测到了交叠,那么就像以前一样,选择交叠最小的那个轴。
 
碰撞检测函数将返回碰撞的法向,还有碰撞的深度(负值)和碰撞时间(正值)之一。最后的伪代码如下…
 

bool Collide(   const Vector* A, int Anum,
                const Vector* B, int Bnum,
                const Vector& xOffset, const Vector& xVel,
                Vector& N, float& t)
{
    if (!A || !B) return false;
      
    // All the separation axes
    // note : a maximum of 32 vertices per poly is supported
    Vector xAxis[64];
    float taxis[64];
    int iNumAxes=0;

    xAxis[iNumAxes] = Vector(-xVel.y, xVel.x);
    float fVel2 = xVel * xVel;
    if (fVel2 > 0.00001f)
    {
        if (!IntervalIntersect( A, Anum, B, Bnum, xAxis[iNumAxes], xOffset, xVel, taxis[iNumAxes], t))
            return false;
        iNumAxes++;
    }

    // test separation axes of A
    for(int j = Anum-1, i = 0; i < Anum; j = i, i ++)
    {
        Vector E0 = A[j];
        Vector E1 = A[i];
        Vector E = E1 - E0;
        xAxis[iNumAxes] = Vector(-E.y, E.x);
       
        if (!IntervalIntersect( A, Anum, B, Bnum, xAxis[iNumAxes], xOffset, xVel, taxis[iNumAxes], t))
            return false;

        iNumAxes++;
    }

    // test separation axes of B
    for(int j = Bnum-1, i = 0; i < Bnum; j = i, i ++)
    {
        Vector E0 = B[j];
        Vector E1 = B[i];
        Vector E = E1 - E0;
        xAxis[iNumAxes] = Vector(-E.y, E.x);

        if (!IntervalIntersect( A, Anum, B, Bnum, xAxis[iNumAxes], xOffset, xVel, taxis[iNumAxes], t))
            return false;
        iNumAxes++;
    }
   
    if (!FindMTD(xAxis, taxis, iNumAxes, N, t))
        return false;

    // make sure the polygons gets pushed away from each other.
    if (N * xOffset < 0.0f)
        N = -N;

    return true;
}

bool AxisSeparatePolygons ( Vector N, Polygon A, Polygon B, Vector Offset, Vector Vel, float &t, float tmax)
{
    float min0, max0;
    float min1, max1;

    CalculateInterval(N, A, min0, max0);
    CalculateInterval(N, B, min1, max1);
   
    float h = Offset dot N;
    min0 += h;
    max0 += h;

    float d0 = min0 - max1; // if overlapped, do < 0
    float d1 = min1 - max0; // if overlapped, d1 > 0

    // separated, test dynamic intervals
    if (d0 > 0.0f || d1 > 0.0f)
    {
        float v = Vel dot N;

        // small velocity, so only the overlap test will be relevant.
        if (fabs(v) < 0.0000001f)
            return false;

        float t0 =-d0 / v; // time of impact to d0 reaches 0
        float t1 = d1 / v; // time of impact to d0 reaches 1
        // sort the times.
        if (t0 > t1)
        {
            float temp = t0;
            t0 = t1;
            t1 = temp;
        }
        // take the minimum positive
        taxis = (t0 > 0.0f)? t0 : t1;

        // intersection time too late or back in time, no collision
        if (taxis < 0.0f || taxis > tmax)
            return true;

        return false;
    }
    else
    {
        // overlap. get the interval, as a the smallest of |d0| and |d1|
        // return negative number to mark it as an overlap
        taxis = (d0 > d1)? d0 : d1;
        return false;
    }
}


bool FindCollisionPlane (Vector* Axis, float* taxis, int iNumAxes, Vector& Ncoll, float& tcoll)
{
    // find collision first
    int mini = -1;
    tcoll = 0.0f;
    for(int i = 0; i < iNumAxes; i ++)
    {
        if (taxis[i] > 0.0f)
        {
            if (taxis[i] > tcoll)
            {
                mini = i;
                tcoll = taxis[i];
                Ncoll = Axis[i];
                Ncoll.Normalise(); // normalise axis
            }
        }
    }

    // found a collision
    if (mini != -1)
        return true;

    // nope, find overlaps
    mini = -1;
    for(int i = 0; i < iNumAxes; i ++)
    {
        float n = Axis[i].Normalise(); // axis length

        taxis[i] /= n; // normalise interval overlap too

        // remember, those numbers are negative, so take the closest to 0
        if (mini == -1 || taxis[i] > tcoll)
        {
            mini = i;
            tcoll = taxis[i];
            Ncoll = Axis[i];
        }
    }
   
    return (mini != -1);
}

现在,你拥有了一个可以检测未来碰撞的的检测系统,或者当重叠的时候,返回碰撞平面和碰撞深度 / 时间
 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值