分离轴定理检测两个凸多边形是否相交

1、什么是分离轴定理?

通过检查两个物体在所有可能的分离轴上的投影是否重叠,来判断它们是否相交。如果存在任何一个分离轴上的投影不重叠,那么两个物体一定不相交。否则,如果所有的分离轴上的投影都重叠,那么两个物体可能相交,需要进一步检查。

如上图,我们可以找到一条分离轴(不唯一),使得三角形的投影线段HI和四边形的投影线段JK不重叠,则两个多边形不相交。

2、怎么确定分离轴

  1. 对于每个物体的边界框,确定其边界框的边或面的法线向量。

  2. 对于每个法线向量,检查两个物体在该法线上的投影是否重叠。如果所有法线上的投影都重叠,那么两个物体一定相交。如果至少一条法线上的投影不重叠,那么两个物体一定不相交。

3、Unity代码实现

    /// <summary>
    /// 判断是否相交
    /// </summary>
    /// <param name="verShapeA">多边形A</param>
    /// <param name="verShapeB">多边形B</param>
    /// <returns></returns>
    private bool IsCross(List<Vector2Int> verShapeA,List<Vector2Int> verShapeB)
    {
        for (int i = 0; i < verShapeA.Count; i++)
        {
            Vector2Int a, b;
            a = verShapeA[i];
            if (i == verShapeA.Count - 1)
            {
                b = verShapeA[0];
            }
            else
            {
                b = verShapeA[i + 1];
            }

            //求边的单位法向量
            Vector2 normalVector = GetNormalVector(a, b);
            //求shapeA在向量上的最低点和最高点
            Vector2 minShapeAPos, maxShapeAPos=Vector2.zero;
            GetShapeProjectLength(verShapeA,normalVector,out minShapeAPos,out maxShapeAPos);
            //求shapeB在向量上的最低点和最高点
            Vector2 minShapeBPos,maxShapeBPos=Vector2.zero;
            GetShapeProjectLength(verShapeB,normalVector,out minShapeBPos,out maxShapeBPos);
            //检查两段投影是否有交集
            if (Mathf.Min(maxShapeAPos.y, maxShapeBPos.y) - Mathf.Max(minShapeAPos.y, minShapeBPos.y) > 0)
            {
                continue;
            }
            else
            {
                return false;
            }
        }
        return true;
    }
    
    //求边的法向量
    private Vector2 GetNormalVector(Vector2Int pos1, Vector2Int pos2)
    {
        Vector2Int edgeVector = pos2 - pos1;
        return new Vector2(-edgeVector.y, edgeVector.x).normalized;
    }
    
    //求shape在法向量的投影最低点和最高点
    private void GetShapeProjectLength(List<Vector2Int> verShape,Vector2 normal,out Vector2 lowPos,out Vector2 highPos)
    {
        lowPos = new Vector2(0, float.MaxValue);
        highPos = new Vector2(0, float.MinValue);
        for (int i = 0; i < verShape.Count; i++)
        {
            float dotProduct = Vector2.Dot(verShape[i], normal);
            Vector2 projectionPoint = dotProduct*(Vector2)normal;
            if (projectionPoint.y < lowPos.y)
            {
                lowPos = projectionPoint;
            }

            if (projectionPoint.y > highPos.y)
            {
                highPos = projectionPoint;
            }
        }
    }

4、效果

采样集较少,不一定能保证算法100%正确(至少检测了10多个案例都是符合预期的)

5、缺点

分离轴定理算法只适用于凸多边形 and 无法告诉你是那条边发生的碰撞

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值