Find center and bounding sphere of scene?

Is there a simple way to find out the center and bounding sphere of a fully dynamic scene? I would like to be able to create a “zoom all” camera feature like the inbuilt zoom extents functionality of Unity but at runtime.

I have lots of experience from Adobe Director (Shockwave 3d) and in Director you can get the bounding sphere of any scene node and its children that doesn’t require a renderer or any geometry. I was kinda expecting the same in Unity.

You should do something like this:

  • Find all renderers (GameObject.FindAllObjects or something like that)
  • renderer.bounds will give you bounding box for renderer
  • Merge all bounding boxes using Bounds.Expand (or something like that)

Hmm, since you want a bounding sphere, I wouldn’t work with boxes. I’d simply get a list of all gameobjects in the scene using,

GameObject[] allGameObjects = GameObject[])GameObject.FindObjectsOfType(typeof(GameObject));

Now, since you want a bounding sphere, you can do two things: The easy way, or the hard, but more correct way. :slight_smile:

The easy one first:

You can run through all those objects and figure out which position is furthest from the origin. This distance is thus the radius of your bounding sphere. You know that a sphere with that radius will contain all other objects, since the distance to the origin of all other objects was found to be less than the radius you use.

That method will certainly result in a sphere that contains all objects, but it might be larger than it needs to be, since that method insists on placing the center of the sphere in 0,0,0. All objects could potentially be inside a marble-sized sphere and still require a bounding sphere of the earth’s radius, if all objects happen to be located approximately earth-radius away from 0,0,0. So that’s not necessarily what you want.

The harder, but more correct way:

You need to calculate the distance between all potential sets of two GameObjects to see which two gameobjects are furthest away from one another. Those two GameObjects then lie on the surface of your bounding sphere, and the center of the bounding sphere is halfway between them. You know that no other object can lie outside this sphere, because if it did, the distance from one of the first two objects to this new object would be greater than the one you found, and thus result in a larger bounding sphere.

I would write that code like so:

    // Acquire all gameobjects:
    GameObject[] allGameObjects = (GameObject[])GameObject.FindObjectsOfType(typeof(GameObject));

    float maxDistance = 0;

    GameObject MaxDistanceOne = null, MaxDistanceTwo = null;

    foreach (GameObject goOuter in allGameObjects)
    {
        // Add this conditional, if your situation allows you to skip objects which are children of others:
        if (goOuter.transform.parent != null)
            continue;

        // For all other objects
        foreach (GameObject goInner in allGameObjects)
        {
            // Again, add this if you can skip child objects, but this time, also skip the case where the inner is equal to the outer
            if (goOuter.transform.parent != null || goOuter == goInner)
                continue;

            // Calculate the distance between inner and outer, and set the max, if this distance is greater than the one we already have
            float dist = Vector3.Distance(goOuter.transform.position, goInner.transform.position);

            // If that distance is greater than the one we already had, update the findings:
            if (dist > maxDistance)
            {
                maxDistance = dist;
                MaxDistanceOne = goOuter;
                MaxDistanceTwo = goInner;
            }
        }
    }

    // At this point, MaxDistanceOne and MaxDistanceTwo should refer to two gameobjects which are further away from one another than any other two gameobjects in the scene
    // Calculate a vector that points from one of them to the other, and half it:
    Vector3 fromOneToTwo = (MaxDistanceTwo.transform.position - MaxDistanceOne.transform.position) * 0.5f;

    // Add this vector to the position of the first gameobject. That vector is the sphere's center, and the sphere's diameter is stored in maxDistance:
    Vector3 SphereCenter = MaxDistanceOne.transform.position + fromOneToTwo;

Edit:

The maxDistance is of course the DIAMETER, not the radius. :wink: I corrected that in the comments to the code above.