Finding center of a group of objects

Hey folks,

I’m trying to implement some double-clicking functionality that will move the camera so that it is looking at the center of the object (or group of objects) that was double-clicked.

For a single of object, I was able to use transform.renderer.bounds.center to get the center of the object, and this seems to work fairly well.

I have objects grouped in a hierarchy, so there are many game objects that do not have a renderer. Does anyone have any ideas as to how I might be able to center the camera on these game objects that do not have renderers?

Basically, if I have the game object Cube Group, with children Red Cube, Blue Cube and Green Cube, how would I find the center of Cube Group? Some groups have a large number of children, so I’m hoping for something that doesn’t involve going through all of the children and using the bounds of the children to calculate the bounds of the group.

Thanks,
Jared

One way would be to let the parent game object always be center of the group that way you can just use LookAt(groupTransform) to center camera view on the group.

Ofc there might be the trouble of keeping the parent gameobject center. But you could adjust that if you add new objects to the group or remove objects.

That was my first cent. :smile:

Edit: Oh and if some objects dont have renders. Why would you want to center cam view on those as they wont show up anyways?

Regards
Marc

Thanks for the response Marc, I’ll take a closer look at the LookAt function.

Since I have this hierarchy set up, the “group objects” don’t have a renderer, but I still want to be able to find the center of the entire group (in addition to the center of each mesh in the group)… does that make sense?

I think Marc has made good suggestion with centering the children on their parent’s transform.
This works for static groups but if you have changing groups then I think there’s no other way than to iterate over all the children and calculate the center.
You could however use Marc’s suggestion to “cache” the center of the group by moving it’s transform to that position and save recalculations as long as the group doesn’t change.

Also, I don’t think going through all child objects to find the center of a group is a bad or ugly approach. It’s rather the only way to do it and if Unity would provide such a function then that’s just what Unity would do for you.

A good approximate is to average the transform.position’s. ie add together all the target positions and divide by the number of targets. It’s not exactly center in that if you have two targets that are in the same position, the “center” gets weighted towards them. I’ve been playing around with a test script and it seems to be pretty close.

Thanks for all of the advice. I think I have a reasonable solution now. I tried a few different methods:

  • averaging the transform.positions
  • finding all the renderers inside the group and averaging the bounds.center
  • finding all the renderers inside the group to calculate the groupMin and groupMax vectors and then using these vectors to determine the groupCenter.

All seemed to work fairly similarly (and accurately). I went for the third option because I can use the bounding box defined by groupMin and groupMax in some other calculations. Looping through all of the objects in the group doesn’t appear to be a big blow to performance.

Thanks again.

-Jared

1 Like

this works like a charm for me, only tested in 2d, but shouldn’t make a difference.

//Optional to toggle calculating the center
var calculateCenter = true;

var groupTransforms : Transform[];
var groupCenter :Vector3;

//Optional object that will follow the center so you can see it in the game
var groupCenterObj : Transform;

function Update()
{	
    if(calculateCenter)
	{
		var groupVectors : Vector3;
		
	   	for (var i : Transform in groupTransforms)
	   	{	   		
	   		groupVectors += i.position;	   		
	   	}
	   	
	   	groupCenter = groupVectors / groupNum;
	}	
	
    //optional make an object follow the found center
	groupCenterObj.position = groupCenter;
}

EDIT: Disregard this. Encapsulate works fine, I’m crazy.

Found a good solution after finding that Bounds.Encapsulate doesn’t actually alter the bounds.center. My solution builds a new bounds using min and max. Here’s the extension:

public static class BoundsExtension
{
    public static Bounds GrowBounds( this Bounds a, Bounds b )
    {
       Vector3 max = Vector3.Max ( a.max, b.max );
       Vector3 min = Vector3.Min( a.min, b.min );
 
       a = new Bounds( (max + min)*0.5f, max - min );
       return a;
    }
}

And use like so: (example draws gizmo using resulting bounds)

void OnDrawGizmos()
    {
       Renderer[] rends = GetComponentsInChildren<Renderer>();
       Bounds bounds = rends[0].bounds;
       foreach (Renderer rend in rends)
       {
         bounds = bounds.GrowBounds( rend.bounds );
       }
       Vector3 center = bounds.center;
 
       Gizmos.DrawCube( bounds.center, bounds.size );
 
       Gizmos.DrawSphere( center, 1f );
    }
3 Likes