Three.js: BoundingBox of a compounded Object3D object?

Created on 26 Sep 2011  ·  15Comments  ·  Source: mrdoob/three.js

Hello Guys,

i hava a Object3D instance, which includes a CubeGeometry and a TextGeometry. My Question: It is possible to get the
bounding box of this compounded geometries? i ask this, because i saw that the Object3D class doesn't have a boundingBox-Method
and i have no approach to calculate it for all objects include in the Object3D container.

My idea was it to center the camera depending on the Object3D- containers centeroid and therefore i have to know the boundingBox.

Greetings roundrobin

Question

Most helpful comment

I came across this looking for the same thing and ended up settling on this:

function getCompoundBoundingBox(object3D) {
    var box = null;
    object3D.traverse(function (obj3D) {
        var geometry = obj3D.geometry;
        if (geometry === undefined) return;
        geometry.computeBoundingBox();
        if (box === null) {
            box = geometry.boundingBox;
        } else {
            box.union(geometry.boundingBox);
        }
    });
    return box;
}

All 15 comments

Object3D doesn't have a method for computing the bounding box, but Geometry does.

With that out of the way, you just need to follow this.

thanks so far. maybe i ask wrong, my itention was to get the bounding box of the two objects. I know how to calculate the bounding box for one geometry, but when i have a compounded 3D objects, how i can calculate the bounding box, for example of two cubes. Or it is neccecary to merge the objects before to one geometry?

