1. We're looking for feedback on Unity Starter Kits! Let us know what you’d like.
    Dismiss Notice
  2. Unity 2017.2 beta is now available for download.
    Dismiss Notice
  3. Unity 2017.1 is now released.
    Dismiss Notice
  4. Introducing the Unity Essentials Packs! Find out more.
    Dismiss Notice
  5. Check out all the fixes for 5.6 on the patch releases page.
    Dismiss Notice
  6. Help us improve the editor usability and artist workflows. Join our discussion to provide your feedback.
    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:
    39
    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
    [​IMG]
    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:
    46
    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:
    2,279
    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.
     
  4. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    39
    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:
    2,279
    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. }
     
    JoePatrick likes this.
  6. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    39
    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.     }