1
\$\begingroup\$

I need to find the position of the closest point from the bounds of multiple colliders. Right now I'm using OnTriggerStay and collider.ClosestPointOnBounds().

This works great for one collider, but as when I add a new collider, it doesn't update.

I've drawn a quick picture to illustrate what I'm trying to say. The black box is the area I want to check in, the red boxes are the colliders with numbers representing the order they entered the black box. The green star is what the code currently says the closest point is, and the blue star is the expected result. The purple star is the position I'm checking for, the blue star should be the closest point to the purple star.

enter image description here

I found this answer to a similar question on answers.unity3d.com. However, I feel like that could be very inefficient because there will be many, probably up to 50 of these box checking scripts running at the same time.

I've also tried using Physics.BoxCast but that gave very wild results. The area it was checking was very different to what I wanted, and also what I was visualizing with gizmos. Also, the whole idea of boxcasts are very very confusing so I would rather something else.

What is the best way to find the closest point on the bounds of multiple colliders within a certain area?

\$\endgroup\$
8
  • \$\begingroup\$ I feel like that wouldn't be efficient in my case, I would have to loop over all of the possible colliders to test if they intersect, and I would have to do that every frame to see if something's changed, and then do all that for each object (up to 50). Besides, isn't that more or less the same as checking for the closest point on the bounds of the collider? \$\endgroup\$
    – mr-matt
    Jul 12, 2017 at 19:38
  • \$\begingroup\$ Ah I think I misinterpreted the question a bit. I'm curious if the green star is occurring because it's actively colliding whereas the blue is "inside" the black area and it's stopped checking. \$\endgroup\$
    – n_plum
    Jul 12, 2017 at 19:42
  • \$\begingroup\$ Actually, the behavior is very unusual and not what you'd expect. The green star basically moves according to the order the objects entered in. If I remove the first one, the green star goes to the 2nd red box. Furthermore, the green start would actually go to the left most point of the 2nd box, even though it's outside the black box. \$\endgroup\$
    – mr-matt
    Jul 12, 2017 at 19:47
  • \$\begingroup\$ It probably just goes to the 0, 0 point of the box (the star that is) and if you're not handling multiple collisions, or have multiple stars (or whatever detection) then it makes sense to just be the first one, then second and so on. So that actually makes sense. Just seems you're not handling multiples \$\endgroup\$
    – n_plum
    Jul 12, 2017 at 19:53
  • \$\begingroup\$ What can I do about it? I'm just using the default OnTriggerStay(Collider col), and then col.ClosestPoint(somePosition). \$\endgroup\$
    – mr-matt
    Jul 12, 2017 at 19:55

2 Answers 2

3
\$\begingroup\$

When I needed to do the same, I've used an approximation which worked well. Here is what I do, given two colliders A and B (any form and complexity, but must be convex):

  1. Find the closest point between center of A and collider surface of B => ptA.
  2. Find closest point between center of B and collider surface of A => ptB.
  3. Find the middle point between ptA & ptB => ptM.
  4. Now find the closest point from ptM and the both collider surfaces. That's your answer.

Here is pseudo-code:

  Vector3 ptA = B.ClosestPoint(A.transform.position);
  Vector3 ptB = A.ClosestPoint(B.transform.position);
  Vector3 ptM = ptA + (ptB - ptA) / 2;
  // Answers:
  Vector3 closestAtA = A.ClosestPoint(ptM);
  Vector3 closestAtB = B.ClosestPoint(ptM);

This solution is rather expensive since you do 4 checks, but with simple colliders the performance hit is negligible.

P.S. Don't ask me for the formula proves. This solution was purely intuitive, and I'm not even sure it's geometrically correct. It simply worked for me :)

\$\endgroup\$
1
  • \$\begingroup\$ Brilliant my man \$\endgroup\$ Aug 23, 2020 at 18:24
0
\$\begingroup\$

I ended up using Physics.OverlapBox and sticking with ClosestPointOnBounds. Here is the successful code I used:

Collider[] cols = Physics.OverlapBox(position, scale, rotation, layerMask);
Vector3 bestPoint = Vector3.zero;
float closestSqrDistance = Mathf.Infinity;

for (int i = 0; i < cols.Length; i++)
{
    Vector3 pos = cols[i].ClosestPointOnBounds(centerPosition);
    Vector3 direction = pos - centerPosition;
    float sqrDist = direction.sqrMagnitude;

    if (sqrDist < closestSqrDistance)
    {
        closestSqrDistance = sqrDist;
        bestPoint = pos;
    }
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ If I read it correctly, this code will find the closest collider with a point on its surface, but all the checks are done for the source collider center, not its bounds. It looks I misread your question. I figured you need to find a line (two points) that gives the closest distance between two arbitrary collider surfaces. For me it was a big challenge (thus, the intuitive solution). \$\endgroup\$
    – real4x
    Jan 17, 2019 at 4:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .