-
Notifications
You must be signed in to change notification settings - Fork 165
Detail Culling
Distant bodies culled | Body comes closer | Body detail increases | Body detail level increase more |
SceneJS supports detail culling via a special frustum/lod
node type, 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 frustum/lod
enables one of its children at any instant in order to show the appropriate level of detail based on the current projected 2D canvas size of the boundary.
The frustum/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.
The frustum/lod
node encloses its child nodes in a 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, when between the second and third thresholds, the second child is enabled, and so on.
An unlimited number of child nodes and size thresholds are supported.
By default, all of the children are disabled when the bounding box falls outside the view frustum, but using the optional frustumCull
property we can disable that behaviour in order to 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.
Example:
someNode.addNode({
type: "frustum/lod",
// World-space axis-aligned bounding box
min: [xPos - 8, yPos - 3, zPos - 5],
max: [xPos + 8, yPos + 6, zPos + 5],
// Size thresholds, one for each child node, in ascending
// order for size, unlimited number
sizes: [
50, 250, 350 // More as required...
],
// Option to show the boundary as a wireframe box for debugging - default false
showBoundary: false,
// Option to disable all child nodes when the bounding box
// falls outside the view frustum - true by default
frustumCull: true,
// A child node for each size, in ascending order of
// detail, unlimited number
nodes: [
// Detail level #1 (lowest)
// A light blue box
{
type: "material",
color: {
r: 0.6,
g: 0.6,
b: 1.0
},
nodes: [
{
type: "translate",
x: xPos,
y: yPos,
z: zPos,
nodes: [{
type: "scale",
x: 4,
y: 3,
z: 4,
nodes: [
// Box primitive, implemented by plugin at
// http://scenejs.org/api/latest/plugins/node/prims/box.js
{
type: "prims/box"
}
]
}]
}
]
},
// Detail level #2 (middle)
// A medium-blue sphere
{
type: "material",
color: {
r: 0.5,
g: 0.5,
b: 1.0
},
nodes: [{
type: "translate",
x: xPos,
y: yPos,
z: zPos,
nodes: [{
type: "scale",
x: 1.0,
y: 0.7,
z: 1.0,
nodes: [
// Sphere primitive, implemented by plugin at
// http://scenejs.org/api/latest/plugins/node/prims/sphere.js
{
type: "prims/sphere",
radius: 5,
latitudeBands: 16, // A fairly low-rez sphere
longitudeBands: 16
}
]
}]
}]
},
// Detail level #3 (highest)
// A dark blue teapot
{
type: "material",
color: {
r: 0.3,
g: 0.3,
b: 1.0
},
nodes: [{
type: "translate",
x: xPos,
y: yPos - 2.5,
z: zPos,
nodes: [{
type: "scale",
x: 2.5,
y: 2.5,
z: 2.5,
nodes: [
// Teapot primitive, implemented by plugin at
// http://scenejs.org/api/latest/plugins/node/prims/teapot.js
{
type: "prims/teapot"
}
]
}]
}]
}
// Mode children as required..
]
});
- The
frustum/lod
node 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
frustum/lod
nodes create frustum collision bodies, and those systems are managed in a load-balanced pool. - The
frustum/lod
node actually wraps a more basicfrustum/body
node type, which creates the collision body and subscribes to it's frustum intersection status and projected 2D boundary size. Thefrustum/lod
node does the job of translating those updates into child node enables/disables. This strategy allows us to reuse thefrustum/body
to create new types of culling node.