IndirectBatchedMesh
new IndirectBatchedMesh()WebGPU-first batched mesh using indirect instanced rendering with GPU-driven culling.
Architecture Overview
- Packs multiple geometries into a single
BufferGeometrywith indirect draw commands - Always uses multi-draw indirect with
firstInstanceoffsets (even without GPU culling) - Stores per-instance data in GPU
StorageBufferAttributes(transforms, colors, geometry IDs) - Delegates culling/sorting to compute pipelines (e.g.,
ComputeBatchCulling) - Supports optional internal culling or external compute pipeline attachment
Limitations
- Transparency is not supported: This mesh class is designed for opaque materials only.
Transparent materials will not render correctly due to the lack of depth sorting.
Use standard
MeshorInstancedMeshwith ComputeInstanceCulling for transparent objects.
Culling Flow
ComputeBatchCullingevaluates visibility/LOD and compacts survivor IDs- Mesh reads from buffers via
setIndirect()andsetSurvivorIdBuffer() - Renderer draws using buffers while compute updates for next frame
Buffer Roles
matricesSB: Authoritative per-instance transformssurvivorIdSB: MapsinstanceIndex→ original instance ID after cullinggeometryIdSB: Identifies which geometry segment each instance usesindirect: Controls finalinstanceCountfor GPU draw
Example: Basic setup with multiple geometries
See also
Example
import { IndirectBatchedMesh, indirectBatch } from '@three-blocks/core';
import * as THREE from 'three/webgpu';
// Create batched mesh: 10000 instances, 50000 vertices, 100000 indices
const material = new THREE.MeshStandardNodeMaterial({ color: 0x4488ff });
const mesh = new IndirectBatchedMesh(10000, 50000, 100000, material);
// Add multiple geometry types
const boxId = mesh.addGeometry(new THREE.BoxGeometry(1, 1, 1));
const sphereId = mesh.addGeometry(new THREE.SphereGeometry(0.5, 16, 16));
const coneId = mesh.addGeometry(new THREE.ConeGeometry(0.5, 1, 8));
// Scatter instances of different geometries
const matrix = new THREE.Matrix4();
const geometries = [boxId, sphereId, coneId];
for (let i = 0; i < 5000; i++) {
const geomId = geometries[i % 3];
const instanceId = mesh.addInstance(geomId);
matrix.makeTranslation(
(Math.random() - 0.5) * 200,
(Math.random() - 0.5) * 50,
(Math.random() - 0.5) * 200
);
mesh.setMatrixAt(instanceId, matrix);
}
scene.add(mesh);Properties
# .frustumCulled : boolean
Disable frustum culling for the indirect batched mesh.
Default is false.
# .perObjectFrustumCulled : boolean
Enable per-instance frustum culling when using internal culling.
Default is true.
# .maxInstanceCount : number
Maximum instance capacity.
# .instanceCount : number
Current number of active instances.
# .unusedVertexCount : number
Remaining vertex capacity.
# .unusedIndexCount : number
Remaining index capacity.
Methods
beginBulkUpdate#
beginBulkUpdate() : thisDefer CPU indirect rebuilds while performing many mutations (add/remove instances).
Call endBulkUpdate() to rebuild once after the batch.
Returns
thisendBulkUpdate#
endBulkUpdate(rebuild : boolean) : thisResume CPU indirect rebuilds after beginBulkUpdate().
Parameters
rebuildoptionalbooleanDefault is
true.Returns
thisenableWorkgroupIndirect#
enableWorkgroupIndirect(workgroupSize : number) : THREE.IndirectStorageBufferAttributeOptional helper: allocate and update an indirect workgroup buffer for compute passes. Writes ceil(instanceCount / workgroupSize) into element 0 each frame.
Parameters
workgroupSizeoptionalnumberDefault is
64.Returns
THREE.IndirectStorageBufferAttribute — Indirect buffer with [x=workgroups, y=1, z=1].enableInternalCulling#
enableInternalCulling(renderer : THREE.WebGPURenderer) : thisEnable built-in compute-based culling using ComputeBatchCulling.
Automatically creates and attaches a culling pipeline.
Parameters
rendererTHREE.WebGPURendererReturns
thissetCullingMatrixNode#
setCullingMatrixNode(resolverFn : function|null) : thisProvide a custom mat4 node for culling/sorting (e.g., animation texture).
Parameters
resolverFnfunction | nullReturns
thisattachGUI#
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.
computeBoundingBox#
computeBoundingBox() : voidCompute the world-space bounding box for all active instances.
Updates this.boundingBox.
Returns
voidcomputeBoundingSphere#
computeBoundingSphere() : voidCompute the world-space bounding sphere for all active instances.
Updates this.boundingSphere.
Returns
voidupdateInternalCulling#
updateInternalCulling(camera : THREE.Camera) : thisUpdate the internal culling system for the current frame. Swaps buffers and runs the compute culling pass.
Parameters
cameraoptionalTHREE.CameraReturns
thissetSurvivorIdBuffer#
setSurvivorIdBuffer(sbAttr : THREE.StorageBufferAttribute, isInternal : boolean) : thisAttach a survivor ID mapping buffer produced by external compute culling.
Parameters
sbAttrTHREE.StorageBufferAttributeisInternaloptionalbooleanDefault is
false.Returns
thissetDrawFirstInstanceBuffer#
setDrawFirstInstanceBuffer(sbAttr : THREE.StorageBufferAttribute|null) : thisAttach a per-draw firstInstance buffer (geometry offsets) produced by compute culling.
Parameters
sbAttrTHREE.StorageBufferAttribute | nullReturns
thissetIndirect#
setIndirect(indirectAttribute : THREE.IndirectStorageBufferAttribute) : thisSet the indirect draw command buffer for this mesh.
Parameters
indirectAttributeTHREE.IndirectStorageBufferAttributeReturns
thissetInstanceCount#
setInstanceCount(maxInstanceCount : number)Resize the instance pool capacity. Preserves existing data and initializes new slots to identity transforms.
Parameters
maxInstanceCountnumberaddInstance#
addInstance(geometryId : number) : numberAdd a new instance referencing a previously added geometry.
Parameters
geometryIdnumberaddGeometry().Returns
number — The new instance ID.addGeometry#
addGeometry(geometry : THREE.BufferGeometry, reservedVertexCount : number, reservedIndexCount : number) : numberAdd a geometry to the batch, allocating space in the merged buffers.
Parameters
geometryTHREE.BufferGeometryreservedVertexCountoptionalnumberDefault is
-1.reservedIndexCountoptionalnumberDefault is
-1.Returns
number — Geometry ID for creating instances.setGeometryAt#
setGeometryAt(geometryId : number, geometry : THREE.BufferGeometry) : numberReplace or update geometry data at a specific geometry slot.
Parameters
geometryIdnumbergeometryTHREE.BufferGeometryReturns
number — The geometry ID.deleteGeometry#
deleteGeometry(geometryId : number) : thisMark a geometry as inactive and delete all associated instances.
Parameters
geometryIdnumberReturns
thisdeleteInstance#
deleteInstance(instanceId : number) : thisMark an instance as inactive and return its slot to the pool.
Parameters
instanceIdnumberReturns
thisoptimize#
optimize() : thisDefragment geometry data by compacting active geometry segments. Reduces gaps and improves memory layout.
Returns
thisgetBoundingBoxAt#
getBoundingBoxAt(geometryId : number, target : THREE.Box3) : THREE.Box3|nullGet the bounding box for a specific geometry.
Parameters
geometryIdnumbertargetTHREE.Box3Returns
THREE.Box3 | null — The bounding box or null if invalid.getBoundingSphereAt#
getBoundingSphereAt(geometryId : number, target : THREE.Sphere) : THREE.Sphere|nullGet the bounding sphere for a specific geometry.
Parameters
geometryIdnumbertargetTHREE.SphereReturns
THREE.Sphere | null — The bounding sphere or null if invalid.setMatrixAt#
setMatrixAt(instanceId : number, matrix : THREE.Matrix4) : thisSet the transform matrix for an instance.
Parameters
instanceIdnumbermatrixTHREE.Matrix4Returns
thisgetMatrixAt#
getMatrixAt(instanceId : number, matrix : THREE.Matrix4) : THREE.Matrix4Get the transform matrix for an instance.
Parameters
instanceIdnumbermatrixTHREE.Matrix4Returns
THREE.Matrix4setColorAt#
setColorAt(instanceId : number, color : THREE.Color) : thisSet the color for an instance. Automatically enables instance colors if not already enabled.
Parameters
instanceIdnumbercolorTHREE.ColorReturns
thisgetColorAt#
getColorAt(instanceId : number, color : THREE.Color) : THREE.ColorGet the color for an instance.
Parameters
instanceIdnumbercolorTHREE.ColorReturns
THREE.ColorsetGeometryIdAt#
setGeometryIdAt(instanceId : number, geometryId : number) : thisChange which geometry an instance references.
Parameters
instanceIdnumbergeometryIdnumberReturns
thisgetGeometryIdAt#
getGeometryIdAt(instanceId : number) : numberGet the geometry ID for an instance.
Parameters
instanceIdnumberReturns
number — Geometry ID.copy#
copy(source : IndirectBatchedMesh) : thisCreate a deep copy of this IndirectBatchedMesh.
Parameters
Returns
thisdispose#
dispose() : voidDispose of GPU resources. Call this when the mesh is no longer needed.
Returns
voidType Definitions
IndirectBatchedMeshBuffers#
matricesSB:THREE.StorageBufferAttribute, colorsSB:THREE.StorageBufferAttribute|null, geometryIdSB:THREE.StorageBufferAttribute, survivorIdSB:THREE.StorageBufferAttribute|null, +1 more
Properties
matricesSBTHREE.StorageBufferAttributecolorsSBTHREE.StorageBufferAttribute | nullgeometryIdSBTHREE.StorageBufferAttributesurvivorIdSBTHREE.StorageBufferAttribute | nullindirectoptionalTHREE.IndirectStorageBufferAttribute