Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
4
Question by Nonakesh · Sep 06, 2011 at 11:54 AM · colliderpointcontain

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. :/

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!

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

10 Replies

· Add your reply
  • Sort: 
avatar image
15
Best Answer

Answer by MirrorIrorriM · Feb 05, 2013 at 06:14 PM

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.

alt text

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.

Comment
Add comment · Show 8 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image cregox · Apr 09, 2013 at 07:13 PM 1
Share

Loved the picture! This is precisely what I had envisioned when I adapted Drakhar's script, but I couldn't be as sure as you are this solution would work 100% - even thought it did on all my tests. I'll post it as yet another answer (because I hate posting code inside comments, making them way too big) and here I ask you to please validate it with your idea. I think what leads it to be done with fewer lines of code make it more elegant and eventually easier to understand. :-P

avatar image Bunny83 · Apr 11, 2013 at 04:15 PM 0
Share

Btw, it might also work with RaycastAll. That way you just have to cast one in each direction, but i never tried that. $$anonymous$$aybe Unity ignores additional collisions with the same collider?! If not that would simplify the function ;)

Note: This approach has the problem that it is "relative" to your starting point. You have to know that you're starting outside or all results are inverted.

avatar image cregox · Apr 11, 2013 at 04:16 PM 0
Share

@Bunny83 exactly what I did. Check my answer! :)

avatar image MirrorIrorriM · Apr 11, 2013 at 05:41 PM 1
Share

RaycastAll can only detect one collision per collider. That is why I had to do the while loop to go through all the intersects with a mesh. It is really unfortunate too. $$anonymous$$akes a lot of intersect logic really annoying.

avatar image cregox · Apr 11, 2013 at 07:35 PM 0
Share

Yeah, I had it wrong. But I still think you could, at least, use $$anonymous$$athf.Infinity for distance and Physics.Raycast to begin with, rather than setting an arbitrary "far point".

Show more comments
avatar image
11
Wiki

Answer by DrakharStudio · Sep 17, 2012 at 08:44 AM

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;
 }
Comment
Add comment · Show 6 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Nonakesh · Sep 17, 2012 at 10:58 AM 1
Share

Well, that would probably work! Unfortunately I don't need it any more... this question is over a year old and I have already switched to a completely different system.

avatar image DrakharStudio · Sep 18, 2012 at 09:21 AM 0
Share

Yeah, but we found the question because we had the same need, and when we solved it, we posted it. And posting year is not shown, just day and month. ???

avatar image Nonakesh · Sep 18, 2012 at 09:59 AM 0
Share

Yeah, it's a bit strange... anyway, thanks for the answer! This method might be handy later in the development.

avatar image cregox · Nov 27, 2012 at 05:54 PM 0
Share

$$anonymous$$ouse over on top the time and it will show the year. And the line about `test.Raycast` has a typo. It should be `out hitInfo`. Great script by the way!

avatar image DrakharStudio · Nov 28, 2012 at 07:22 AM 0
Share

Thanks Cawas for the mouse-over tip and for detecting the typo ;)

Show more comments
avatar image
6

Answer by chriscode · Jul 11, 2018 at 10:33 PM

    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;
     }
 

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image ddaleymont · Jan 15, 2020 at 08:15 PM 1
Share

Extremely simple and effective. I don't know if there's a performance hit from closestPoint but this is the cleanest answer.

Just heads up for people who end up here that closestPoint doesn't work on concave meshColliders.

avatar image
0

Answer by SilverTabby · Sep 06, 2011 at 01:30 PM

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.

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


Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Nonakesh · Sep 06, 2011 at 03:23 PM 0
Share

Thank you for your answer, but could it be that this script only works when the point is touching the collider, not when it is inside?

avatar image ina · May 04, 2012 at 03:27 AM 0
Share

Vector3.one doesn't seem like it is pointing in the right direction? Also, point is not defined?

avatar image
0

Answer by cregox · Apr 09, 2013 at 07:16 PM

Here's my version of Mirror's idea, applied in Drakhar's script. I'm also using a layer mask here to prevent further issues on the detection. Hope you enjoy! :)

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;
 }
Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image MirrorIrorriM · Apr 11, 2013 at 03:42 PM 0
Share

This system would only work for small $$anonymous$$ority of meshes. You only check once for the skin of the object with a Physics.RaycastAll, This is problematic because the skin of a mesh is only 1 way. You have to check from both sides in order to see it. Because you only check from one side, your calculation only works when the point of interest is the center of a convex shape. Also, Physics.RaycastAll only sees each object once. If the ray overlaps with the same object 5 times, it will not return all intersects with the object, only the first will be returned.

avatar image cregox · Apr 11, 2013 at 04:06 PM 0
Share

@$$anonymous$$irrorIrorri$$anonymous$$ From my brief experience with few trials, I have to disagree. Physics.RaycastAll seem to be returning an array with every time it hits any "skin", as you call it. I've tested this on many concave meshes and it always worked. And I came with this idea the same way you did, because I was having issues with the first implementation which didn't account for concave shapes.

avatar image MirrorIrorriM · Apr 11, 2013 at 05:41 PM 0
Share

Just tested it. RaycastAll only gives one hit per collider. In addition, when you do your RaycastAll, you do not set a distance. This will just shoot a beam straight through the object with nothing to stop it. You need to set a distance for it to actually stop at the point of interest.

avatar image cregox · Apr 11, 2013 at 06:05 PM 0
Share

@$$anonymous$$irrorIrorri$$anonymous$$ I must admit now I see something wrong there, and I'll spend some time to check exactly what while making tests to make sure this works... But I still don't think raycastall gives only 1 hit per collider and I don't think we need to set a distance to make it stop. It goes from origin to infinite, and if it really works like that, it sounds better than making a distance to "near infinite" as you suggest. A whole different problem (I now see) is that maybe it doesn't allow to use masks without setting a distance.

avatar image cregox · Apr 11, 2013 at 07:32 PM 0
Share

@$$anonymous$$irrorIrorri$$anonymous$$ yes, indeed RaycastAll only gives 1 hit per Collider, sadly. $$anonymous$$y confusion there was because I was trying with concave objects and shapes which had many colliders, so I don't really have any good test case. As for the distance, it can be set to Infinity anyway. I'll updated my answer. (BTW, you should have just linked me your previous posts on this subject! http://answers.unity3d.com/questions/386698/detecting-how-many-times-a-raycast-collides-with-a.html )

  • 1
  • 2
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

18 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Internal collisions 1 Answer

raycastHit.point - How do I make it ignore colliders? 1 Answer

Find closest point of one object 3 Answers

How do I find whether a point exists within the volume of a (trigger) collider? 0 Answers

How to get the Collider point? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges