2

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.

Yunus Emre
  • 61
  • 10
  • Is the collider you're checking for always a boxcollider, and if so, is it axis alligned (mentioning `.ClosestPointOnBounds()` seems to suggest so)? Or are you looking for a more generic answer that works for any given collider? – Alex Leest May 16 '22 at 13:48
  • I've edited my question. As you can see the closest point is the blue arrow but I also wanna know the black arrow. This looks like 2D but I wanna do this in 3D space. – Yunus Emre May 16 '22 at 13:57
  • Noted. Is the collider always aligned with the coördinate grid, or do you need it to be able to rotate freely from that? – Alex Leest May 16 '22 at 13:59
  • The GameObject and the box collider move around 3D space and nothing is static. – Yunus Emre May 16 '22 at 14:01

4 Answers4

0

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.

Alex Leest
  • 76
  • 7
  • Yeah I thought that as well but the problem is my cube and collider change shapes at runtime so this solution can cause an alignment problem. I look for a simple solution. – Yunus Emre May 16 '22 at 14:18
  • As far as I can see, resizing the new face-colliders would still be the simplest solution. If you can mirror the behavior that currently changes your cube and collider into these face-colliders, that'll be a solution. – Alex Leest May 16 '22 at 14:25
0

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);
shingo
  • 18,436
  • 5
  • 23
  • 42
0

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.)

umadik
  • 101
  • 2
  • 17
Mason Cloud
  • 1,266
  • 1
  • 15
  • 20
-1

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

BayEggex
  • 50
  • 6
  • 1
    I doubt you understood the question correctly. The code you gave example works outside of collider. If you put a game object inside the collider, I cannot measure the distance between the game object and the collider. – Yunus Emre May 16 '22 at 13:33
  • First of all, I thought you wanted outside of collider in the question, sorry for wasting your time. Also, if you didn't try Physics.Raycast() or Raycast() this might solve the problem – BayEggex May 16 '22 at 13:59
  • I tried the physics lib but I got the same result. – Yunus Emre May 16 '22 at 14:03