Test if point is in Collider/Trigger

Is it possible to test if a point is inside of a Collider/Trigger?
I try to test if 4 points are inside of a cylinder, so I can’t use the Bounds.Contains()

Btw. I want to use different shapes (Mesh Colliders) later, so a simple script like testing the distance between point and cylinder middlepoint won’t work. :confused:

EDIT:

I was able to avoid the problem, by using a “Point in Polygon” - script (I only need to check it in 2d), but it would still be really helpful if somebody could say me how to test if a point is inside a collider/trigger!

Although this question is old, I thought I would post another way to solve it. While @DrakharStudio’s solution would work for most convex shapes, many concave shapes could read inside when they actually aren’t.

Take a look at this picture for example.

Because the shape is concave, it is possible for you to pass through the skin of the object, only to exit it at a later time and re-enter it. Therefor, to be truly accurate, you must also test to exit the collider. You can do this with a simple 2 directional loop.

using UnityEngine;
using System.Collections;
  
public class CollisionTest : MonoBehaviour {
    void Update() {
        Vector3 Point;
        Vector3 Start = new Vector3(0,100,0); // This is defined to be some arbitrary point far away from the collider.
        Vector3 Goal = transform.position; // This is the point we want to determine whether or not is inside or outside the collider.
        Vector3 Direction = Goal-Start; // This is the direction from start to goal.
        Direction.Normalize();
        int Itterations = 0; // If we know how many times the raycast has hit faces on its way to the target and back, we can tell through logic whether or not it is inside.
        Point = Start;
  
  
        while(Point != Goal) // Try to reach the point starting from the far off point.  This will pass through faces to reach its objective.
        {
            RaycastHit hit;
            if( Physics.Linecast(Point, Goal, out hit)) // Progressively move the point forward, stopping everytime we see a new plane in the way.
            {
                Itterations ++;
                Point = hit.point + (Direction/100.0f); // Move the Point to hit.point and push it forward just a touch to move it through the skin of the mesh (if you don't push it, it will read that same point indefinately).
            }
            else
            {
                Point = Goal; // If there is no obstruction to our goal, then we can reach it in one step.
            }
        }
        while(Point != Start) // Try to return to where we came from, this will make sure we see all the back faces too.
        {
            RaycastHit hit;
            if( Physics.Linecast(Point, Start, out hit))
            {
                Itterations ++;
                Point = hit.point + (-Direction/100.0f);
            }
            else
            {
                Point = Start;
            }
        }
        if(Itterations % 2 == 0)
        {
            print("Point is Outside");
        }
        if(Itterations % 2 == 1)
        {
            print("Point is Inside");
        }
    }
}

We can tell if the object is inside or outside based on the number of times it has collided with a mesh. Since you cannot see the skin of a mesh coming from inside it, we also need to project raycasts coming from the point of interest. This technique works for all objects which are not 2-Dimensional, no matter how complex the shape or where the center is.

I would do something similar to the solution by @SilverTabby, but casting a ray from the point of interest to the center of the collider.

static public bool IsInside ( Collider test, Vector3 point)
{
   Vector3    center;
   Vector3    direction;
   Ray        ray;
   RaycastHit hitInfo;
   bool       hit;
  
   // Use collider bounds to get the center of the collider. May be inaccurate
   // for some colliders (i.e. MeshCollider with a 'plane' mesh)
   center = test.bounds.center;
  
   // Cast a ray from point to center
   direction = center - point;
   ray = new Ray(point, direction);
   hit = test.Raycast(ray, out hitInfo, direction.magnitude);
  
   // If we hit the collider, point is outside. So we return !hit
   return !hit;
}
bool IsInside ( Collider c , Vector3 point )
{
    Vector3 closest = c.ClosestPoint(point);
    // Because closest=point if inside - not clear from docs I feel
    return closest == point;
}

The first solution that I can come up with is that if you have a Vector3 point, and a refrence to the collider that you are checking, I would do a collider.Raycast (different from Physics.Raycast!) with a ray so small, that it could only hit the collider if your point was already touching it.

The only reason I haven’t already recommended collider.ClosestPointOnBounds is because I don’t know if a point inside the collider will return the input point or if it will return a something on the edge of the bounding box.

This is not C# but JS-like, now obsolete, Unity Script
var other : Collider;
var point : Vector3;
var dist : float = 0.001;

private var r : Ray = new Ray(point, Vector3.one);
private var hit : RaycastHit;
if(other.Raycast(r, hit, dist))
{    
    //point is inside other.
} else {
    //point is outside other.
}

