Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BoundingBox of a compounded Object3D object? #581

Closed
roundrobin opened this issue Sep 26, 2011 · 15 comments
Closed

BoundingBox of a compounded Object3D object? #581

roundrobin opened this issue Sep 26, 2011 · 15 comments
Labels

Comments

@roundrobin
Copy link

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

@mrdoob
Copy link
Owner

mrdoob commented Sep 26, 2011

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.

@roundrobin
Copy link
Author

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.

@mrdoob
Copy link
Owner

mrdoob commented Sep 26, 2011

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.

@roundrobin
Copy link
Author

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

@richardcarhart
Copy link

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);
}

@NickLarsen
Copy link

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;
}

@mrdoob
Copy link
Owner

mrdoob commented Feb 24, 2013

@NickLarsen Looks good!

@PanChan
Copy link

PanChan commented Jun 18, 2013

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 ?

@WestLangley
Copy link
Collaborator

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

@NickLarsen
Copy link

@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.

@PanChan
Copy link

PanChan commented Jun 19, 2013

@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!

@asg-3d
Copy link
Contributor

asg-3d commented Nov 12, 2013

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? :)

@danielribeiro
Copy link
Contributor

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

@asg-3d
Copy link
Contributor

asg-3d commented Nov 12, 2013

I will try this method, thanks!

@danielribeiro
Copy link
Contributor

No problem. I went through this realization a few months ago myself: danielribeiro/three-hub@859f148#diff-0dad6abd7a4801d561b83deddedc1baa

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

8 participants