CompositePrimitive groups primitives together to create hierarchies of primitives for layering, and aggregation/deaggregation.
Efficient rendering is achieved because primitives in the same composite are put into a bounding volume hierarchy (BVH), which enables efficient culling using view frustum and horizon culling.
Technical Details: The BVH is created using a surface area heuristic. The BVH is efficiently updated when a primitive in a composite changes position based on an algorithm in the 2007 paper Automatic Creation of Object Hierarchies for Ray Tracing of Dynamic Scenes. Removing primitives from a composite, and thus the BVH, is efficient and described in the Deletion in Bounding Volume Hierarchies blog post. Horizon culling is also explained in the Horizon Culling blog post.
Layering is showing/hiding groups of primitives in the same general area based on display conditions. This is commonly used to show more detailed primitives as the camera becomes closer. Aggregation and deaggregation extend the layering concept so it appears that primitives expand into more primitives or collapse into less. This is frequently done based on distance to a reference point or camera altitude as the following example demonstrates.
For efficient display condition evaluation, primitives that share the same condition can be combined using a composite primitive. For example, consider primitives with two different constraints:
1,000 models with the same camera altitude constraint of [0, 1,000] meters
1 model with a camera altitude constraint of [1,000 to 10,000] meters
When the camera zooms out, 1 model represents 1,000 models.
If these primitives are added to the primitive manager individually, 1,001 primitives need to be visited when the scene is rendered, regardless of camera position. This is grossly inefficient once the camera's altitude is above 1,000 meters. The CPU will spin and cache miss for nothing.
If the 1,000 models are added to a composite primitive instead, only 2 primitives need to be visited in this case (1 for the composite and 1 for the model that is rendered). This is shown in the following code sample:
AltitudeDisplayCondition closeCondition = new AltitudeDisplayCondition(0.0, 1000.0); AltitudeDisplayCondition farCondition = new AltitudeDisplayCondition(1000.0, 10000.0); CompositePrimitive closePrimitives = new CompositePrimitive(); closePrimitives.setDisplayCondition(closeCondition); closePrimitives.add(model1); closePrimitives.add(model2); // ... closePrimitives.add(model1000); SceneManager.getPrimitives().add(closePrimitives); // Add composite of primitives to manager aggregateModel.setDisplayCondition(farCondition); SceneManager.getPrimitives().add(aggregateModel); // Add single primitive to manager
Since composites are primitives themselves, you can add composites to composites to build hierarchies that efficiently find and render the correct primitives based on display conditions.