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?
[BurstCompile]
public static class BurstGeometryUtility {
public static Bounds CalculateBounds(NativeArray<float3> array, float4x4 trs) {
if (array.Length == 0) {
ThrowEmpty();
// default to zero-sized bounds in player builds - no exception support
return new Bounds(new Vector3(0, 0, 0), new Vector3(0, 0, 0));
}
float3 min = math.transform(trs, array[0]), max = min;
for (int i = 1; i < array.Length; i++) {
float3 value = math.transform(trs, array[i]);
// componentwise min/max works as expected
min = math.min(min, value);
max = math.max(max, value);
}
return new Bounds((min + max) * 0.5f, max - min);
}
[BurstCompile]
public static void CalculateBounds(ref NativeArray<float3> array, in float4x4 trs, out Bounds bounds) {
bounds = CalculateBounds(array, trs);
}
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
private static void ThrowEmpty() {
throw new ArgumentException("Array cannot be empty");
}
}
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.
3 Likes
The solution provided by @Anthiese should work, however, if performance is an issue, this could be easily parallelized since Bounds union operator is abelian 
Checkout my implementation for “accumulated product”:
https://github.com/andywiecko/BurstCollections#nativeaccumulatedproductt-op
1 Like
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:
public static class BoundsExtension
{
public static AABB ToAABB(this Bounds bounds)
{
return new AABB(
new float2(bounds.min.x, bounds.min.y),
new float2(bounds.max.x, bounds.max.y)
);
}
}
I’ll be using this to check collisions when placing some trees in my prototype’s map generation.
var bounds = new NativeArray<AABB>(2, Allocator.TempJob);
bounds[0] = item.trunkBounds.ToAABB();
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.

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.
float4x4 tMatrix = float4x4.TRS(location, transform.rotation, transform.localScale);
for (int vN = 0; vN < newObjectBounds.Length; vN++)
{
float2 min = math.mul(tMatrix, math.float4(newObjectBounds[vN].Min, 1, 1)).xy;
float2 max = math.mul(tMatrix, math.float4(newObjectBounds[vN].Max, 1, 1)).xy;
newObjectBounds[vN] = new AABB(min, max);
}
1 Like
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:
[BurstCompile]
public static class BurstGeometryUtility
{
public static AABB TranslateAABB(AABB bounds, float4x4 trs)
{
float2 min = Translate(trs, bounds.Min);
float2 max = Translate(trs, bounds.Max);
return new AABB(min, max);
}
public static AABB CalculateAABB(NativeArray<float2> array, float4x4 trs)
{
if (array.Length == 0)
{
ThrowEmpty();
return default;
}
float2 min = Translate(trs, array[0]), max = min;
for (int i = 0; i < array.Length; i++)
{
float2 value = Translate(trs, array[i]);
min = math.min(min, value);
max = math.max(max, value);
}
return new AABB(min, max);
}
private static float2 Translate(float4x4 trs, float2 value)
{
return math.transform(trs, math.float3(value, 1)).xy;
}
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
private static void ThrowEmpty()
{
throw new ArgumentException("Array cannot be empty");
}
}
Unity really should have a more Burst-compatible bounding box of their own.
1 Like