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
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
Comentários muito úteis
Eu me deparei com isso procurando a mesma coisa e acabei decidindo por isso: