Accurate bounding boxes

ball = loader.loadModel(“smiley”)
ball.reparentTo(render)
ball.showBounds()
print ball.getBounds()

bsphere, c (0,0,0), r 1.73205

The above snippet shows that the bounding box for the smiley is actually a sphere larger than the visible geometry, which is a sphere of radius 1. The bounding radius is √3, which means the bounds are a sphere circumscribing a cube circumscribing the actual sphere.

ball.showTightBounds()
The “tighter” bounds are in fact that cube.

A few questions:
Why does getBounds()] return an incorrect bsphere? Best case would be a bsphere of radius 1, which would be perfect. Second best would be to the circumscribing bbox. if the exact bsphere calculation is too intensive to do automatically. But … returning a bsphere circumscribing a bbox circumscribing the correct sphere??

Why does showTightBounds() not show the correct bsphere? The bbox is better than getBounds, but still not very tight. I would have expected Bounds to be the bbox and TightBounds the bpshere.

Even if TightBounds were good enough, how do I get the actual bounds? I would expect calcTightBounds() to update the NodePath with TightBounds. It doesn’t. I really don’t know what the hell it does that’s useful.

If panda3d cannot in any way get the correct bounds by itself, how do I manually do it?
I cannot setBounds() on the NodePath ball, nor does
ball.node().setBounds(BoundingSphere(Point3(0,0,0), 1))
correct the bounds of ball.

Thanks to ThomasEgi on IRC for trying to make sense of all this, BTW.

First, you need to define exactly what you mean by a “bounds”.

Panda defines the “bounds” to be a geometric bounding volume, of an arbitrary shape (but usually a sphere) that is no smaller than its enclosed geometry. By this definition, getBounds() returns an acceptable bounding volume: it is indeed no smaller than the enclosed geometry. This makes it suitable for use in culling operations and so on.

It sounds like you want to get the smallest spherical bounding volume that is no smaller than its enclosed geometry. This is actually very difficult to compute in general, unless you happen to know that the enclosed geometry is spherical. Panda, of course, doesn’t know that in general, because it’s not true in general.

Note, however, that getTightBounds() returns the smallest axis-aligned box that is no smaller than its enclosed geometry. Thus, it satisfies its definition as a “tight” bounds, because you will not find a tighter bounding volume that is also a box. It doesn’t return a spherical bounds, though, as you observed.

Panda doesn’t bother going through all the trouble it would take to compute a tight spherical bounds, because the loose bounds that it computes is good enough. The extra performance gain you’d get for having a tighter culling bounds isn’t worth the effort it would take to compute it.

If you really wanted to override the bounding volume, you could do so with:

ball.node().setBounds(BoundingSphere(...))
ball.node().setFinal(1)

The “final” means that the bounding volume you are setting is the final, authoritative bounding volume, and the the bounding volumes Panda finds at lower levels shouldn’t contribute.

The other way to override the bounding volume, without setting the “final” attribute, is to go all the way to the bottom, where the geometry actually resides. You can set a bounding volume on the individual Geom, within the GeomNode. This will then propagate upwards in the normal way.

David

Perhaps I should have explained what I was using this for. I am trying to enable click-and-drag selection of objects in 3d.

Originally, (ignoring a little bit of advice) I tried creating 4 collision planes in a pyramid and detected collision with all 4 of them. After working the kinks out, this worked nearly perfectly, and was usually only off by a pixel or two from the visual geometry.

Now I’m changing it to use a BoundingHexahedron and the method contains() to check if anything is touching or wholly inside the area.


Anyway, your first suggestion did not work. It did nothing, as far as I could tell. Clicks within the original/large bsphere still registered.
ball.node().setBounds(…)
ball.node().setFinal(1)

The following line worked better:
ball.getChild(0).node().setBounds(…)

Now it only counts clicks within the bbox/TightBounds. Thjat’s mildly annoying, but I can live with it.


All the precise definitions you gave were helpful in understanding what was going on. Could they be added to the API ref. somewhere?

Well, OK. Calling setFinal() is only a cue to Panda’s cull and collision traversals to respect the new bounding volume on all children nodes. It doesn’t affect any custom code you might have that calls node.getBounds() to get the bounding volume directly; that bounding volume of the child node will still report itself to be the size that Panda computed it, unless you explicitly replace it (as you did in the second example).

The API ref doesn’t lend itself well to introductory concepts like this, since there’s not really a place to put them. The API ref is only a loose collection of descriptions of individual classes and methods, and there’s no guarantee that anyone browsing it will read it in any particular order, so there’s nowhere to put a “read this first” kind of text.

However, this sort of thing would go well in the Manual, which is exactly suited for this kind of instruction. However, we don’t yet have a chapter or even a page about bounding volumes in the Manual at all. Would you like to write such a thing?

David

Well, I tried. I have no way of knowing if it will be helpful to anyone but me. :laughing:

Excellent, thanks!

Minor point: in fact, there is a method called getTightBounds(). It returns the tuple (pointA, pointB). It’s just a simple wrapper around calcTightBounds().

David

Sorry for the thread resurrection but its the most recent one that relates to my question. How can I get the dimensions of the tight bounding box as used in showTightBounds?

b3=np.getTightBounds()
dimensions=b3[1]-b3[0]

That just gets the length of the bounding box doesn’t it? I’m also interested in the height and width of the bounding box.

getTightBounds() returns 2 Point3’s, the min & max bounds. So, by getting the 3 components vector between those points, you’ll get the dimensions, not just the length. That vec’s X, Y, Z are length, width, and height.

Ah, I see now. For some reason I was operating under the assumption that the bounding box is aligned to the longest length of the nodepath. Thanks ynjh_jo.

Hey,
I have the same problem like the guy with the ball. My models have bounds and tightbounds much more bigger than my model is. I am using PandAI and if i am adding obstacles, PandAI uses those bounds to calculate where to go and where not to go.
In my scenario this is really a big problem, because normally you can walk through it, but now you can’t because the bounds are twice that big than necessary.

i tried that

self.getModel().node().setBounds(BoundingSphere(Point3(0,0,0), 1))
self.getModel().node().setFinal(True)

but this doesn’t work. I can not make radius smaller, i am only able to make it bigger, but that of course does not help.