检测思路
首先要做的是将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)); } } }
运行结果
时间: 2024-10-04 20:51:54