Here’s my version of @MirrorIrorriM’s idea, applied in @DrakharStudio’s script. I’m also using a layer mask here to prevent further issues on the detection. Hope you enjoy! :slight_smile:

Edit:

Unfortunately, RaycastAll doesn’t bring all hits in the same collider - just the first one. So this simply doesn’t work, while RaycastAll isn’t fixed or I find/create a new implementation of it.

P.S. to both: if you feel this is good, be free to assimilate this on your answer to better organize this “thread” dudes.

/// 
/// Check if point is contained inside a collider.
/// It doesn't necessarily work for concave colliders, as RaycastAll only brings 1 hit per collider.
/// Usage example, assuming they're not null:
/// Collider col; Vector3 point;
/// if (col.Contains(point)) print("collider contains point");
/// 
static public bool Contains (this Collider col, Vector3 point) {
	// Use collider bounds to get the center of the collider.
	Vector3 center = col.bounds.center;
	
	// Get direction for later casting a ray from point to center . . .
	Vector3 direction = center - point;
	
	// Attempt to prevent raycast to hit any other collider.
	int originalLayer = col.gameObject.layer;
	int unusedLayer = 28; // random assumption
	col.gameObject.layer = unusedLayer;
	LayerMask mask = 1 << col.gameObject.layer;
	
	// If we hit the collider any odd number of times, point is probably inside.
	// But keep in mind RaycastAll doesn't bring more than 1 hit per collider, so this is just here for future implementation.
	int hits = Physics.RaycastAll(point, direction, Mathf.Infinity, mask).Length;
	bool inside = (hits % 2) == 0; // Keep in mind "Length" begins at 0.
	
	// Just recover original collider's layer.
	col.gameObject.layer = originalLayer;
	
	return inside;
}

Uhm … I need that too, for spawning the enemies [I don’t want them to spawn one on top of another], but your solutions are weird …

Is it not easier, to make an object with collider, set in onTrigger, parent it by the Spawner/Player/Whatever you need to test the collision for, and then just change the child objects position to the one you want to test, and do a simple collision check with the trigger, then disable it/remove/put away/whatever?

Kind of like … instead of using elaborate methods of calculating liquids temperature just stick a finger in and see what happens. Simple and works!

We needed to detect if a Zombie is inside a building, so each building as a bounding box. Then we use:

Collider[] cols = Physics.OverlapSphere(unityGameObject.transform.position,1f);

Here’s a light-weight alternative that works for all collider types with the exception of concave MeshColliders. (See @MirrorIrorriM’s solution for those); convex MeshColliders are just fine.

bool IsWithin(Collider c, Vector3 point, bool useRigidbody)
{
    Vector3 closest = c.ClosestPoint(point);
    Vector3 origin = c.transform.position + (c.transform.rotation * c.bounds.center);

    Vector3 originToContact = closest-origin;
    Vector3 pointToContact = closest-point;
  
    // If you're checking if a point is within a moving rigidbody and want to use it instead (ideally a single collider rigidbody; multiple could move the center of mass between the colliders, placing it "outside" and returning false positives). 
    Rigidbody r = c.attachedRigidbody;
    if (useRigidbody && (r != null))
    {
        // The benefit of this is the use of the center of mass for a more accurate physics origin; we multiply by rotation to convert it from it's local-space to a world offset.
        originToContact = closest - (r.position + (r.rotation * r.centerOfMass));
    }

    // Here we make the magic, originToContact points from the center to the closest point. So if the angle between it and the pointToContact is less than 90, pointToContact is also looking from the inside-out.
    // The angle will probably be 180 or 0, but it's bad to compare exact floats and the rigidbody centerOfMass calculation could add some potential wiggle to the angle, so we use "< 90" to account for any of that.
    return (Vector3.Angle(originToContact, pointToContact) < 90);
}

As you can see this doesn’t use any raycasts or muck about with object layers (outside of the self-contained ClosestPoint() method), just some simple Vector math.

Just want to mention that if you are playing with Collider2D, you can simply use myCollider.OverlapPoint.

Very late to the party, but this implementation will get a good approximation.

bool CubeInsideCollider ( Vector3 pos , Vector3 halfExtents )
{
    Collider[] colliders = Physics.OverlapBox(pos, halfExtents);
    return colliders.Length > 0;
}

The Vector3 halfExtents can be as arbitrarily small as desired, and you can pass Layers to the OverlapBox method to selectively ignore certain colliders.