Three.js: BoundingBox de um objeto Object3D composto?

Criado em 26 set. 2011  ·  15Comentários  ·  Fonte: mrdoob/three.js

Ola pessoal,

Eu tenho uma instância Object3D, que inclui um CubeGeometry e um TextGeometry. Minha pergunta: é possível obter o
caixa delimitadora dessas geometrias compostas? eu pergunto isso porque vi que a classe Object3D não tem um método boundingBox
e eu não tenho nenhuma abordagem para calculá-lo para todos os objetos incluídos no recipiente Object3D.

Minha ideia era centralizar a câmera dependendo do centroide dos contêineres Object3D e, portanto, eu tenho que conhecer o boundingBox.

Saudações, roundrobin

Question

Comentários muito úteis

Eu me deparei com isso procurando a mesma coisa e acabei decidindo por isso:

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

Todos 15 comentários

Object3D não tem um método para calcular a caixa delimitadora, mas Geometry tem .

Com isso resolvido, você só precisa seguir isso .

obrigado até agora. talvez eu pergunte errado, minha intenção era pegar a caixa delimitadora dos dois objetos. Eu sei como calcular a caixa delimitadora para uma geometria, mas quando tenho objetos 3D compostos, como posso calcular a caixa delimitadora, por exemplo, de dois cubos. Ou é necessário mesclar os objetos anteriores em uma geometria?

Espero que você tenha entendido :) é difícil de explicar.

Eu vejo. Eu acho que a única maneira agora é comparar todas as caixas delimitadoras e fazer max() e min() s com todos os valores.

ok obrigado. Vou postar minha solução se tiver sucesso

Aqui está minha solução. Simplesmente passe o objeto para esta função e ela examinará seus filhos para calcular a altura / largura do objeto e atribuir uma propriedade de altura e largura ao objeto.


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


Eu me deparei com isso procurando a mesma coisa e acabei decidindo por isso:

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 Parece bom!

Tenho exatamente o mesmo problema e a mesma ideia que o roundrobin de dois anos atrás. A solução do @NickLarsen parece muito boa, como o @mrdoob disse, mas há um grande problema ... Vou tentar explicar.

Na minha cena, há sempre um Object3D que contém todas as geometrias. Por exemplo, tenho 8 esferas com raios diferentes e coordenadas y diferentes. Eles estão todos localizados em x = 0 e z = 0.
Então tentei calcular toda a caixa delimitadora com a função de NickLarsen, mas o resultado foi muito estranho. Para encontrar o erro, registrei todas as caixas delimitadoras individuais no 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}})

Como você pode ver, as caixas delimitadoras são sempre calculadas no sistema de coordenadas local da esfera única. E quando você os une, não faz sentido! Como posso obter a caixa delimitadora em coordenadas mundiais para obter a caixa delimitadora real do meu Object3D?

No branch r.59dev, consulte Box3.setFromObject( object ) .

@PanChan você precisa filtrar suas transformações antes de executar isso e funcionará conforme o esperado. Em meu uso real disso, eu clono a geometria para cada objeto e aplico as transformações a ele antes de calcular a caixa delimitadora. Você pode ver minha implementação real aqui . No entanto, sou muito novato quando se trata dessas coisas, então aceite minha implementação com uma boa dose de ceticismo.

@NickLarsen Encontrei outra solução que parece funcionar. Depois de calcular a caixa delimitadora, eu traduzo para o sistema mundial:

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

Não sei se é uma boa solução, mas funciona por enquanto. Acho que estou esperando a nova revisão com a solução profissional;) ​​Obrigado pela explicação!

Usando a solução @NickLarsen em meu projeto estou otimizando um pouco o cálculo para os casos em que a caixa delimitadora do objeto já existe e, portanto, não é necessário calculá-la novamente.

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 Condições IF - certamente não é um exemplo de bom código, mas o que fazer, melhor ainda, não resolvi? :)

Este é um tópico muito antigo. Hoje em dia você pode apenas novo new THREE.Box3().setFromObject(object3d)

Vou tentar esse método, obrigado!

Sem problemas. Eu mesmo passei por essa constatação há alguns meses: https://github.com/danielribeiro/three-hub/commit/859f148349ca64ede9ee224d55ad2ea3f51c0da0#diff -0dad6abd7a4801d561b83deddedc1baa

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

yqrashawn picture yqrashawn  ·  3Comentários

filharvey picture filharvey  ·  3Comentários

donmccurdy picture donmccurdy  ·  3Comentários

akshaysrin picture akshaysrin  ·  3Comentários

fuzihaofzh picture fuzihaofzh  ·  3Comentários