Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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
7
Question by MirrorIrorriM · Jan 24, 2013 at 12:54 AM · raycastdetectionmeshcolliderpolygonintersect

Detecting how many times a raycast collides with a single concave meshcollider

Hello all,

I am attempting to create an anti-mesh destructible terrain engine similar to that of the original Red Faction. The system uses meshes to cut into other meshes by taking all vertices of the original mesh that intersect with an "eraser mesh" or anti-mesh deleting said vertices. Afterwards, it takes all of the vertices of the anti-mesh and add them to the vertices of the original mesh, essentially taking a "bite" out of it.

Here is a picture that demonstrates this concept. Where the red is the original mesh, and the green is the anti-mesh, and cyan is the vertices of interest.

alt text

The system, however, requires the ability to see if an individual point is within a collision mesh. I have researched the topic a bit and found that the best way to do this in the traditional sense is to use a raycast algorithm to look and see how many intersects a raycast has with a mesh. If you have an odd number of intersects, you know for certain that the point is within the mesh; an even number of intersects implies the point lies outside of the mesh (where zero is also even).

Here is another image to demonstrate this concept. Here green is the mesh, and the line running through it is red and blue. Cyan are the intersects with the polygon "skin".

alt text

Problem is, using a simple RaycastAll only gives ONE intersect per meshCollider. I was wondering what the function would be in unity c# in order to see how many intersects a ray has with a given mesh.

Thanks in advance.

Comment
Add comment · Show 4
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 AlucardJay · Jan 24, 2013 at 01:12 AM 0
Share

I cannot find the API link where I learned how to do this, but for an array of colliders that SphereCastAll hit, this is the method. I don't know if it works for RaycastAll, but worth a try hey :

 var collidersInRange : RaycastHit[];
 collidersInRange = Physics.SphereCastAll( transform.position, 1.0, transform.forward, 10.0, hitmeLayermask );
 
 for ( i = 0; i < collidersInRange.Length; i ++ )
 {
     Debug.Log( "collidersInRange[" + i + "] " + collidersInRange[i].collider.gameObject.name + " : " + collidersInRange[i].collider.transform.position );
     Debug.Log( "collidersInRange[" + i + "] hitpoint = " + collidersInRange[i].point );
 }
avatar image MirrorIrorriM · Jan 24, 2013 at 01:34 AM 0
Share

Thank you for the quick response, but sadly this does not answer my question. I not only need to know the colliders the raycast hits, I need to know each and every intersect it has on that collider. $$anonymous$$eaning that I not only need to know when it hits it, I need to know when the raycast leaves it too. And if need be re-enters it. And re-leaves it. And re-enters it. etc etc.

avatar image AlucardJay · Jan 24, 2013 at 02:08 AM 0
Share

Sure, no worries, that's why it was just a suggestion/comment. I don't know how you are going to manage when the raycast exits the collider, this would be the same as casting from within a convex collider ie the collision won't detect from the backface. $$anonymous$$aybe have to cast a ray in both directions (from start to finish, then fom finish to start).

There must be a way to find the contact points :

http://docs.unity3d.com/Documentation/ScriptReference/Collision-contacts.html

http://docs.unity3d.com/Documentation/ScriptReference/ContactPoint-point.html

Edit : I just did a quick test with this script and some primitives, see if it works for your mesh. As I stated above, it won't register hits on the backface of a collider mesh :

 #pragma strict
 
 function Start() 
 {
     CheckCollisionPoints();
 }
 
 function Update() 
 {
     // so you can move the raycasting object around and get new results
     if ( Input.Get$$anonymous$$ouseButtonDown(0) )
     {
         CheckCollisionPoints();
     }
 }
 
 function CheckCollisionPoints() 
 {
     var collidersInRange : RaycastHit[];
     collidersInRange = Physics.RaycastAll( transform.position, transform.forward, 1000.0 );
     
     for ( var i : int = 0; i < collidersInRange.Length; i ++ )
     {
         Debug.Log( "collidersInRange[" + i + "] " + collidersInRange[i].collider.gameObject.name + " : hitpoint = " + collidersInRange[i].point );
     }
     
     Debug.DrawRay( transform.position, transform.forward * 1000.0, Color.red, 5.0 );
 }
avatar image MirrorIrorriM · Jan 24, 2013 at 02:15 AM 0
Share

That line of code would in theory work perfectly. The problem is that unity seems to only return a max of 1 hit per collider. So even if you hit two faces you only get 1 result.

I'm going to try creating a new ray at the point where the last one hit, going in the same direction as the last. To create a "chain" of rays. Hopefully this will work better.

3 Replies

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

Answer by MirrorIrorriM · Jan 24, 2013 at 02:41 AM

Thanks to alucardj for helping with the logic.

Note that this solution doesn't work if you have one sided 2 dimensional objects such as the default unity plane. It will be unable to tell if the object is actually inside anything or not.

How you solve the problem is you have to make multiple a new raycast every time you collide with the object. You repeat this until you reach your target, at which point you reverse direction to try and return from an arbitrary point in world space which is outside the collider in question. You must do the return check to get all the "backfaces" which the first raycast direction will miss. Here is the final code.

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

