测试碰撞的时候,最好单独建立一个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);
}
}