See Javadoc
A bounding volume is used for object culling before rendering of a scene graph, and determines if a given object is within the camera's field of view.
For complex objects, such as a human figure, determining if the object is within viewable space can be a very computationally expensive exercise, since tests would have to be done against every polygon within the model. Therefore, an invisible, mathematically simple volume such as a sphere or a cube is placed around the model in such a way as to contain all geometry within the complex model. When culling is performed on the scene graph, this simple object is tested for visibility before the geometry it contains is considered for rendering. If the simple object fails the test (i.e., is not within view of the camera), then the complex object and all of its children are discarded from the potentially renderable set of objects within the scene graph, saving processor power.
jME defines the BoundingVolume as an abstract class that has subclasses of BoundingSphere, BoundingBox and OrientedBoundingBox. Creation of the bounding volume is the same no matter what type used.
NOTE: You should only set the bounding volume for Geometry using setModelBounds as the world bounds are generated automatically during each update.
Every Spatial contains a BoundingVolume for determining visibility, this is the World Bounds and may represent anything from the bounding surrounding a single model's vertices, to a bounding surrounding multiple models (and their corresponding boundings).
To set the BoundingVolume of a Geometry object, use the object's setModelBounds method passing in the concrete class you wish to use. Next, call updateModelBounds to have the bounding volume automatically calculated for you. You can also pre-calculate the boundings if you wish. Calling updateModelBounds will in turn call the BoundingVolume's computeFromPoints method which finds the minimal bounding that will contain all the vertices of the Geometry.
After the model's bounding is calculated updateWorldBound should be called. This will set the world bounding of the Geometry, which transforms the bounding into the world space.
When calling updateWorldBound on the root node of the scene graph this will merge the boundings up the tree.
What BoundingVolume type should I use?
This depends on the shape of the model you wish to encapsulate. If it's “bulbous” and round you might use a BoundingSphere, if it's long you might use a BoundingBox. You'll need to determine this on a case by case basis. Generally, BoundingSphere calculations are faster.
Frustum culling allows for significant speed increases, but to make this as efficient as possible, boundings are maintained at all levels of the scene graph to allow culling of entire branches in a single operation. The creation of these bounds are accomplished automatically in Node's updateWorldBound method. During this method call, the BoundingVolume's maintained by the children of a Nodes are merged into a single bounding that is applied to the Nodes. This operation propogates from the bottom up, allowing the user to set the Model bounds of the Geometry in the scene and have the scene graph optimize itself. During a merge of two boundings, a third bounding is created that minimally contains the two bounding volumes. Two different boundings can be merged, and different combinations result in a different bounding type:
BoundingBox + BoundingSphere = BoundingBox
BoundingBox + OrientedBoundingBox = OrientedBoundingBox
BoundingSphere + BoundingBox = BoundingSphere
BoundingSphere + OrientedBoundingBox = OrientedBoundingBox
OrientedBoundingBox + BoundingBox = OrientedBoundingBox
OrientedBoundingBox + BoundingSphere = OrientedBoundingBox
As you can see, order of the merge can play a part in what the result can be.
The merge will create the bounding for each element of the graph, and transform them into world space. This will allow for the fast culling operations that we desire.
The BoundingVolumes also allow us to do fast intersection tests. This includes both Picking and Collisions. The picking is nothing more than a test of intersection with a Ray. While collisions are dependant on intersection with a second BoundingVolume. Simple intersection tests can come in handy for some applications, but if you need complete collision detection you should make use of the capabilities built into Spatial. This functionality makes use of the BoundingVolumes to propogate intersection tests down the tree.
See Picking and Collisions
The BoundingVolume class provides a number of convience methods. The transform method allows you to rotate, translate and scale a bounding. distanceTo provides a value for the distance from a point to the center of the bounding, while distanceToEdge will provide the distance from a point to the edge of a bounding. That is, the closest point that would fall on the bounding's surface is calculated and the distance from this point to the supplied point is calculated.
Sphere s = new Sphere("Our Model", 20, 20, 5); s.setModelBound(new BoundingSphere()); s.updateModelBound();
Sphere s = new Sphere("Our Model", 20, 20, 5); s.setModelBound(new BoundingSphere()); s.setLocalTranslation(new Vector3f(10,0,5)); s.updateModelBound(); //need to make sure the scenegraph has the latests boundings root.updateWorldBound(); Ray r = new Ray(origin, direction); System.out.println("Does the Ray hit? " + s.getWorldBound().intersects(r));
Sphere s = new Sphere("Our Model", 20, 20, 5); s.setModelBound(new BoundingSphere()); s.setLocalTranslation(new Vector3f(10,0,5)); s.updateModelBound(); Box b = new Box("Box", min, max); b.setModelBound(new BoundingBox()); b.setLocalTranslation(new Vector3f(0, 5, 5)); b.updateModelBound(); //need to make sure the scenegraph has the latests boundings root.updateWorldBound(); System.out.println("Do they hit? " + s.getWorldBound().intersects(b.getWorldBound()));