name: vtj-performance description: Optimizes Three.js rendering performance. Use when rendering large numbers of objects, optimizing frame rates, implementing streaming, or managing memory in voxel/block-based scenes.
vite-threejs Performance Optimization
Overview
Performance patterns for voxel-based Three.js applications.
Key techniques:
- InstancedMesh: Batch render thousands of similar objects
- Occlusion culling: Skip hidden blocks
- Geometry sharing: Single geometry for all blocks
- Idle queue: Non-blocking chunk generation
Quick Reference
| Technique | Use When | Benefit |
|---|---|---|
| InstancedMesh | 100+ similar objects | Reduced draw calls |
| Occlusion culling | Voxel terrain | Fewer vertices processed |
| Geometry sharing | Multiple meshes same shape | Lower memory |
| Swap-and-pop | Dynamic instance removal | O(1) deletion |
| Idle queue | Background tasks | No frame drops |
InstancedMesh Pattern
const geometry = new THREE.BoxGeometry(1, 1, 1) // Shared
const material = new THREE.MeshStandardMaterial({ color: 0x888888 })
const mesh = new THREE.InstancedMesh(geometry, material, count)
mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage)
// Set instance at index
mesh.setMatrixAt(index, matrix)
mesh.instanceMatrix.needsUpdate = true
Full patterns: See references/instanced-mesh.md
O(1) Instance Removal
// Swap last instance into deleted slot
const lastIndex = mesh.count - 1
if (index < lastIndex) {
mesh.getMatrixAt(lastIndex, tempMatrix)
mesh.setMatrixAt(index, tempMatrix)
}
mesh.count--
mesh.instanceMatrix.needsUpdate = true
Implementation details: See references/swap-and-pop.md
Occlusion Culling
Skip blocks completely surrounded by other blocks:
if (isBlockObscured(x, y, z)) return // Skip rendering
renderBlock(x, y, z)
Algorithm: See references/occlusion-culling.md
Idle Queue
// Schedule work without blocking main thread
idleQueue.enqueue('chunk', () => {
chunk.generateData()
}, priority)
API reference: See references/idle-queue.md
Memory Management
destroy() {
// Dispose materials
if (Array.isArray(mesh.material)) {
mesh.material.forEach(m => m?.dispose())
} else {
mesh.material?.dispose()
}
// Remove from scene
scene.remove(mesh)
mesh = null
}
Complete patterns: See references/memory-management.md
Common Mistakes
- ❌ Creating geometry per object
- ❌ Using
splice()for instance removal - ❌ Forgetting
needsUpdate = true - ❌ Synchronous chunk generation
Full catalog: See references/common-mistakes.md
Configuration
export const CHUNK_CONFIG = {
chunkWidth: 64, // Balance draw calls vs memory
viewDistance: 1, // 1 = 3x3 chunk grid
unloadPadding: 1, // Hysteresis for unloading
}
Tuning guide: See references/configuration.md