i hope you got my point :) it`s difficult to explain.

I see. I guess the only way right now is to compare all the bounding boxes and do some max() and min()s with all the values.

okay thanks. I'll post my solution if I am successfully

Here's my solution. Simply pass the object to this function and it will look through it's children to compute the height/width of the object and assign a height and width property to the object.


calculateDimensions(myObject);

...

/*
* Get the size of the compound object by computing the bounding box and getting the max/min of each of its children
*/
function calculateDimensions(_object) {

    var absoluteMinX = 0, absoluteMaxX = 0, absoluteMinY = 0, absoluteMaxY = 0, absoluteMinZ = 0, absoluteMaxZ = 0;

    for (var i = 0; i < _object.children.length; i++) {
        _object.children[i].geometry.computeBoundingBox();
        absoluteMinX = Math.min(absoluteMinX,_object.children[i].geometry.boundingBox.min.x);
        absoluteMaxX = Math.max(absoluteMaxX,_object.children[i].geometry.boundingBox.max.x);
        absoluteMinY = Math.min(absoluteMinY,_object.children[i].geometry.boundingBox.min.y);
        absoluteMaxY = Math.max(absoluteMaxY,_object.children[i].geometry.boundingBox.max.y);
        absoluteMinZ = Math.min(absoluteMinZ,_object.children[i].geometry.boundingBox.min.z);
        absoluteMaxZ = Math.max(absoluteMaxZ,_object.children[i].geometry.boundingBox.max.z);
    }

    // set generic height and width values
    _object.depth = (absoluteMaxX - absoluteMinX) * _object.scale.x;
    _object.height = (absoluteMaxY - absoluteMinY) * _object.scale.y;
    _object.width = (absoluteMaxZ - absoluteMinZ) * _object.scale.z;

    // remember the original dimensions
    if (_object.originalDepth === undefined) _object.originalDepth = _object.depth;
    if (_object.originalHeight === undefined) _object.originalHeight = _object.height;
    if (_object.originalWidth === undefined) _object.originalWidth = _object.width;

    console.log("Depth: " + _object.depth + ", Height: " + _object.height + ", Width: " + _object.width);
}


I came across this looking for the same thing and ended up settling on this:

function getCompoundBoundingBox(object3D) {
    var box = null;
    object3D.traverse(function (obj3D) {
        var geometry = obj3D.geometry;
        if (geometry === undefined) return;
        geometry.computeBoundingBox();
        if (box === null) {
            box = geometry.boundingBox;
        } else {
            box.union(geometry.boundingBox);
        }
    });
    return box;
}

@NickLarsen Looks good!

I have exactly the same problem and the same idea as roundrobin, two years ago. The solution of @NickLarsen looks really good, like @mrdoob said, but there is a big problem... I'll try to explain it.

In my scene there is always one Object3D which contains all geometries. For example I have 8 Spheres with different radius and different y-coordinate. They are all located at x=0 and z=0.
Then I tried to compute the whole boundingbox with the function from NickLarsen, but the result was very strange. To find the error, I logged all the single bounding boxes to the console:

({min:{x:-10, y:-10, z:-10}, max:{x:10, y:10, z:10}})
({min:{x:-20, y:-20, z:-20}, max:{x:20, y:20, z:20}})
({min:{x:-7, y:-7, z:-7}, max:{x:7, y:7, z:7}})
({min:{x:-18, y:-18, z:-18}, max:{x:18, y:18, z:18}})
({min:{x:-15, y:-15, z:-15}, max:{x:15, y:15, z:15}})
({min:{x:-3, y:-3, z:-3}, max:{x:3, y:3, z:3}})
({min:{x:-10, y:-10, z:-10}, max:{x:10, y:10, z:10}})
({min:{x:-25, y:-25, z:-25}, max:{x:25, y:25, z:25}})

As you can see, the bounding boxes are always calculated in the local coordinate system of the single sphere. And when you union them, it makes no sense! How can I get the boundingbox in world coordinates to get the real boundingbox of my Object3D ?

In the r.59dev branch, see Box3.setFromObject( object ).

@PanChan you need to percolate your transformations before you run this and it will work as intended. In my actual use of this, I clone the geometry for each object and apply the transformations to it before computing the bounding box. You can see my actual implementation here. I'm pretty noob when it comes to this stuff though, so take my implementation with a good dose of skepticism.

@NickLarsen I found another solution which seems to work. After computing the boundingbox, I translate it to the world system:

var bb = geometry.boundingBox;
bb.translate(obj3D.localToWorld( new THREE.Vector3()));

Don't know if it's a good solution, but it works for now. Think I'm waiting for the new revision with the professional solution ;) Thanks for the explanation!

Using @NickLarsen solution in my project I'm a bit optimized calculation for cases where the bounding box of the object already exists, and thus calculate it again is not necessary.

function getComplexBoundingBox(object3D) {
    var box = null;
    object3D.traverse(function(obj3D) {
        if (obj3D.matrixWorldNeedsUpdate) obj3D.updateMatrixWorld();
        var geometry = obj3D.geometry;
        // If current is not a geometry (THREE.Geometry), proceed to the next one
        if (geometry === undefined) return null;
        // If this object is already bounding box, then use it
        if (geometry.boundingBox) { 
            var workableBox = geometry.boundingBox.clone();
            // Move the resulting bounding box to the position of the object itself
            workableBox.applyMatrix4(obj3D.matrixWorld);
            if (box === null) {
                box = workableBox;
            } else {
                box.union(workableBox);
            }
        // If there is no bounding box for current object - creating
        } else {
            var workableGeometry = geometry.clone();
            // Move the resulting geometry in the position of the object itself
            workableGeometry.applyMatrix(obj3D.matrixWorld);
            // Calculate the bounding box for the resulting geometry
            workableGeometry.computeBoundingBox();
            if (box === null) {
                box = workableGeometry.boundingBox;
            } else {
                box.union(workableGeometry.boundingBox);
            }
        }
    });
    return box;
}

5 IF conditions - it is certainly not an example of good code, but what to do, better yet I have not worked out? :)

This is a really old thread. Nowadays you can just new new THREE.Box3().setFromObject(object3d)

I will try this method, thanks!

No problem. I went through this realization a few months ago myself: https://github.com/danielribeiro/three-hub/commit/859f148349ca64ede9ee224d55ad2ea3f51c0da0#diff-0dad6abd7a4801d561b83deddedc1baa

Was this page helpful?
0 / 5 - 0 ratings