Three.js: BoundingBox d'un objet Object3D composé?

Créé le 26 sept. 2011  ·  15Commentaires  ·  Source: mrdoob/three.js

Bonjour gars,

J'ai une instance Object3D, qui comprend un CubeGeometry et un TextGeometry. Ma question: il est possible d'obtenir le
boîte englobante de ces géométries composées? Je demande cela, car j'ai vu que la classe Object3D n'a pas de méthode boundingBox
et je n'ai aucune approche pour le calculer pour tous les objets inclus dans le conteneur Object3D.

Mon idée était de centrer la caméra en fonction du centeroid des conteneurs Object3D et donc je dois connaître le boundingBox.

Salutations Roundrobin

Question

Commentaire le plus utile

Je suis tombé sur ceci à la recherche de la même chose et j'ai fini par m'installer sur ceci:

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

Tous les 15 commentaires

Object3D n'a pas une méthode de calcul de la zone de délimitation, mais Geometry - t .

Avec cela à l'écart, il vous suffit de suivre ceci .

merci jusqu'ici. peut-être que je me trompe, mon intention était d'obtenir la boîte englobante des deux objets. Je sais comment calculer la boîte englobante pour une géométrie, mais quand j'ai un objet 3D composé, comment je peux calculer la boîte englobante, par exemple de deux cubes. Ou est-il nécessaire de fusionner les objets avant en une seule géométrie?

j'espère que vous avez compris mon point :) c'est difficile à expliquer.

Je vois. Je suppose que le seul moyen pour le moment est de comparer toutes les boîtes englobantes et de faire quelques max() et min() s avec toutes les valeurs.

d'accord merci. Je publierai ma solution si je réussis

Voici ma solution. Passez simplement l'objet à cette fonction et il examinera ses enfants pour calculer la hauteur / largeur de l'objet et attribuer une propriété de hauteur et de largeur à l'objet.


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


Je suis tombé sur ceci à la recherche de la même chose et j'ai fini par m'installer sur ceci:

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 a l'air bien!

J'ai exactement le même problème et la même idée que roundrobin, il y a deux ans. La solution de @NickLarsen a l' air vraiment bien, comme l' a dit

Dans ma scène, il y a toujours un Object3D qui contient toutes les géométries. Par exemple, j'ai 8 sphères avec un rayon différent et une coordonnée y différente. Ils sont tous situés à x = 0 et z = 0.
Ensuite, j'ai essayé de calculer toute la zone de délimitation avec la fonction de NickLarsen, mais le résultat était très étrange. Pour trouver l'erreur, j'ai enregistré toutes les boîtes de délimitation uniques sur la 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}})

Comme vous pouvez le voir, les boîtes englobantes sont toujours calculées dans le système de coordonnées local de la sphère unique. Et quand vous les unissez, cela n'a aucun sens! Comment puis-je obtenir la boîte englobante en coordonnées mondiales pour obtenir la vraie boîte englobante de mon Object3D?

Dans la branche r.59dev, voir Box3.setFromObject( object ) .

@PanChan vous devez percoler vos transformations avant de l'exécuter et cela fonctionnera comme prévu. Dans mon utilisation réelle de cela, je clone la géométrie de chaque objet et lui applique les transformations avant de calculer la boîte englobante. Vous pouvez voir ma mise en œuvre réelle ici . Je suis assez noob quand il s'agit de ce genre de choses, alors prenez ma mise en œuvre avec une bonne dose de scepticisme.

@NickLarsen J'ai trouvé une autre solution qui semble fonctionner. Après avoir calculé la boîte englobante, je la traduis dans le système mondial:

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

Je ne sais pas si c'est une bonne solution, mais ça marche pour le moment. Je pense que j'attends la nouvelle révision avec la solution professionnelle;) Merci pour l'explication!

En utilisant la solution

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 conditions IF - ce n'est certainement pas un exemple de bon code, mais que faire, mieux encore je n'ai pas travaillé? :)

C'est un fil vraiment ancien. De nos jours, vous pouvez simplement nouveau new THREE.Box3().setFromObject(object3d)

Je vais essayer cette méthode, merci!

Aucun problème. J'ai moi-même vécu cette réalisation il y a quelques mois: https://github.com/danielribeiro/three-hub/commit/859f148349ca64ede9ee224d55ad2ea3f51c0da0#diff -0dad6abd7a4801d561b83deddedc1baa

Cette page vous a été utile?
0 / 5 - 0 notes