Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bounds.Contains() is not working at all as expected

Discussion in 'Scripting' started by JoePatrick, Jul 16, 2017.

  1. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    118
    I've been having issues where when the object is rotated (even with a 1,1,1 scale and no parent) Bounds.Contains() is returning true when the point isn't in the bounds.
    I thought maybe I had a bug in my code so I wrote a test script - literally 1 line - and the error persists.
    Here is the full code of my test script
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class test : MonoBehaviour {
    4.  
    5.     public bool TEST;
    6.     public GameObject point;
    7.  
    8.     // Use this for initialization
    9.     void Start () {
    10.        
    11.     }
    12.    
    13.     // Update is called once per frame
    14.     void Update () {
    15.         TEST = gameObject.GetComponent<Collider>().bounds.Contains(point.transform.position);
    16.     }
    17. }
    And here is the result

    As you can see the TEST box is checked, even though the sphere very clearly isn't within the bounds of the cube.

    Anyone know what's going on? It's driving me completely mad!
    Thanks :)
     
  2. Kasper_OmsK

    Kasper_OmsK

    Joined:
    Jul 9, 2015
    Posts:
    47
    That's indeed really weird...

    There's nothing wrong with your code as far as I can tell...
    Have you tried testing dumb point like (0,0,0) ? Or infinitely far away points
     
  3. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,196
    Bounds is an AABB - axis aligned bounding box. It's defined exclusively by the center and extents, and hold no information about the rotation of the object. For a collider, the .bounds is the smalles axis alligned box that contains the entire collider.

    AABBs are used for rough spatialization of things. It's much faster to check if two axis aligned boxes are overlapping than two general boxes.


    If you want to know if something is inside of your box, you'll have to do the math yourself. If you're working with other colliders, you could use an OverlapBox check.
     
    Bunny83 and PraetorBlue like this.
  4. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    118
    I have used it before and it usually works just fine even if rotated, I also tried this code and the issue persisted
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class test : MonoBehaviour {
    4.  
    5.     public bool TEST;
    6.     public GameObject point;
    7.  
    8.     // Use this for initialization
    9.     void Start () {
    10.      
    11.     }
    12.  
    13.     // Update is called once per frame
    14.     void Update () {
    15.         TEST = gameObject.GetComponent<Collider>().bounds.Intersects(point.GetComponent<Collider>().bounds);
    16.     }
    17. }
    I'll try that other stuff you mentioned though
     
  5. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,196
    It literally says in the docs that it's not rotated. If you used it before, you just didn't notice the bug.


    Here's a script you can add to a GameObject to draw the current bounds for a Collider or Renderer as gizmos. Then you can see the behaviour of the bounds as you rotate the object.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. #if UNITY_EDITOR
    4. using UnityEditor;
    5. #endif
    6.  
    7. public class DrawBoundsGizmos : MonoBehaviour {
    8. #if UNITY_EDITOR
    9.     public enum ColliderOrRenderer {
    10.         Collider,
    11.         Renderer
    12.     }
    13.  
    14.     public enum DrawWhen {
    15.         Always,
    16.         Selected,
    17.         ParentSelected
    18.     }
    19.  
    20.     public ColliderOrRenderer type;
    21.     public DrawWhen drawWhen;
    22.  
    23.     private static readonly Vector3 gizmosSize = Vector3.one * .1f;
    24.  
    25.     public void OnDrawGizmosSelected() {
    26.         if (drawWhen == DrawWhen.ParentSelected) {
    27.             DrawGizmos();
    28.         } else if (drawWhen == DrawWhen.Selected && Selection.activeTransform == transform) {
    29.             DrawGizmos();
    30.         }
    31.     }
    32.  
    33.     private void OnDrawGizmos() {
    34.         if (drawWhen == DrawWhen.Always) {
    35.             DrawGizmos();
    36.         }
    37.     }
    38.  
    39.     private void DrawGizmos() {
    40.         try {
    41.             Bounds B = type == ColliderOrRenderer.Renderer ? GetComponent<Renderer>().bounds : GetComponent<Collider>().bounds;
    42.             DrawGizmosFor(B);
    43.         }
    44.         catch {
    45.             // nothing to draw the bounds of!
    46.         }
    47.     }
    48.  
    49.     public static void DrawGizmosFor(Bounds B) {
    50.         var xVals = new[] {
    51.             B.max.x, B.min.x
    52.         };
    53.         var yVals = new[] {
    54.             B.max.y, B.min.y
    55.         };
    56.         var zVals = new[] {
    57.             B.max.z, B.min.z
    58.         };
    59.  
    60.         for (int i = 0; i < xVals.Length; i++) {
    61.             var x = xVals[i];
    62.             for (int j = 0; j < yVals.Length; j++) {
    63.                 var y = yVals[j];
    64.                 for (int k = 0; k < zVals.Length; k++) {
    65.                     var z = zVals[k];
    66.  
    67.                     var point = new Vector3(x, y, z);
    68.                     Gizmos.DrawCube(point, gizmosSize);
    69.  
    70.                     if (i == 0) {
    71.                         Gizmos.DrawLine(point, new Vector3(xVals[1], y, z));
    72.                     }
    73.                     if (j == 0) {
    74.                         Gizmos.DrawLine(point, new Vector3(x, yVals[1], z));
    75.                     }
    76.                     if (k == 0) {
    77.                         Gizmos.DrawLine(point, new Vector3(x, y, zVals[1]));
    78.                     }
    79.  
    80.                 }
    81.             }
    82.         }
    83.     }
    84. #endif
    85. }
     
  6. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    118
    Huh, I guess you're right - and that's a neat little script thanks :)

    I actually just wrote my own script for checking the bounds
    It requires you to do all the transformations (centre, scale etc) on the parent gameobject rather than the collider component (so the collider centre is 0,0,0 and scale is 1,1,1) but that's fine for me and it works great.
    Code (CSharp):
    1. bool ColliderContainsPoint(Transform ColliderTransform, Vector3 Point, bool Enabled)
    2.     {
    3.         Vector3 localPos = ColliderTransform.InverseTransformPoint(Point);
    4.         if (Enabled && Mathf.Abs(localPos.x) < 0.5f && Mathf.Abs(localPos.y) < 0.5f && Mathf.Abs(localPos.z) < 0.5f)
    5.             return true;
    6.         else
    7.             return false;
    8.     }
     
    zelderus and PitVital like this.
  7. calpolican

    calpolican

    Joined:
    Feb 2, 2015
    Posts:
    400
    I know this is a very old post, but I just wanted to say: Joe Patrick, lots of thanks for this awesome script, it's a pretty simple solution but very elegant and it works great!
     
  8. PitVital

    PitVital

    Joined:
    Jan 6, 2018
    Posts:
    5

    I know we are going back some years with this, but this just saved me a bit of work, thanks JoePatrick for sharing your findings :)
     
  9. unity_OwXnva3VjWOa8A

    unity_OwXnva3VjWOa8A

    Joined:
    Jun 1, 2018
    Posts:
    1
    Awesome Solution dude! thanks !
     
  10. KKmainK

    KKmainK

    Joined:
    Sep 7, 2016
    Posts:
    11
    Joe Patrick is king♡
     
  11. ge01f

    ge01f

    Joined:
    Nov 28, 2014
    Posts:
    121
    I made a few changes to this, since I had the same problem:

    Code (CSharp):
    1. public bool TransformBoxContainsPoint(Transform colliderTransform, Vector3 offset, Vector3 colliderSize, Vector3 point)
    2. {
    3.   Vector3 localPos = colliderTransform.InverseTransformPoint(point);
    4.  
    5.   localPos -= offset;
    6.  
    7.   if (Mathf.Abs(localPos.x) < (colliderSize.x/2) && Mathf.Abs(localPos.y) < (colliderSize.y/2) && Mathf.Abs(localPos.z) < (colliderSize.z/2))  return true;
    8.   else return false;
    9. }
    10.  
    Call with:

    Code (csharp):
    1.  
    2. var box = gameObject.GetComponent<BoxCollider>();
    3. var found = TransformBoxContainsPoint(box.transform, box.center, box.size, testObject.transform.position);
    4.  
     
    Last edited: Sep 21, 2022
    marios-trophygames likes this.
  12. Evan_Reid

    Evan_Reid

    Joined:
    Mar 18, 2023
    Posts:
    1
    @ge01f how would i make your little method return the objects its touching instead?