Three.js: BoundingBox eines zusammengesetzten Object3D-Objekts?

Erstellt am 26. Sept. 2011  ·  15Kommentare  ·  Quelle: mrdoob/three.js

Hallo Leute,

Ich habe eine Object3D-Instanz, die eine CubeGeometry und eine TextGeometry enthält. Meine Frage: Es ist möglich, die zu bekommen
Begrenzungsrahmen dieser zusammengesetzten Geometrien? Ich frage dies, weil ich gesehen habe, dass die Object3D-Klasse keine BoundingBox-Methode hat
und ich habe keinen Ansatz, um es für alle Objekte zu berechnen, die im Object3D-Container enthalten sind.

Meine Idee war es, die Kamera abhängig vom Centeroid der Object3D-Container zu zentrieren, und deshalb muss ich die BoundingBox kennen.

Grüße Roundrobin

Question

Hilfreichster Kommentar

Ich bin auf der Suche nach dem gleichen Ding darauf gestoßen und habe mich darauf festgelegt:

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

Alle 15 Kommentare

Object3D nicht über eine Methode zur Berechnung des Begrenzungsrahmen, aber Geometry tut .

Mit diesem aus dem Weg, brauchen Sie nur folgen diesen .

danke bisher. Vielleicht frage ich falsch, meine Absicht war es, den Begrenzungsrahmen der beiden Objekte zu bekommen. Ich weiß, wie man den Begrenzungsrahmen für eine Geometrie berechnet, aber wenn ich zusammengesetzte 3D-Objekte habe, wie ich den Begrenzungsrahmen berechnen kann, zum Beispiel für zwei Würfel. Oder ist es notwendig, die Objekte vorher zu einer Geometrie zusammenzuführen?

Ich hoffe du hast meinen Standpunkt verstanden :) es ist schwer zu erklären.

Aha. Ich denke, der einzige Weg im Moment ist, alle Begrenzungsrahmen zu vergleichen und einige max() und min() s mit allen Werten zu machen.

okay danke. Ich werde meine Lösung veröffentlichen, wenn ich erfolgreich bin

Hier ist meine Lösung. Übergeben Sie das Objekt einfach an diese Funktion, und es durchsucht die untergeordneten Objekte, um die Höhe / Breite des Objekts zu berechnen und dem Objekt eine Eigenschaft für Höhe und Breite zuzuweisen.


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


Ich bin auf der Suche nach dem gleichen Ding darauf gestoßen und habe mich darauf festgelegt:

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 Sieht gut aus!

Ich habe genau das gleiche Problem und die gleiche Idee wie Roundrobin vor zwei Jahren. Die Lösung von @NickLarsen sieht wirklich gut aus, wie @mrdoob sagte, aber es gibt ein großes Problem ... Ich werde versuchen, es zu erklären.

In meiner Szene gibt es immer ein Object3D, das alle Geometrien enthält. Zum Beispiel habe ich 8 Kugeln mit unterschiedlichem Radius und unterschiedlicher y-Koordinate. Sie befinden sich alle bei x = 0 und z = 0.
Dann habe ich versucht, die gesamte Boundingbox mit der Funktion von NickLarsen zu berechnen, aber das Ergebnis war sehr seltsam. Um den Fehler zu finden, habe ich alle einzelnen Begrenzungsrahmen an der Konsole protokolliert:

({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}})

Wie Sie sehen können, werden die Begrenzungsrahmen immer im lokalen Koordinatensystem der einzelnen Kugel berechnet. Und wenn Sie sie vereinen, macht es keinen Sinn! Wie kann ich die Boundingbox in Weltkoordinaten erhalten, um die reale Boundingbox meines Object3D zu erhalten?

Im Zweig r.59dev finden Sie unter Box3.setFromObject( object ) .

@PanChan Sie müssen Ihre Transformationen versickern, bevor Sie dies ausführen, und es wird wie beabsichtigt funktionieren. Bei meiner tatsächlichen Verwendung klone ich die Geometrie für jedes Objekt und wende die Transformationen darauf an, bevor ich den Begrenzungsrahmen berechne. Sie können meine tatsächliche Implementierung hier sehen . Ich bin ziemlich noob, wenn es um dieses Zeug geht, also nimm meine Implementierung mit einer guten Dosis Skepsis.

@ NickLarsen Ich habe eine andere Lösung gefunden, die zu funktionieren scheint. Nachdem ich den Boundingbox berechnet habe, übersetze ich ihn in das Weltsystem:

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

Ich weiß nicht, ob es eine gute Lösung ist, aber es funktioniert vorerst. Denke ich warte auf die neue Revision mit der professionellen Lösung;) Danke für die Erklärung!

Mit der @ NickLarsen- Lösung in meinem Projekt bin ich eine etwas optimierte Berechnung für Fälle, in denen der Begrenzungsrahmen des Objekts bereits vorhanden ist, und daher ist eine erneute Berechnung nicht erforderlich.

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 WENN Bedingungen - es ist sicherlich kein Beispiel für guten Code, aber was tun, besser noch habe ich nicht ausgearbeitet? :) :)

Dies ist ein wirklich alter Thread. Heutzutage können Sie nur neue new THREE.Box3().setFromObject(object3d)

Ich werde diese Methode ausprobieren, danke!

Kein Problem. Ich habe diese Erkenntnis vor einigen Monaten selbst durchlaufen: https://github.com/danielribeiro/three-hub/commit/859f148349ca64ede9ee224d55ad2ea3f51c0da0#diff -0dad6abd7a4801d561b83deddedc1baa

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen