SceneJS Visibility and Detail Culling
|Detail culling demo||Visibility culling demo|
SceneJS supports detail culling via the
cull/detail node, which sets up an axis-aligned bounding box around its child nodes. Each child provides a different level of detail for the object within the boundary, and the
cull/detail enables one of its children at any instant in order to show the appropriate detail level for the current projected 2D canvas size of the boundary.
cull/body node can be configured to disable all its children when the boundary falls outside the view frustum. This is an optional configuration because the node might potentially be used to switch detail for non-visible objects, such as sound sources, which could influence the scene even when they fall outside the frustum. Note that the node disables all children at the lowest level of detail, effectively working as a sort of distance culling.
Internally, culling is distributed across multiple culling engines, each running in its own web worker. This attempts to make culling responsive, while preventing it from starving the main rendering thread.
Creating a detail-switched object
cull/detail node encloses its child nodes in an axis-aligned World-space bounding box and enables the appropriate child for the box’s current projected 2D canvas size.
As shown in the example below, we configure the node with a 2D size threshold for each child node, given in property
sizes. When the boundary’s projected size falls below the first of these thresholds, then no child will be enabled. When the projected size is between the first and second thresholds, the first child is enabled, then when between the second and third thresholds, the second child is enabled, and so on.
You can have an unlimited number of child nodes and size thresholds.
By default, all of the children are disabled when the bounding box falls outside the view frustum, but as mentioned above, we can use the optional
frustumCull property to disable that behaviour and cull the children solely on the projected box size, which actually works regardless of which direction the box is in with regard to the viewing direction. This is useful for disabling distant sound effects etc.
- Boundaries can’t be transformed yet - they are fixed in World-space.
- Boundaries don’t automatically fit their child nodes. That’s because they might enclose things for which we might not be able to automatically determine the boundaries of, such as sound. It’s up to the scene definer (human, generator or plugin) to keep track of the boundaries of things, which seemed a reasonable tradeoff to reduce performance and complexity.
Here’s some details on the internals, just in case you’re curious how it works:
cull/detailnode is implementated by this custom node plugin.
- For performance, culling is distributed across multiple culling engines, each running within its own worker thread. Each of those workers is proxied by a system in which the
cull/detailnodes create frustum collision bodies, and those systems are managed in a load-balanced pool.
cull/detailnode actually wraps a more basic
cull/bodynode type, which creates the collision body and subscribes to its frustum intersection status and projected 2D boundary size. The
cull/detailnode does the job of translating those updates into child node enables/disables. This strategy allows us to reuse the
cull/bodyfor internal workings of new types of culling node in future.
cull/visibilityboundaries to be defined in Model-space, where they are transformed by parent transform nodes
- Other types of boundary shape, such as spherical
- Each culling engine simply iterates over a list of bodies - improve their performance by organising the bodies in KD-trees
- Issues tagged ‘culling’