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

二、 用于碰撞响应的扩展分离坐标轴方法
检测多边形相交是非常有用的方法,但是可以做更多的事情。当多边形相交时,我想将他们移开以避免他们相交。
 
分离轴的方法可以非常好的用于这种情况,但是还需要作一些额外的工作。必须返回相交的深度,和推开多边形将它们分离的方向。相交的深度和方向的组合称为MTD,或者最小平移距离。这是用于将物体分离的的最小向量。
 
为了计算MTD,我们可以使用分离坐标轴。
 
当物体相交时,我们可以计算两个物体在每一个分离轴上的投影间隔。两个间隔交叠的部分提供了一个推动向量,你需要将其应用到其中一个物体上以便物体在轴上的投影停止交叠

“推动向量”你需要应用于A上将A推开,这样就可以使A和B分开。
 
显然,不能沿着一个随机的轴来推开物体。候选轴是投影在该轴上两个间隔之间交叠最小的那个。并且这个推动向量提供了最小平移距离。
 

bool Intersect(Polygon A, Polygon B, Vector& MTD)
{
    // potential separation axes. they get converted into push
    vectors Vector Axis[32];
    // max of 16 vertices per polygon
    int iNumAxis = 0;
    for(J = A.num_vertices–1, I = 0; I < A. num_vertices; J = I, I ++)
    {
        Vector E = A.vertex[I] – A.vertex[J];
        Axis[iNumAxis++] = Vector(-E.y, E.x);
   
    if (AxisSeparatePolygons(N, A, B))
            return false;
    }
    for(J = B. num_vertices–1, I = 0; I < B.num_vertices; J = I, I ++)
    {
        Vector E = B.vertex[I] – B.vertex[J];
        Axis[iNumAxis++] = Vector(-E.y, E.x);
   
        if (AxisSeparatePolygons (N, A, B))
            return false;
    }
   
    // find the MTD among all the separation vectors
    MTD = FindMTD(Axis, iNumAxis);

    // makes sure the push vector is pushing A away from B
    Vector D = A.Position – B.Position;
    if (D dot MTD < 0.0f)
        MTD = -MTD;

    return true;
}

 

bool AxisSeparatePolygons(Vector& Axis, Polygon A, Polygon B)
{
    float mina, maxa;
    float minb, maxb;

    CalculateInterval(Axis, A, mina, maxa);
    CalculateInterval(Axis, B, minb, maxb);

    if (mina > maxb || minb > maxa)
        return true;

    // find the interval overlap
    float d0 = maxa - minb;
    float d1 = maxb - mina;
    float depth = (d0 < d1)? d0 : d1;

    // convert the separation axis into a push vector (re-normalise
    // the axis and multiply by interval overlap)
    float axis_length_squared = Axis dot Axis;

    Axis *= depth / axis_length_squared;
    return false;
}

 

Vector FindMTD(Vector* PushVectors, int iNumVectors)
{
    Vector MTD = PushVector[0];
    float mind2 = PushVector[0] dot PushVector[0];
    for(int I = 1; I < iNumVectors; I ++)
    {
        float d2 = PushVector[I] * PushVector[I];
        if (d2 < mind2)
        {
            mind2 = d2;
            MTD = PushVector[I];
        }
    }
    return MTD;
}

一旦得到了MTD向量,可以使用如下的方式将他们分开
 

A.Postion += MTD * 0.5f;
B.Position -= MTD * 0.5f;

显然,如果物体A是静态的,那么B将被完全的MTD推开(B.Position-=MTD)而A将不会被推开。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值