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
0
Question by Benjames · Feb 11, 2019 at 05:58 PM · meshcolliderpoint

Point inside mesh?

I have this function that is supposed to check if a point is inside a mesh collider. The problem is it doesn't work right all the time. It actually works better is I change Vector3 from= (Vector3.up 5000f); to Vector3 from = (Random.onUnitSphere 5000f);.. but that doesn't seem very consistent, like it works but is bad practice right?

     bool IsInCollider(MeshCollider other, Vector3 point) {
         Vector3 from = (Vector3.up * 5000f);
         Vector3 dir = (point - from).normalized;
         float dist = Vector3.Distance(from, point);
         int hit_count = 0;
         //fwd
         RaycastHit[] hit = Physics.RaycastAll(from, dir, dist);
         for (int tt = 0; tt < hit.Length; tt++) {
             if (hit[tt].collider == other) {
                 hit_count++;
             }
         }
         //back
         dir = (from - point).normalized;
         RaycastHit[] hitt = Physics.RaycastAll(point, dir, dist);
         for (int tt = 0; tt < hitt.Length; tt++) {
             if (hitt[tt].collider == other) {
                 hit_count++;
             }
         }
         if (hit_count % 2 == 1) {
             return (true);
         }
         return (false);
     }
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

4 Replies

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

Answer by Benjames · Feb 12, 2019 at 05:14 PM

Ok so I found that RaycastAll will only return the first hit it gets on a single mesh. So I had to write something that restarted the Raycast from the hit position. Here is my code.

    public  bool IsInCollider(MeshCollider other, Vector3 point) {
         Vector3 from = (Vector3.up * 5000f);
         Vector3 dir = (point - from).normalized;
         float dist = Vector3.Distance(from, point);        
         //fwd      
         int hit_count = Cast_Till(from, point, other);
         //back
         dir = (from - point).normalized;
         hit_count += Cast_Till(point, point + (dir * dist), other);
 
         if (hit_count % 2 == 1) {
             return (true);
         }
         return (false);
     }
 
     int Cast_Till(Vector3 from, Vector3 to, MeshCollider other) {
         int counter = 0;
         Vector3 dir = (to - from).normalized;
         float dist = Vector3.Distance(from, to);
         bool Break = false;
         while (!Break) {
             Break = true;
             RaycastHit[] hit = Physics.RaycastAll(from, dir, dist);
             for (int tt = 0; tt < hit.Length; tt++) {
                 if (hit[tt].collider == other) {
                     counter++;
                     from = hit[tt].point+dir.normalized*.001f;
                     dist = Vector3.Distance(from, to);
                     Break = false;
                     break;                    
                 }
             }
         }
         return (counter);
     }
Comment
Add comment · 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
1

Answer by Ymrasu · Feb 11, 2019 at 06:46 PM

I believe Physics.Raycast only hits colliders it does not start within. So you can use that to your advantage. If you cast from your point towards the collider it should hit it, unless it is within the collider.

 bool IsInCollider(MeshCollider other, Vector3 point)
     {
         Vector3 direction = other.bounds.center - point;
         RaycastHit[] hits = Physics.RaycastAll(point, direction);
 
         foreach(RaycastHit hit in hits) {
             if(hit.collider == other) {
                 // we hit it so we were outside it
                 return false;
             }
         }
         
         // no hits probably means we're inside it
         return true;
     }

EDIT: Thinking about another way to get a point inside the mesh instead of other.bounds.center made me realize that you can just try this:

 bool IsInCollider(Collider other, Vector3 point)
     {
 
         if(other.ClosestPoint(point) == point) {
             return true;
         }
         
         return false;
     }
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 Benjames · Feb 11, 2019 at 09:33 PM 0
Share

I believe that it would not work out for all shapes. like a concave shape where the center of the bounds doesn't actually lie within the shape. Thanks for the input though!

avatar image Ymrasu Benjames · Feb 11, 2019 at 10:36 PM 0
Share

This is what happens when I overthink it. I think you can simply check if (other.ClosestPoint(point) == point) to see if it is inside the mesh.

avatar image Benjames Ymrasu · Feb 11, 2019 at 11:50 PM 0
Share

Oh jeez I didn't know that existed. I'll try it out thanks!

Show more comments
avatar image
0

Answer by olejuer · Feb 19, 2020 at 11:04 AM

Very old thread, but came up on google when looking for "Unity check inside mesh". This is actually quite a tricky problem, but I have a simple solution that covers most cases

 private bool IsInsideMesh(Vector3 point)
     {
         Physics.queriesHitBackfaces = true;
         int hitsUp = Physics.RaycastNonAlloc(point, Vector3.up, _hitsUp);
         int hitsDown = Physics.RaycastNonAlloc(point, Vector3.down, _hitsDown);
         Physics.queriesHitBackfaces = false;

         for (var i = 0; i < hitsUp; i++)
             if (_hitsUp[i].normal.y > 0)
                 for (var j = 0; j < hitsDown; j++)
                     if (_hitsDown[j].normal.y < 0 && _hitsDown[j].collider == _hitsUp[i].collider)
                         return true;
         
         return false;
     }

This makes use of the fact that no collider is hit twice by a raycast. If the hit normal has a positive component in the direction of the raycast, it's a backface. As long as the mesh has a closed surface and does not extend indefinitely, a single raycast would suffice. Any quad, or plane, however, would give false positives. To cover those cases, fire a raycast in the opposite direction and see if you hit a backface of the same mesh. This covers most cases.

If you look closely, though, things get tricky and mathy. There meshes that generate false positives, like an open half sphere. You would have to check, if the mesh is a closed surface. Another problem is that the mesh could have a closed part and an open part, like a cube with an extra face extruded from one edge. The point could be inside the closed part, but the full mesh would technically still not be a closed surface, giving you a false negative. So you should limit the check to the part of the mesh that you hit with the raycast. So yeah, there should be an asset for this...

Personally, I will just live with the check above.

Comment
Add comment · 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
0

Answer by Laiken · Dec 23, 2021 at 07:22 AM

For mesh colliders

 bool IsInsideMeshCollider(MeshCollider col, Vector3 point)
     {
         var temp = Physics.queriesHitBackfaces;
         Ray ray = new Ray(point, Vector3.back);
 
         bool hitFrontFace = false;
         RaycastHit hit = default;
 
         Physics.queriesHitBackfaces = true;
         bool hitFrontOrBackFace = col.Raycast(ray, out RaycastHit hit2, 100f);
         if (hitFrontOrBackFace)
         {
             Physics.queriesHitBackfaces = false;
             hitFrontFace = col.Raycast(ray, out hit, 100f);
         }
         Physics.queriesHitBackfaces = temp;
 
         if (!hitFrontOrBackFace)
         {
             return false;
         }
         else if (!hitFrontFace)
         {
             return true;
         }
         else 
         {
             // This can happen when, for instance, the point is inside the torso but there's a part of the mesh (like the tail) that can still be hit on the front
             if (hit.distance > hit2.distance)
             {
                 return true;
             }
             else
                 return false;
         }
 
     }
Comment
Add comment · 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

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

100 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 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 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 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 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 avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How can I find the position between Point A and Point B, X units away from Point A? 1 Answer

Simple Point system 3 Answers

Moving character to a specific point ? 0 Answers

Do Dynamic Batching before Light pass. 0 Answers

Automatic path to point & click game. 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