Instanced Rendering System
Hyperscape uses GPU instancing to efficiently render large numbers of resource entities (trees, rocks, ores, herbs) with minimal draw calls.Overview
The instanced rendering system pools identical models into sharedInstancedMesh objects, reducing draw calls from O(n) per resource to O(1) per unique model per LOD level.
Key Components
- GLBResourceInstancer: General-purpose instancer for rocks, ores, herbs
- GLBTreeInstancer: Specialized instancer for trees with dissolve materials
- InstancedModelVisualStrategy: Visual strategy wrapper for instanced entities
- TreeGLBVisualStrategy: Tree-specific strategy with depleted model support
Architecture
Instance Pooling
Each instancer maintains separate pools for:- Normal state: Active resources (trees, rocks, etc.)
- Depleted state: Harvested resources (stumps, empty ore veins)
- LOD levels: Distance-based level of detail (LOD0, LOD1, LOD2)
LOD System Integration
- Distance-based switching: Automatically switches LOD levels based on camera distance
- Hysteresis: Prevents flickering by using different thresholds for switching up vs down
- Per-instance tracking: Each instance tracks its current LOD level independently
Collision Handling
Instanced entities use invisible collision proxies for raycasting:- Proxy mesh positioned at instance location
- Invisible to camera (renderOrder = -1, no material rendering)
- Enables mouse hover and click detection
- Persists across state transitions (normal → depleted)
Depleted Models Feature
Resources can specify depleted models that display after harvesting:State Transitions
When a resource is depleted:- Instancer removes instance from normal pool
- Instancer adds instance to depleted pool (if
depletedModelPathconfigured) - Collision proxy remains in place
- Highlight mesh updates to match new state
- Instancer removes instance from depleted pool
- Instancer adds instance back to normal pool
- Collision proxy persists (no recreation needed)
Highlight Mesh Support
Instanced entities support hover/selection highlighting:- Preloaded from LOD0 geometry
- Shared across all instances of the same model
- Positioned/scaled to match the hovered instance
- Removed from scene when hover ends
API Changes
ResourceVisualStrategy.onDepleted()
Breaking Change: Return type changed fromvoid to boolean
- Strategies that handle depletion internally (instanced): return
true - Strategies that don’t handle depletion: return
false - ResourceEntity only loads individual depleted model if strategy returns
false
ResourceVisualStrategy.getHighlightMesh()
New Optional Method:null if highlighting is not supported or should use default behavior.
Performance Benefits
Draw Call Reduction
Before instancing (1000 trees):- 1000 draw calls (1 per tree)
- High CPU overhead from draw call submission
- GPU state changes per tree
- 3 draw calls (1 per LOD level)
- Minimal CPU overhead
- Single GPU state change per LOD level
Memory Efficiency
- Geometry sharing: Single geometry buffer shared across all instances
- Material sharing: Single material shared across all instances
- Transform matrices: Stored in GPU-side instance buffer
- Collision proxies: Lightweight Box3 bounds, no full geometry duplication
Configuration
Resource Manifest
Visual Strategy Selection
The system automatically selects the appropriate strategy:Fallback Behavior
If instancing fails (e.g., model loading error), the system automatically falls back toStandardModelVisualStrategy:
Debugging
Visual Debugging
Enable debug visualization to see instance bounds:- Draw wireframe boxes around each instance
- Color-code by LOD level (green=LOD0, yellow=LOD1, red=LOD2)
- Show instance count per pool
Performance Monitoring
Check instance statistics:Limitations
- Maximum instances per mesh: 65,536 (WebGPU limit)
- Uniform materials only: All instances of a model share the same material
- No per-instance animations: Use Vertex Animation Textures (VAT) for animated instances
- Static geometry: Instance geometry cannot be modified at runtime
Future Improvements
- Frustum culling per instance (currently culls entire InstancedMesh)
- Occlusion culling integration
- Dynamic instance addition/removal without full rebuild
- Per-instance material variations via vertex colors
- GPU-driven LOD selection