Unity3D box與sphere碰撞

測試碰撞的時候,最好單獨建立一個Demo(有點像單元測試),排除不必要的干擾,往往效更快,思路更清晰。
http://www.idivecat.com/archives/507
《實時碰撞算法檢測》P113

在這裏插入圖片描述

注意

  • Bounds並不是碰撞體的參數集合,只是一個與座標軸對齊的AABB盒,不會受到旋轉的影響,因此不能作爲碰撞的參數
  • InverseTransformVector會受到localScale的影響,因此需要乘以Scale或lossyScale
  • 本地變量和全局變量不要穿插引用,要統一,否則會出問題
public class CubeTest : MonoBehaviour
{
    public SphereCollider SphereCollider;
    public BoxCollider BoxCollider;

    // Start is called before the first frame update
    void Start()
    {
        
    }


    /// <summary>
    /// 點到OBB的最近點
    /// </summary>
    private Vector3 ClosestPointOBB(Vector3 p, BoxCollider boxCollider)
    {
        Vector3 extents = Vector3.Scale( boxCollider.transform.lossyScale, boxCollider.size) * 0.5f;
        Vector3 d = p - boxCollider.transform.position;
        Vector3 q = boxCollider.transform.position;

        // world space to local space
        Vector3 dl = boxCollider.InverseTransformVector(d);
        dl = Vector3.Scale(dl, boxCollider.transform.lossyScale);

        float distX = dl.x;   
        if (distX > extents.x) distX = extents.x;  
        if (distX < -extents.x) distX = -extents.x;
        // along the axis to get world position
        q += distX * boxCollider.transform.right;

        float distY = dl.y;
        if (distY > extents.y) distY = extents.y;
        if (distY < -extents.y) distY = -extents.y;
        q += distY * boxCollider.transform.up;

        float distZ = dl.z;
        if (distZ > extents.z) distZ = extents.z;
        if (distZ < -extents.z) distZ = -extents.z;
        q += distZ * boxCollider.transform.forward;

        return q;
    }

    /// <summary>
    /// 測試球與OBB相交,並取最近點
    /// </summary>
    private bool TestSphereOBB(SphereCollider s, BoxCollider boxCollider, ref Vector3 p)
    {
        p = ClosestPointOBB(s.transform.position, boxCollider);
        Vector3 v = p - s.transform.position;
        return Vector3.Dot(v, v) <= s.radius * s.radius;
    }


    // Update is called once per frame
    void Update()
    {
        Vector3 p = Vector3.zero;
        bool bCollide = TestSphereOBB(SphereCollider, BoxCollider, ref p);
        if (bCollide)
        {
            transform.GetComponent<Renderer>().material.color = Color.red;
        }
        else
        {
            transform.GetComponent<Renderer>().material.color = Color.white;
        }
    }


    private void OnDrawGizmos()
    {
        Vector3 q = ClosestPointOBB(SphereCollider.transform.position, BoxCollider);
        Gizmos.color = Color.green;
        Gizmos.DrawWireSphere(q, 0.1f);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章