Search Unity

Question Burstable version of GeometryUtility.CalculateBounds

Discussion in 'Burst' started by tonytopper, Oct 5, 2022.

  1. tonytopper

    tonytopper

    Joined:
    Jun 25, 2018
    Posts:
    226
    I've been using GeometryUtility.CalculateBounds to do some geometry stuff in my game prototype. I'm now moving things over to Jobs and Burst. I am still using GameObjects and am diving into IJobParallelForTransform. I need to do the same thing that this CalculateBounds function does but do it in a Burst compatible function.

    I tried to find the source of this function so I could write my own Burst-compatible version but have yet to have luck.

    Suggestions?
     
  2. Anthiese

    Anthiese

    Joined:
    Oct 13, 2013
    Posts:
    73
    Code (CSharp):
    1. [BurstCompile]
    2. public static class BurstGeometryUtility {
    3.     public static Bounds CalculateBounds(NativeArray<float3> array, float4x4 trs) {
    4.         if (array.Length == 0) {
    5.             ThrowEmpty();
    6.             // default to zero-sized bounds in player builds - no exception support
    7.             return new Bounds(new Vector3(0, 0, 0), new Vector3(0, 0, 0));
    8.         }
    9.         float3 min = math.transform(trs, array[0]), max = min;
    10.         for (int i = 1; i < array.Length; i++) {
    11.             float3 value = math.transform(trs, array[i]);
    12.             // componentwise min/max works as expected
    13.             min = math.min(min, value);
    14.             max = math.max(max, value);
    15.         }
    16.         return new Bounds((min + max) * 0.5f, max - min);
    17.     }
    18.  
    19.     [BurstCompile]
    20.     public static void CalculateBounds(ref NativeArray<float3> array, in float4x4 trs, out Bounds bounds) {
    21.         bounds = CalculateBounds(array, trs);
    22.     }
    23.  
    24.     [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
    25.     private static void ThrowEmpty() {
    26.         throw new ArgumentException("Array cannot be empty");
    27.     }
    28. }
    Something along these lines could work. Moving around a bunch of points and taking the localToWorldMatrix of some object for the second parameter, this seems to match up with the GeometryUtility method.
     
    Last edited: Oct 5, 2022
    mm_hohu, tonytopper and andywiecko like this.
  3. andywiecko

    andywiecko

    Joined:
    Nov 18, 2020
    Posts:
    3
    tonytopper likes this.
  4. tonytopper

    tonytopper

    Joined:
    Jun 25, 2018
    Posts:
    226
    Thanks so much for the replies. Since I've also started using the work of @andywiecko, I am converting over from Bounds to AABB since floatN should be better in Burst than VectorN.

    Rolled this quick extension:
    Code (CSharp):
    1. public static class BoundsExtension
    2.     {
    3.         public static AABB ToAABB(this Bounds bounds)
    4.         {
    5.             return new AABB(
    6.                 new float2(bounds.min.x, bounds.min.y),
    7.                 new float2(bounds.max.x, bounds.max.y)
    8.             );
    9.         }
    10.     }
    I'll be using this to check collisions when placing some trees in my prototype's map generation.

    Code (CSharp):
    1. var bounds = new NativeArray<AABB>(2, Allocator.TempJob);
    2. bounds[0] = item.trunkBounds.ToAABB();
    3. bounds[1] = item.canopyBounds.ToAABB();
    Since those two bounds are actually nAABBs, not axis aligned, I need to align them to the access of the tree's Transform. Hence the later need for the CalculateBounds function.

    upload_2022-10-5_10-2-41.png

    This is the code I started to write to do the alignment; bounds above is newObjectBounds below. I like the work by @Anthiese and will use it as a basis for a CalculateAABB refactor/fix of my code below, which I am not even sure works.
    Code (CSharp):
    1. float4x4 tMatrix = float4x4.TRS(location, transform.rotation, transform.localScale);
    2.  
    3. for (int vN = 0; vN < newObjectBounds.Length; vN++)
    4. {
    5.      float2 min = math.mul(tMatrix, math.float4(newObjectBounds[vN].Min, 1, 1)).xy;
    6.      float2 max = math.mul(tMatrix, math.float4(newObjectBounds[vN].Max, 1, 1)).xy;
    7.      newObjectBounds[vN] = new AABB(min, max);
    8. }
     
    Last edited: Oct 6, 2022
    andywiecko likes this.
  5. tonytopper

    tonytopper

    Joined:
    Jun 25, 2018
    Posts:
    226
    I like the idea of parallel bounds calculation. I have other places where that would be more helpful.

    Here's where I seem to have landed:

    Code (CSharp):
    1. [BurstCompile]
    2. public static class BurstGeometryUtility
    3. {
    4.     public static AABB TranslateAABB(AABB bounds, float4x4 trs)
    5.     {
    6.         float2 min = Translate(trs, bounds.Min);
    7.         float2 max = Translate(trs, bounds.Max);
    8.  
    9.         return new AABB(min, max);
    10.     }
    11.  
    12.     public static AABB CalculateAABB(NativeArray<float2> array, float4x4 trs)
    13.     {
    14.         if (array.Length == 0)
    15.         {
    16.             ThrowEmpty();
    17.             return default;
    18.         }
    19.  
    20.         float2 min = Translate(trs, array[0]), max = min;
    21.         for (int i = 0; i < array.Length; i++)
    22.         {
    23.             float2 value = Translate(trs, array[i]);
    24.             min = math.min(min, value);
    25.             max = math.max(max, value);
    26.         }
    27.  
    28.         return new AABB(min, max);
    29.     }
    30.  
    31.     private static float2 Translate(float4x4 trs, float2 value)
    32.     {
    33.         return math.transform(trs, math.float3(value, 1)).xy;
    34.     }
    35.  
    36.     [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
    37.     private static void ThrowEmpty()
    38.     {
    39.         throw new ArgumentException("Array cannot be empty");
    40.     }
    41. }
    Unity really should have a more Burst-compatible bounding box of their own.
     
    andywiecko likes this.