Get closest point between GameObject (inside the cube collider) and 3D cube collider

Viewed 568

enter image description here

How do I calculate the distance of a game object (inside a cube collider) from the cube collider surface? The existing calculations were made from the cube surface outwards so I got 0 when I used the collider.closestpoint or collider.closestpointonbounds.

4 Answers

The simplest (but computationally not the cheapest) would be to not rely on your current collider for the distance, but to add a set of small colliders around the edge of the object (so 6 colliders, one per face of the cube). Using Collider.ClosestPoint() on all 6 faces and calculating the distance like that would give you the results you need.

First convert a point to local space.

var localPoint = transform.InverseTransformPoint(worldPoint);
var extents = collider.size * 0.5f;
var closestPoint = localPoint;

Compute the distance to each face.

var disx = extents.x - Mathf.Abs(localPoint.x);
var disy = extents.y - Mathf.Abs(localPoint.y);
var disz = extents.z - Mathf.Abs(localPoint.z);

Find the closest face (smallest distance) and move the closest point along this axis.

if(disx < disy)
{
    if (disx < disz)
        closestPoint.x = extents.x * Mathf.Sign(localPoint.x); //disx
    else
        closestPoint.z = extents.z * Mathf.Sign(localPoint.z); //disz
}
else
{
    //......
}

Plus the offset of the collider, convert to world space.

closestPoint += collider.center;
transform.TransformPoint(closestPoint);

I don't know how efficient this is, but here is how I solved it:

    public static Vector3 ClosetPointOnBounds(Vector3 point, Bounds bounds)
    {
        Plane top = new Plane(Vector3.up, bounds.max);
        Plane bottom = new Plane(Vector3.down, bounds.min);

        Plane front = new Plane(Vector3.forward, bounds.max);
        Plane back = new Plane(Vector3.back, bounds.min);

        Plane right = new Plane(Vector3.right, bounds.max);
        Plane left = new Plane(Vector3.left, bounds.min);

        Vector3 topclose = top.ClosestPointOnPlane(point);
        Vector3 botclose = bottom.ClosestPointOnPlane(point);

        Vector3 frontclose = front.ClosestPointOnPlane(point);
        Vector3 backclose = back.ClosestPointOnPlane(point);

        Vector3 rightclose = right.ClosestPointOnPlane(point);
        Vector3 leftclose = left.ClosestPointOnPlane(point);

        Vector3 closest = point;
        float bestdist = float.MaxValue;
        foreach (Vector3 p in new Vector3[] { 
            topclose, botclose, frontclose, backclose, leftclose, rightclose 
        })
        {
            float dist = Vector3.Distance(p, point);
            if (dist < bestdist)
            {
                bestdist = dist;
                closest = p;
            }
        }

        return closest;
    }

(note: this assumes and axis-aligned box, which is all I needed at the time. If you want to rotate it you will have to do more work to transform the point.)

You can Calculate by Vector3.Distance

some example

 float minDistance =2;
 float Distance = Vector3.Distance(other.position, transform.position);
 if(Distance < minDistance)
 {
     //some code stuffs
 }
 else if(Distance > minDistance){
     //some code stuffs
 }

Useful information about Vector3.Distance and getting Distance from object source: https://docs.unity3d.com/ScriptReference/30_search.html?q=Distance

Related