Reputation: 205
So I am having this code:
computeCarBoundingBox(mesh);
mesh.rotation.x = this.rotationVal[ 0 ];
mesh.rotation.y = this.rotationVal[ 1 ];
mesh.rotation.z = this.rotationVal[ 2 ];
Where I try to compute a bounding box for a mesh, if I compute it after rotation look like this:
If I compute it after the rotation look like this:
My compute bounding box function is this:
function computeCarBoundingBox(mesh){
var box = new THREE.Box3().setFromObject(mesh);
var boundingBoxHelper = new THREE.Box3Helper( box, 0xffff00 );
scope.carBoundingBox =boundingBoxHelper;
scene.add(scope.carBoundingBox);
console.log(box.min); // x, y, and z are all Infinity.
console.log(box.max); // x, y, and z are all -Infinity.
}
I do have a geometry. This is a part of my code :
this.loadCar = function ( carsVector,carName,roadName ) {
if(carName=='veyron')
{
var index = 0;
}
else if(carName=='F50')
{
var index = 1;
}
else
{
var index = 2;
}
console.log("Selected car name:"+carName);
var carLoader = new THREE.BinaryLoader();
carLoader.load( carsVector[Object.keys(carsVector)[index]].url, function( geometry ) {
geometry.sortFacesByMaterialIndex();
console.log("url--->"+carsVector[Object.keys(carsVector)[index]].url);
var materials = [];
this.scaleVal = carsVector[ Object.keys(carsVector)[index] ].scale * 1;
if(roadName =='road01'){
this.positionVal = carsVector[ Object.keys(carsVector)[index] ].position_r1;
}
else if(roadName=='road02'){
this.positionVal = carsVector[ Object.keys(carsVector)[index] ].position_r2;
}
this.rotationVal = carsVector[ Object.keys(carsVector)[index] ].init_rotation;
for ( var i in carsVector[ Object.keys(carsVector)[index] ].materialsMap ) {
materials[ i ] = carsVector[ Object.keys(carsVector)[index] ].materialsMap[ i ];
}
createObject(geometry,materials);
});
return scope.carMesh;
}
// internal helper methods
function createObject ( geometry, materials ) {
scope.carGeometry = geometry;
scope.carMaterials = materials;
createCar();
};
function createCar () {
console.log("CREATE CARRRRRRRRRRRRRRRRR");
if ( scope.carGeometry ) {
var carMaterial = new THREE.MeshFaceMaterial( scope.carMaterials );
var mesh = new THREE.Mesh( scope.carGeometry, carMaterial );
mesh.scale.x = mesh.scale.y = mesh.scale.z = this.scaleVal;
mesh.position.set( this.positionVal[0], this.positionVal[1], this.positionVal[2]);
mesh.rotation.x = this.rotationVal[ 0 ];
mesh.rotation.y = this.rotationVal[ 1 ];
mesh.rotation.z = this.rotationVal[ 2 ];
this.carMesh = mesh;
//
computeCarBoundingBox(mesh);
console.log("This car mesh"+this.carMesh);
addShadows();
scene.add(this.carMesh);
//this.carBoundingBox.rotation.x =this.r[0];
//this.carBoundingBox.rotation.y = this.r[1];
//this.carBoundingBox.rotation.z = this.r[2];
//scene.add( this.carBoundingBox );
}
if ( scope.callback ) {
scope.callback(this.carMesh);
}
}
Upvotes: 5
Views: 4568
Reputation: 501
I run into this problem recently. Thanks to @Wolfgang Fahl 's resolution. Tt’s the right direction, but when I was doing it, I found something was wrong. When the mesh have rotation effection. the box is still bigger than original one. So you need to remove rotation before create BoxHelper, then add rotation back.
static adjustRelativeTo(mesh, toMesh) {
toMesh.updateMatrixWorld(); // important !
mesh.applyMatrix4(new THREE.Matrix4().copy( toMesh.matrixWorld ).invert());
}
addBoundingBox(mesh, toMesh) {
// remove rotation
let rotate = mesh.rotation.clone();
mesh.rotation.set(0, 0 , 0);
let box = new THREE.BoxHelper( mesh, 0xffff00);
// apply to parent matrix
adjustRelativeTo(box, toMesh);
toMesh.add(box);
// 然后再把旋转加上
mesh.rotation.set(rotate.x, rotate.y, rotate.z);
}
Upvotes: 1
Reputation: 15604
These are the methods I'm using in my project where I add the bounding boxes after rotation. If you don't rotate first you don't need the adjustRelativeTo step see e.g. https://codepen.io/seppl2019/pen/zgJVKM
class ChildPart {
constructor(mesh) {
this.mesh=mesh;
this.boxwire=null;
}
// add my bounding box wire to the given mesh
addBoundingBoxWire(toMesh) {
var boxwire = new THREE.BoxHelper(this.mesh, 0xff8000);
this.boxwire=boxwire;
ChildPart.adjustRelativeTo(boxwire,toMesh);
toMesh.add(boxwire);
}
static adjustRelativeTo(mesh,toMesh) {
//logSelected("adjusting toMesh",toMesh);
//logSelected("beforeAdjust",this.mesh);
toMesh.updateMatrixWorld(); // important !
mesh.applyMatrix(new THREE.Matrix4().getInverse(toMesh.matrixWorld));
//logSelected("afterAdjust",this.mesh);
}
}
Upvotes: 1
Reputation: 17596
That's how .setFromObject()
works, when object is wide and when you rotate it, its box will be bigger, as it's world-axis-aligned:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 5, 5);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 0.75);
light.position.set(-10, 10, -10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.25));
scene.add(new THREE.GridHelper(10, 10));
var geometry = new THREE.BoxGeometry(2, 1, 3);
geometry.translate(0, 0.5, 0);
var mesh1 = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({
color: "gray"
}));
mesh1.position.x = -2.5;
scene.add(mesh1);
var mesh2 = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({
color: "aqua"
}));
mesh2.position.x = 2.5;
mesh2.rotation.y = THREE.Math.degToRad(45);
scene.add(mesh2);
var bbox1 = new THREE.Box3().setFromObject(mesh1);
var bbox2 = new THREE.Box3().setFromObject(mesh2);
var bhelp1 = new THREE.Box3Helper(bbox1, 0xffff00);
scene.add(bhelp1);
var bhelp2 = new THREE.Box3Helper(bbox2, 0xff00ff);
scene.add(bhelp2);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/93/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
Upvotes: 0
Reputation: 10177
Alright I have two theories, and no certain answer. sorry!
1) It is possible for meshes to be without geometry. Does your mesh have a geometry? If not the code called from setFromObject will fail. (expandByPoint will never be called and min and max will remain at Infinity since the previous makeEmpty-call).
2) Seeing how deeply dependent that recursive "expandByOject" code is on scope and this
, I would try adding parenthesis to your new-operator var box = (new THREE.Box3()).setFromObject(mesh);
It's a bit of a shot in the dark, but perhaps the scope is never properly set.
Sorry for not taking the time and testing things out first.
Upvotes: -1