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
3
Question by Bryan 4 · Mar 23, 2011 at 07:50 PM · physicsboxcolliderpoints

Test to see if a Vector3 (point) is within a boxcollider.

Is there a way to get the 3 rotated axis of the box collider to test if a point lies within it?

The quickest technique I know to obtain a boolean result for point within an OBB relys on axis, center, and the box's extent, However I cannot find a way to get the axis.

Comment
Add comment · Show 1
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 David_JAM · May 22, 2019 at 07:28 PM 0
Share

Does anybody know how to do this when the box collider isn't known.

In my example; I have a unknown number of box colliders in the game and I want to check if a vector3 contains any box collider?

All the examples I see are only good if you already know the box collider you're checking...

5 Replies

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

Answer by efge · Mar 23, 2011 at 07:58 PM

Maybe you could use Bounds.Contains on Collider.bounds.

Comment
Add comment · Show 4 · 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 Bryan 4 · Mar 23, 2011 at 08:02 PM 0
Share

Did not see that! Thank you very much.

avatar image Chris.Hoback.CILAT · Apr 10, 2012 at 08:37 PM 1
Share

Hmmmm . . I am trying to do something similar, but when I use Bounds.Contains where the bounds comes from a rotated box collider it lies about the result. . . . to my face. The documentation specifically says bounds is AABB only. So i'm not sure that is working for you. If anyone knows of a way to tell if a point is inside a rotated box collider, I'd be very very interested.

avatar image shieldgenerator7 · Mar 25, 2016 at 06:40 PM 0
Share

I looked at this, but thought it wasn't what I wanted. I confused the size attribute as a float, but it's actually a Vector3. Just FYI in case anyone makes the same mistake I did.

avatar image TobiasW · Mar 25, 2016 at 08:08 PM 1
Share

Bounds don't have rotation. This won't give you a Bounds fitting exactly the rotated BoxCollider, but ins$$anonymous$$d makes a new axis-aligned Bounds object in which the rotated BoxCollider is fully contained - so it will be bigger than the BoxCollider.

You might consider accepting the answer by @$$anonymous$$ikeEnoch ins$$anonymous$$d. That's how I'd do it too.

edit: Argh, didn't check how old this was, just saw that it had a new comment.

avatar image
13

Answer by MikeEnoch · Nov 25, 2015 at 12:19 PM

Also a late reply, but this question is high on the Google search results for OABB checks with BoxColliders, so worth mentioning that something like this would probably be faster than a raycast:

     bool PointInOABB (Vector3 point, BoxCollider box )
     {
         point = box.transform.InverseTransformPoint( point ) - box.center;
         
         float halfX = (box.size.x * 0.5f);
         float halfY = (box.size.y * 0.5f);
         float halfZ = (box.size.z * 0.5f);

         if( point.x < halfX && point.x > -halfX && 
            point.y < halfY && point.y > -halfY && 
            point.z < halfZ && point.z > -halfZ )
             return true;
         else
             return false;
     }

Works by transforming your point into the box's local space and then checking against the box dimensions directly.

Comment
Add comment · Show 4 · 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 Pawl · Mar 26, 2016 at 07:43 AM 1
Share

This is a great solution.

As an aside, the 6 '&&' checks can be optimized by checking 'II' (and flipping the signs) to benefit from run-time short circuit evaluation.

avatar image shieldgenerator7 Pawl · Mar 26, 2016 at 05:39 PM 2
Share

It can already benefit from run-time short circuit evaluation, because as soon as one of the and conditions fail, the whole thing does

avatar image Pawl shieldgenerator7 · Mar 28, 2016 at 05:44 AM 2
Share

Damn, you're absolutely right, I stand corrected.

avatar image MrBarragan · May 25, 2016 at 05:20 PM 0
Share

This is an awesome solution. I've been banging my head against my keyboard for hours trying to figure out why my ** bounds check wouldn't work. This solves everything nicely. Thank you very much.

avatar image
3

Answer by pjcarey97 · Sep 03, 2014 at 09:53 PM

This was three and a half years ago, but useful tip for others who come across this question: put the box in it's own layer, cast a ray from the point your checking to the center of the box, and make sure your layermask is only that layer. If your raycast returns false, the point IS inside the box, if it returns true, your point IS NOT inside the box. Then if you still care what layer the box is in, return it to the layer it was in.

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 jhughes2112 · Feb 23, 2018 at 08:00 AM

So, I know this is an ancient thread, but I found a neat way to do the same thing without all the branches, as min and max are often implemented without comparisons. It's pretty much doing the same thing as above, just differently.

 static bool IsInsideBounds(Vector3 worldPos, BoxCollider bc)
 {
     Vector3 localPos = box.transform.InverseTransformPoint(worldPos);
     Vector3 delta = localPos - bc.center + bc.size * 0.5f;
     return Vector3.Max(Vector3.zero, delta)==Vector3.Min(delta, bc.size);
 }

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 Bunny83 · Feb 23, 2018 at 12:00 PM 0
Share

Even it's a bit shorter than what $$anonymous$$ike posted it's certainly not better or faster. Vector3.$$anonymous$$in and $$anonymous$$ax are implemented like this:

 public static Vector3 $$anonymous$$in(Vector3 lhs, Vector3 rhs)
 {
     return new Vector3($$anonymous$$athf.$$anonymous$$in(lhs.x, rhs.x), $$anonymous$$athf.$$anonymous$$in(lhs.y, rhs.y), $$anonymous$$athf.$$anonymous$$in(lhs.z, rhs.z));
 }

And $$anonymous$$athf.$$anonymous$$in / $$anonymous$$ax is implemented like this:

 public static float $$anonymous$$in(float a, float b)
 {
     return (a >= b) ? b : a;
 }

So you get a lot additional method calls and no benefit of early exit at all. You will always have to go though all conditions. $$anonymous$$ethod calls can have a huge impact on performance if you use such a method literally 100k times a frame. Have a look at this bilinear texture resampling algorithm i've posted over here. The "inlined" and optimised version runs about 8 times faster than the one using the straight forward solution. The optimised version is the one on the dropbox.


So I would always prefer $$anonymous$$ike's solution over this one. Btw: How would you implement a $$anonymous$$ / max function without comparison? You get two inputs and have to return the smaller / greater one. How would you do that without a comparison?


$$anonymous$$ikes solution could be written a bit more compact:

  bool PointInOABB (Vector3 point, BoxCollider box )
  {
      point = box.transform.InverseTransformPoint( point ) - box.center;
      var half = box.size * 0.5f;
      if( point.x < half.x && point.x > -half.x && 
         point.y < half.y && point.y > -half.y && 
         point.z < half.z && point.z > -half.z )
          return true;
      return false;
  }

Or a bit more efficient:

  bool PointInOABB (Vector3 point, BoxCollider box )
  {
      point = box.transform.InverseTransformPoint( point );
      var c = box.center;
      var s = box.size;
      float X = s.x * 0.5f + point.x - c.x;
      if (X < 0 || X > s.x)
          return false;
      float Y = s.y * 0.5f + point.y - c.y;
      if (Y < 0 || Y > s.y)
          return false;
      float Z = s.z * 0.5f + point.z - c.z;
      if (Z < 0 || Z > s.z)
          return false;
      return true;
  }

This avoids unnecessary method calls and unnecessary calculations in case of an early exit. Note that depending on the type of game it might be beneficial to re-order the x,y and z cases to better match the situation. For example for some kind of RTS game most things will be on the same height (y value). It's much more common to have different x and z values so those should be checked first and y last. However it depends on the general layout.

avatar image jhughes2112 Bunny83 · Feb 23, 2018 at 05:41 PM 0
Share

Thanks for the detailed response. I think there's some parts in it that I agree with, and some that are more nuanced than you suggest. Hear me out.

You're absolutely right that in naive, unoptimized C#, function call overhead is expensive. You can measure that in the editor directly. When I did that, my function was about 50% slower than the most optimized version you provided above. Specifically, a million iterations of calls to a basic function (with a tiny bit of other overhead) was about 7.5 seconds versus 11.5 seconds. I was a little surprised it mattered that much, and was ready to call it there and eat some crow and pat you on the back. After all, that circumstance, you definitely are correct.

