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

Question Burstable version of GeometryUtility.CalculateBounds

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

  1. tonytopper

    tonytopper

    Joined:
    Jun 25, 2018
    Posts:
    199
    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:
    72
    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:
    199
    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:
    199
    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.