Do I have to set boundingSpheres differently after init?

I create mathematical geometries. I would like to create suitable boundingSperes for these. This works if I set the boundingSphere during initialization.

_Init(params) {
   this.geometry_ = new THREE.BufferGeometry();
   this.mesh_ = new THREE.Mesh(this.geometry_, params.material);

   
   const boundingSphere = new THREE.Sphere(this.params_.boundingPosition, this.params_.width * 2);
   this.mesh_.geometry.boundingSphere = boundingSphere;
   this.mesh_.geometry.computeBoundingSphere();	 	   
}

But it would be even better if I could use the arithmetic mean of all vertices as the center of the boundingSphere. Since I can do this at the same time as creating the geometry, calculating the center of gravity of the geometry is a simple matter.
What doesn’t work is creating the boundingSphere after the init.

If I later call the exact same 3 lines as in the init just for a test:

   const boundingSphere = new THREE.Sphere(this.params_.boundingPosition, this.params_.width * 2);
   this.mesh_.geometry.boundingSphere = boundingSphere;
   this.mesh_.geometry.computeBoundingSphere();

the boundigSperes no longer work.
I quickly notice this when I turn the camera a little and then geometries disappear from view. Do I need to set boundingSpheres in a different way after init?

P.S:
I had the values ​​displayed in text fields so that I could better see what was going on.

const center = new THREE.Vector3(data.center[0], data.center[1], data.center[2]);

const boundingSphere = new THREE.Sphere(center.clone(), this.params_.width);
this.mesh_.geometry.boundingSphere = boundingSphere;
this.mesh_.geometry.computeBoundingSphere();
 
document.getElementById("testfield19").value = center.x;
document.getElementById("testfield20").value = center.y;
document.getElementById("testfield21").value = center.z;
document.getElementById("testfield25").value = this.mesh_.geometry.boundingSphere.center.x;
document.getElementById("testfield26").value = this.mesh_.geometry.boundingSphere.center.y;
document.getElementById("testfield27").value = this.mesh_.geometry.boundingSphere.center.z;

document.getElementById("testfield22").value = this.params_.width;
document.getElementById("testfield28").value = this.mesh_.geometry.boundingSphere.radius;

Top line center(xyz) testfield(19, 20, 21) and radius testfield(22).
The bottom line is the read values ​​of the boundingSphere center(xyz) testfield(25, 26, 27) and radius testfield(28).

That doesn’t even begin to agree. And if I don’t clone the center vector, the center vector is changed by the boundingSphere instead of the boundingSphere taking over the values.

If I do the whole thing at the beginning in the init, the values ​​match and my center vector and radius are not influenced by the boundingSphere. The same lines of code produce different results depending on where I execute them (init or update). The fact that my center values ​​and radius are changed by the boundingSphere when I run it in the update instead of the boundingSphere taking them over is definitely not correct.

It is hard to debug fragments of code with unknown data. When I try to reproduce it, everything works fine (overwriting the bounding sphere with custom sphere works, recalculating it afterwards also works):

var geo = object.geometry;

// calculate it automatically
geo.computeBoundingSphere();
console.log( geo.boundingSphere.center, geo.boundingSphere.radius );
// { x: 1, y: 0, z: -1 } 1.8708286933869707

// set it manually
geo.boundingSphere = new THREE.Sphere( new THREE.Vector3(2,-1,2), 3 );
console.log( geo.boundingSphere.center, geo.boundingSphere.radius );
// { x: 2, y: -1, z: 2 } 3

// calculate it automatically
geo.computeBoundingSphere();
console.log( geo.boundingSphere.center, geo.boundingSphere.radius );
// { x: 1, y: 0, z: -1 } 1.8708286933869707

// set it manually
geo.boundingSphere = new THREE.Sphere( new THREE.Vector3(4,7,-3), 12 );
console.log( geo.boundingSphere.center, geo.boundingSphere.radius );
// { x: 4, y: 7, z: -3 } 12

// calculate it automatically
geo.computeBoundingSphere();
console.log( geo.boundingSphere.center, geo.boundingSphere.radius );
// { x: 1, y: 0, z: -1 } 1.8708286933869707

Most likely you do something strange in the code.

A side note on:

I’m not sure the arithmetic mean (or the center of mass) is a good candidate for bounding sphere center… unless your geometry has well distributed vertices. Consider this example:

1 Like

I thought about making a CodePen example to reproduce this, because I agree with you completely when you say that code snippets alone limits what can be said about. In my case, the vertices are almost equidistant from each other and therefore their center of gravity is very suitable for the boundingSphere. If this were completely irregular like in your picture which one vertex is far away from the others, then I agree that the center of gravity would be a bad choice. Then I would use the average weight by their squared distances or something else that suits more.
The fact that it works for you reassures me. That might sound a bit paradoxical, but it means I know that I’m doing something wrong, which narrows down the cause. That also helps me.

1 Like

I think the problems I have with the boundingSpheres could be related, among other things, to the fact that I use a logarithmic depth buffer and have to take that into account in my own shaders. Plus, that’s not the only special feature I use. So I solved it like this:

//in my iteration loop
const cameraDirection = new THREE.Vector3();
const objectDirection = new THREE.Vector3();
this.camera.getWorldDirection(cameraDirection);
const objectPosition = this.objects[k].params_.boundingPositionCenter;
objectDirection.subVectors(objectPosition.clone(), this.camera.position); 
const distance = objectDirection.length();
objectDirection.normalize();		
const cosAlpha = objectDirection.dot(cameraDirection);
const size = this.objects[k].params_.size;	
					
if (cosAlpha < 0 && distance > size) {
	this.objects[k].params_.mesh_.visible = false;
} else {						
    this.objects[k].params_.mesh_.visible = true;
}

This is very simple but works great. I can now include the fov range of the camera to improve this so that not only objects behind the camera plane are checked, but also really close to the camera’s frustum. This is basically very similar to what a boundingSphere would do. I can still improve it, but the important thing is that it’s going very well

1 Like