Then I decided to produce a build and run the same test, given the JIT in C# might be disabled in the Editor, or in some other way interfere with real runtime behavior. That showed your version running the same code in 6.3 seconds, and $$anonymous$$e ran in 3.9 seconds. Almost 40% faster. I was happily surprised, again, that optimized C# could get as much as a typical C++ compiler would.

So... it depends. If your platform has no JIT and you aren't using IL2CPP, I suspect you might have better performance by doing all the manual removal of function calls as you said... but I would probably check to see if AOT compilation is smart enough to inline functions that naive C# does not before making that statement. If you are using any IL2CPP or JIT platforms, function call overhead melts away with inlining of functions and the branch misprediction matter more.

Regardless, performance tuning is complicated and things that work in one environment often do not translate to another. The answer? Both solutions are better sometimes. I just liked how short and simple $$anonymous$$e was, and felt I'd share it. Now I've learned a little more about C# in the process. Thanks!

avatar image jhughes2112 Bunny83 · Feb 23, 2018 at 05:56 PM 0
Share

Btw: How would you implement a $$anonymous$$ / max function without comparison? You get two inputs and have to return the smaller / greater one. How would you do that without a comparison?

Sorry, I meant to mention that $$anonymous$$/max for integers is easily done without a comparison. I misremembered there being float versions as well, but can't find them at the moment. For some fun reading, check out Bit Twiddling Hacks

avatar image
0

Answer by AnKOu · Jan 16, 2019 at 11:50 PM

Nice method. Very useful.

But this kind of method definitively should be in a static util class.

And why this if / else statement ?

So as an instance method :

 /// <summary>
 /// Return true if the point is inside the given BoxCollider.
 /// </summary>
 /// <param name="p_Point"></param>
 /// <param name="p_Box"></param>
 /// <returns></returns>
 public static bool IsInside(this Vector3 p_Point, BoxCollider p_Box)
 {
     p_Point = p_Box.transform.InverseTransformPoint(p_Point) - p_Box.center;

     float l_HalfX = (p_Box.size.x * 0.5f);
     float l_HalfY = (p_Box.size.y * 0.5f);
     float l_HalfZ = (p_Box.size.z * 0.5f);

     return (p_Point.x < l_HalfX && p_Point.x > -l_HalfX &&
         p_Point.y < l_HalfY && p_Point.y > -l_HalfY &&
         p_Point.z < l_HalfZ && p_Point.z > -l_HalfZ);
 }

Same with SphereCollider

 /// <summary>
 /// Return true if the point is inside the given SphereCollider.
 /// </summary>
 /// <param name="p_Point"></param>
 /// <param name="p_Box"></param>
 /// <returns></returns>
 public static bool IsInside(this Vector3 p_Point, SphereCollider p_Sphere)
 {
     p_Point = p_Sphere.transform.InverseTransformPoint(p_Point) - p_Sphere.center;
     return p_Point.sqrMagnitude <= p_Sphere.radius * p_Sphere.radius;
 }

And maybe when all type all colliders are supported, do a method like that :

 /// <summary>
 /// Is the Point inside the given Collider ?
 /// Must be a convex collider.
 /// </summary>
 /// <param name="p_Point"></param>
 /// <param name="p_Collider"></param>
 /// <returns></returns>
 public static bool IsInside(this Vector3 p_Point, Collider p_Collider)
 {
     SphereCollider l_SphereCollider = p_Collider as SphereCollider;
     if (l_SphereCollider != null)
     {
         return p_Point.IsInside(l_SphereCollider);
     }
 
     BoxCollider l_BoxCollider = p_Collider as BoxCollider;
     if (l_BoxCollider != null)
     {
         return p_Point.IsInside(l_BoxCollider);
     }
 
     //etc...
  }
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

10 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

Related Questions

Quickly moving cubes fall through quad floor 3 Answers

Bump when crossing box colliders 1 Answer

Why is it so fast to move objects with collider collisions? 1 Answer

Apply Gravity to Car Physics 0 Answers

Collision Detection for Kinematic Rigidbodies 0 Answers


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