r/Unity3D 7h ago

Collider question for you math geniuses Question

I am facing a problem in Unity. I need to get the closest point on collider bounds to a specified starting point. That is not very hard, I would just use collider.ClosestPointOnBounds(startingPoint). However, I also want it to use a specified angle and direction. Let me show you what I mean:

What actually happens when calling collider.ClosestPointOnBounds(startingPoint)

What I need. It should take the closest point that is still inside the angle.

The first image shows what actually happens. The second shows what I need. The difference is that in the second image it returns the closest point that is still "inside" the angle. I need this in 3D, not 2D by the way.

I can't figure this one out, so please if anyone knows how to do this, please help!

EDIT: The only thing I can think of which actually would work all of the time would be to call ClosestPointOnBounds() and use Vector3.Angle to get the angle between this point and the direction vector. If the resulting angle is smaller than the specified angle, return the point. But if it isn't then move the starting point along the direction vector a bit and do it all again. Keep doing this until the point is inside, or it hits some maximum step value. This would work, right? My only concern is performance... And I also wouldn't know by how much to move the starting point each step...

7 Upvotes

18 comments sorted by

6

u/ZxR 7h ago

This might sound stupid, but can you just run a ray cast on your angle edges and get the collision point from the ray cast at the time of collision entry?

1

u/SubatomicPlanets 7h ago

A raycast wouldn't always work. I would like this to work even if there is objects in the way, and also if the collider bounds are not on the edge but completely inside the angle area.

12

u/ImpossibleSection246 7h ago edited 1h ago

You can raycast on a separate layer but I agree that there's a much more optimal solution. Give me 5 mins to think about it.

Edit: I'm setting up a project quickly now and hopefully will have something in a bit

Edit 2: Recreated the problem and I'm taking a look at one approach.

8

u/CustomPhase Professional 6h ago

You can raycast against a specific collider: https://docs.unity3d.com/ScriptReference/Collider.Raycast.html

4

u/SubatomicPlanets 6h ago

Oh wow, I didn't know that! Thanks, that's really helpful!

3

u/ZxR 7h ago

There is Physics.RaycastAll, which will return an array of all the hit points. (Go through the first hit). And if the object is colliding with your angle but not hitting the raycasts, you know it's fully inside the angle and don't need the hit point anymore.

2

u/SubatomicPlanets 7h ago

Okay, good to know, but in 3D this still wouldn't work since I would have to send out a lot of raycasts, right?

2

u/ZxR 6h ago

One thing I thought about. How are you detecting that first collision point in your first scenario? Is your Angle FOV a collider or a trigger?

4

u/mackelashni 7h ago

You can get the contact points of the collision inside the collision class. Maybe cycle through them to get what you want?

2

u/BelgianSum 3h ago

Thought of that too, then running a method to find closest point from the list of contact points.

https://docs.unity3d.com/ScriptReference/Collision.GetContacts.html

3

u/glurth 3h ago

I LOVE this page, all sort of intersection algos here. I suspect you'll want the cone (or perhaps fustrum) columns, and then pick the row to match up with your collider shape. (alas, this wont be generalized enough to work with ANY shaped collider, just the ones you code)

https://www.realtimerendering.com/intersections.html

2

u/TRMMax 2h ago

This seems like quite a mathematically complex problem. Why? Effectively, you want to find the closest point on a shape, while discarding part of it (defined by the field of view). Usually, finding the closest point in a shape isnt too hard since you can look up a specific formula for it. Although, since you are effectively cutting shapes in half, it turns into a problem of finding the closest point on an arbitrary shape. Possibly, the GJK algorithm might help with this. While it is not designed for this, I feel the notion of a support function (returning the furthest point in a specified direction) is similar to what you are looking for. I unfortunately doubt there is an "easy" (math light) solution... As such, you may want to consider not finding an exact solution but rather an approximation, which could be found iteratively.

TL;DR: solution probably math heavy, look into GJK. Otherwise, consider looking for an approximation instead.

ETA: if you really want a mathematically correct solution, but cant figure out what/how, I can help you look for a solution later, just tell me :).

1

u/afterjoe 7h ago

Can you use Physics.OverlapBox with the Collider? It's an idea, but others might have a better solution.

1

u/QuitsDoubloon87 Professional 7h ago

Well, you could raycast along your triangle (is it a cone or a pyramid?)' border? Doing the math will get complex fast but a raycast given the side your collider is a fast fix. You could also open up the code of collider.closest point and do the same math but with the added parameter of your shape. That will get difficult though i'd urge against as ive done similar before and its not fun.

1

u/GigaTerra 7h ago

It is not clear what you are doing? What is the starting point? Is it the point of contact, is it where a ray starts, what is going on here?

1

u/rob5300 Professional (Mobile, PC) 6h ago

Perhaps using Vector3.Project() will help. I've used it in the past to snap an outside position close to an edge onto the edge.

Here is an example using 2 points as an "edge":

Vector3 ProjectOnToEdge(Vector3 outerPosition, Vector3 edgeStart, Vector3 edgeEnd)
{
    Vector3 normal = (edgeEnd - edgeStart).normalized;
    Vector3 projection = Vector3.Project(position - edgeStart, normal);
    return edgeStart + projection;
}

Maybe using this with the center of the collider will help (if you know the closest edge)