ComputeBatchCulling
new ComputeBatchCulling(options : Object)GPU-driven culling for IndirectBatchedMesh with matrix-based reference positions.
Architecture
- Optimized for
IndirectBatchedMeshwith per-instance matrices - Two-pass block compaction algorithm for efficient parallel writes
- Supports both ref-position and matrix-based culling
- Per-geometry bounding sphere tests (reads from mesh geometry info)
- Writes survivor IDs for indirect instanced draw
Limitations
- Transparency is not supported: IndirectBatchedMesh does not support transparent materials. Use opaque materials only. Depth sorting is not available.
Block Compaction Algorithm
- Count Pass: Each instance atomically increments its block counter if visible
- Prefix Sum: CPU computes block offsets (serial over blocks, parallel within)
- Scatter Pass: Each visible instance writes to its block's allocated slot
Matrix vs Position Mode
- Position Mode (default): Uses
refPosition/refNormalarrays - Matrix Mode (via
bindMatricesAsReference()): Extracts position from matrices- Enables per-geometry bounding sphere culling
- Ideal for
IndirectBatchedMeshintegration
LOD System
- Purpose: Reduce draw density smoothly with distance by keeping each instance with probability
pKeep. - Near/Far:
lodNeardefines where LOD begins.lodFardefines where range mode reaches full falloff. - Modes (
lodMode):- Disabled (
LOD_MODE_DISABLED): LOD sampling is off. - Range (
LOD_MODE_RANGE): Smoothstep falloff betweenlodNearandlodFar.pKeep = 1 - smoothstep( lodNear, lodFar, d ) - Exp (
LOD_MODE_EXP): Exponential density falloff starting atlodNear.pKeep = exp( -density^2 * (d - lodNear)^2 )Note:lodNearshifts the start of the exp curve; increasing it delays the falloff.
- Disabled (
- Density Parameter:
lodDensityacts as exp density (smaller = slower decay). - Sampling: Each instance is kept if
hash(instanceId) < pKeep, giving stable stochastic thinning. - Compatibility: Internally computes
stepF = sqrt(1 / max(pKeep, eps))for legacy outputs.
Integration with IndirectBatchedMesh
Constructor Parameters
optionsObjectrendererTHREE.WebGPURendererWebGPU renderer instance.countnumberTotal number of instances to test.refPositionoptionalTHREE.StorageBufferAttributeReference positions (vec3) - optional if using matrices.refNormaloptionalTHREE.StorageBufferAttributeReference normals (vec3) - optional if using matrices.indexCountnumberIndex count per geometry for indirect draw args.enabledoptionalbooleanEnable frustum culling.
Default istrue.frustumPadXYoptionalnumberFrustum padding in XY directions.
Default is0.2.frustumPadZNearoptionalnumberFrustum padding at near plane.
Default is0.0.frustumPadZFaroptionalnumberFrustum padding at far plane.
Default is0.2.
See also
Example
import { IndirectBatchedMesh, ComputeBatchCulling, indirectBatch } from '@three-blocks/core';
// Create batched mesh
const count = 10000;
const mesh = new IndirectBatchedMesh(count, 50000, 150000, material);
mesh.frustumCulled = false; // Disable CPU culling
// Add geometries and instances
const sphereId = mesh.addGeometry(new SphereGeometry(1, 16, 16));
for (let i = 0; i < count; i++) {
const id = mesh.addInstance(sphereId);
const matrix = new Matrix4();
matrix.makeTranslation(
Math.random() * 100 - 50,
Math.random() * 100 - 50,
Math.random() * 100 - 50
);
mesh.setMatrixAt(id, matrix);
}
// Setup material with indirect batch node
material.positionNode = Fn(() => {
indirectBatch(mesh).toStack();
return positionLocal;
})();
// Create culler
const culler = new ComputeBatchCulling({
renderer,
count,
indexCount: sphereGeometry.index.count,
enabled: true
});
// Bind mesh matrices as culling reference
culler.bindMatricesAsReference(mesh);
culler.attachGeometry(mesh.geometry);
culler.attachMesh(mesh);
// Render loop
function animate() {
culler.setCameraUniforms(camera);
culler.update(); // GPU culling
renderer.render(scene, camera);
}
Properties
# .indirect : THREE.IndirectStorageBufferAttribute
Get indirect draw buffer.
# .outIdSSBO : THREE.StorageBufferAttribute
Get survivor ID buffer.
# .outIdNode : StorageNode
Get survivor ID storage node (TSL).
Methods
setCameraUniforms#
setCameraUniforms(camera : THREE.Camera)Update camera uniforms for frustum culling.
Call before update() each frame.
Parameters
cameraTHREE.CameraattachGUI#
attachGUI(folder : Object)Attach culling controls to a GUI folder. Compatible with lil-gui, dat.gui, and Three.js Inspector.
Parameters
folderObjectdisposeGUI#
disposeGUI()Detach and destroy the GUI folder.
update#
update()Execute GPU culling with two-pass block compaction. Must be called every frame before rendering.
attachGeometry#
attachGeometry(geometry : THREE.BufferGeometry)Attach geometry to receive indirect draw args.
Parameters
geometryTHREE.BufferGeometryattachMesh#
attachMesh(mesh : THREE.Mesh)Attach mesh and configure survivor buffer.
Parameters
meshTHREE.MeshsetReferenceMatrixNode#
setReferenceMatrixNode(resolverFn : function|null) : thisOverride the matrix used for culling (e.g., animation texture).
Parameters
resolverFnfunction | nullReturns
thisbindMatricesAsReference#
bindMatricesAsReference(mesh : IndirectBatchedMesh)Bind mesh matrices as culling reference (enables matrix mode).
Extracts positions from instance matrices and enables per-geometry sphere tests.
Automatically called by IndirectBatchedMesh when culling is enabled.
Parameters
matricesSB storage buffer.readIndirectArgs#
readIndirectArgs() : Promise<Uint32Array>Read back indirect draw arguments from GPU (debug/stats).
Returns
Promise<Uint32Array> — Array of [indexCount, instanceCount, firstIndex, baseVertex, firstInstance].readSurvivorIndicesAsync#
readSurvivorIndicesAsync() : Promise<Uint32Array>Read back surviving instance IDs from GPU (debug/analysis).
Returns
Promise<Uint32Array> — Array of survivor instance indices.dispose#
dispose()Dispose of GPU resources.