碰撞检测之Sphere-Box检测

Posted 拳四郎

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了碰撞检测之Sphere-Box检测相关的知识,希望对你有一定的参考价值。

检测思路

首先要做的是将Box转为AABB,然后判断圆心是否在Box内,用的就是之前的SAT

如果圆心在Box内,肯定相交,

如果不在圆心内,则有四种情况,与顶点相交,与楞相交,与面相交,这里的确定也是通过SAT来确定。

在二维中,如果圆心不box内,有两种情况


技术分享技术分享


只要对比红色线段的长度和圆的半径就可以了。


代码

 public static bool IntersectSphereBox(Sphere sphere, Box box)
        {
            Vector3 delta = sphere.center - box.center;
            Matrix4x4 boxRotMatrix = Matrix4x4.TRS(Vector3.zero, box.rotation, Vector3.one);
            Vector3 dRot = boxRotMatrix.inverse.MultiplyVector(delta);

            bool outside = false;
            if (dRot.x < -box.extents.x)
            {
                outside = true;
                dRot.x = -box.extents.x;
            }
            else if (dRot.x > box.extents.x)
            {
                outside = true;
                dRot.x = box.extents.x;
            }

            if (dRot.y < -box.extents.y)
            {
                outside = true;
                dRot.y = -box.extents.y;
            }
            else if (dRot.y > box.extents.y)
            {
                outside = true;
                dRot.y = box.extents.y;
            }

            if (dRot.z < -box.extents.z)
            {
                outside = true;
                dRot.z = -box.extents.z;
            }
            else if (dRot.z > box.extents.z)
            {
                outside = true;
                dRot.z = box.extents.z;
            }


            if (outside)    //if clipping was done, sphere center is outside of box.
            {
                Vector3 clippedDelta = boxRotMatrix.MultiplyVector(dRot);   //get clipped delta back in world coords.
                Vector3 clippedVec = delta - clippedDelta;            //what we clipped away.	

                float lenSquared = clippedVec.sqrMagnitude;
                float radius = sphere.radius;
                if (lenSquared > radius * radius)   // PT: objects are defined as closed, so we return ‘true‘ in case of equality
                    return false;   //disjoint
            }
            return true;
        }


测试代码

public class SphereBoxTester : MonoBehaviour {
    public GameObject sphere;
    public GameObject box;
    Box _box;
    Sphere _sphere;
    // Use this for initialization
    void Start () {
        _box = new Box();

        _sphere = new Sphere();
    }

    // Update is called once per frame
    void Update () {
        _box.center = box.transform.position;
        _box.rotation = box.transform.rotation;
        _box.extents = 0.5f * box.transform.localScale;

        _sphere.center = sphere.transform.position;
        _sphere.radius = 0.5f * sphere.transform.localScale.x;

        if (NIntersectTests.IntersectSphereBox(_sphere, _box))
        {
            sphere.GetComponent<MeshRenderer>().materials[0].SetColor("_Color", new Color(1, 0, 0));
        }
        else
        {
            sphere.GetComponent<MeshRenderer>().materials[0].SetColor("_Color", new Color(1, 1, 1));
        }
    }
}



运行结果


技术分享

技术分享

技术分享



以上是关于碰撞检测之Sphere-Box检测的主要内容,如果未能解决你的问题,请参考以下文章

碰撞检测之Ray-Box检测

碰撞检测之Ray-Sphere检测

碰撞检测之Box-Box检测

pygame之精灵碰撞检测

AEJoy —— 表达式之碰撞检测JS

2022-04-20 Unity入门7——物理系统之碰撞检测