It is actually remarkably similar to the original picture I posted.

alt text

Comment
Add comment · Show 3 · 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 jvhgamer · Aug 11, 2017 at 03:38 PM 0
Share

$$anonymous$$irror$$anonymous$$irror,

I'm trying to do something very similar. I have a ray casting on user mouse click going through an object, then casting a second ray perpendicular to the first (offset to ensure the second ray starts from outside the collider) back towards the origin point (where the user clicked).

Unfortunately I am running into the same situation you did in which I would like to be able to deter$$anonymous$$e if there are multiple walls to the collider.

 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
 RaycastHit hit;
 if (Physics.Raycast(ray, out hit))
 {
 
 //obtain the vector where the ray hit the collider.
     hitPoint = hit.point; //origin point
 //offset the ray, keeping it along the XZ plane of the hit
     Vector3 offsetDirection = -1 * hit.normal;
 //offset a long way, $$anonymous$$imum thickness of the object
     ray.origin = hit.point  + offsetDirection * 100;
 //point the ray back at the first hit point
     ray.direction = (hit.point - ray.origin).normalized;
 //raycast all, because there might be other objects in the way
     RaycastHit[] hits = Physics.RaycastAll(ray);
     foreach (RaycastHit h in hits)
     {
         if (h.collider == hit.collider)
         {
             hitBack = h.point; //destination point
         }
     }
 }

hitPoint is the origin point (the first ray cast from the mouse where the user clicks) hitBack is the destination point (second ray cast perpendicularly to the first ray back towards it)

avatar image jvhgamer · Aug 11, 2017 at 03:38 PM 0
Share

As you said before, RaycastAll only gives one intercept per mesh collider. There in lies the problem. I am trying to implement your while loop to continuously cast rays until a ray reaches the origin point but am co$$anonymous$$g up short on the math.

                     //offset the ray, keeping it along the XZ plane of the hit
                     Vector3 offsetDirection = -hit.normal;
                     //offset a long way, $$anonymous$$imum thickness of the object
                     ray.origin = hit.point + offsetDirection * 100;
                     //point the ray back at the first hit point
                     ray.direction = (hit.point - ray.origin).normalized;
 
                     Vector3 Point, Goal, Direction;
                     Point = ray.origin;
                     Goal = hit.point;
                     Direction = ray.direction;
 
                     Debug.Log("Point: " + Point);
                     Debug.Log("Goal: " + Goal);
                     Debug.Log("Point+: " + (Point + (Direction * 100.0f)));
 
                     while (Point != Goal)
                     {
 
                         RaycastHit hit2;
                         if (Physics.Linecast(Point, Goal, out hit2))
                         {
                             counter_one++;
                             Point = hit2.point;
                             Debug.Log("Point-hit2: " + Point);
                         }
                         else
                         {
                             Point = Goal;
                             hitBack = Point;
                         }
                     }

I'm running through Debug printout statements to try and diagnose how to do the math properly to ensure the rays co$$anonymous$$g back toward the origin point eventually reach it and the while loop stops, but as of now, it deadlocks and crashes Unity.

I as well am unsure if it would be possible to add to my existing RaycastAll loop and do the casting their, or if Linecasting is the better option.

*Double commenting as it wouldn't allow me to post this all in one comment

avatar image jvhgamer · Aug 11, 2017 at 06:39 PM 0
Share

Figured it out! Thanks $$anonymous$$irror$$anonymous$$irror for posting this.

avatar image
0

Answer by SofiaFeist · Feb 09, 2020 at 12:43 AM

Hello, I've been having a similar problem recently and this thread helped me a lot to solve it. I just wanted to share my code, which is a bit smaller than MirrorIrorriM's but uses the exact same logic, in case anyone is interested. Let me know if anyone has any feedback.

 bool InsideCollider(Vector3 point) 
     {
         int count = 0;
         RaycastHit hit;
 
         Vector3 rayStart =  new Vector3(100, 100, 100);
         Vector3 direction = point - rayStart;
         Vector3 hitPoint = rayStart;
 
         while (Physics.Raycast(hitPoint, direction, out hit, direction.magnitude) && count < 100)         // count < 100 Just in case you accidentally enter an infinite loop
         {
             hitPoint = hit.point + (direction.normalized / 100.0f);
             count++;
         }
 
         hitPoint = point;
 
         while (Physics.Raycast(hitPoint, -direction, out hit, direction.magnitude) && count < 100)
         {
             hitPoint = hit.point + (-direction.normalized / 100.0f);
             count++;
         }
 
         // Checking how many intersections there are
         if (count % 2 == 0)     // if count is even
             return false;
         else   // if count is odd
             return true;
     }
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 Dreamer-of-dreams · Mar 29, 2020 at 12:01 PM

alt text

https://gist.github.com/tsubaki/6438870 This Japanese commented code solves all problems, it was recently released


屏幕快照-2020-03-29-下午75057.png (108.9 kB)
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

13 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

Related Questions

Cutting a Sprite 0 Answers

Trigger and raycast error? 2 Answers

Mesh polygon of a hit surface on a gameobject 1 Answer

Detecting game object under UI 2 Answers

How can I make a raycast move towards an object? 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