Visual Effects
Hyperscape uses GPU-driven visual effects for resource depletion, respawn animations, and environmental feedback. All effects use TSL (Three Shading Language) shaders that require WebGPU.Visual effects code lives in
packages/shared/src/systems/shared/world/ and uses the DissolveAnimation state machine for smooth transitions.Tree Dissolve Transparency (March 2026)
New Feature (PR #1101): Depleted trees use screen-door dithering to become ~70% transparent instantly on depletion, then animate back to full opacity over 0.3s on respawn.
Overview
The tree dissolve system provides visual feedback for resource depletion and respawn:- Instant Depletion: Tree becomes 70% transparent immediately when depleted
- Smooth Respawn: Animates from transparent to opaque over 0.3 seconds
- Performance: Uses screen-door dithering in opaque render pass (no alpha blending overhead)
- LOD Preservation: Dissolve state carries over during LOD transitions (no visual pops)
Implementation
Dual Encoding Strategy: The system supports both InstancedMesh and BatchedMesh rendering:
Shared Animation Module:
packages/shared/src/systems/shared/world/DissolveAnimation.ts provides the state machine:
Configuration
Dissolve timing is configured inGPU_VEG_CONFIG:
DISSOLVE_DURATION: Animation duration in seconds (0.3s = ~18 frames at 60fps)DISSOLVE_MAX: Animation progress ceiling (always 1.0)DISSOLVE_ALPHA_SCALE: Fraction of fragments discarded via dithering (0.7 = 70% transparent)
Shader Implementation
The dissolve effect uses screen-door dithering in thealphaTestNode:
dissolveVal, creating a stippled transparency effect that keeps trees in the opaque render pass with full early-Z rejection.
Performance Benefits
Opaque Pass Preservation:- Trees stay in opaque render pass (no transparency sorting)
- Full early-Z rejection (fragments behind opaque geometry are culled)
- No fill-rate cost from alpha blending
- Consistent performance regardless of dissolve state
- R channel: Highlight intensity (1.0 = normal, >1.0 = highlighted)
- G channel: Highlight intensity (same as R)
- B channel:
1.0 - dissolveVal(1.0 = fully visible, 0.0 = fully dissolved)
LOD Transition Handling
Dissolve state is preserved when trees swap between LOD levels:API Reference
GLBTreeInstancer / GLBTreeBatchedInstancer:Usage Example
Tree Collision Proxy (March 2026)
Improvement (PR #1100): Tree collision detection now uses actual LOD2 model geometry instead of oversized cylinders.
Problem
The old system used invisible cylinder hitboxes with 0.4 radius factor, which were much larger than the visible tree silhouette. Ground clicks near trees were being intercepted by the collision proxy instead of registering as ground clicks.Solution
Replace cylinder with actual LOD2 mesh geometry so clicks only register on the visible tree silhouette:Geometry Caching
Proxy geometries are cached per(sourceGeometries, scale) to avoid redundant merges:
- Float Key Safety: Scale rounded to 3 decimal places to prevent floating-point cache misses
- Multi-Part Merging: Combines bark and leaves into single proxy mesh
- Defensive Bounding Box: Pre-computes
boundingBoxandboundingSphereto prevent lazy mutation by Three.js raycaster - Memory Management: Cache cleared during world teardown to prevent GPU buffer leaks
API Reference
GLBTreeInstancer / GLBTreeBatchedInstancer:Benefits
- Accurate Click Detection: Clicks only register on visible tree silhouette
- No Ground Click Interception: Ground clicks near trees work correctly
- Memory Efficient: Cached geometry shared across all trees with same model+scale
- Graceful Fallback: Uses tighter cylinder (0.25 radius) if LOD unavailable
Screen-Door Dithering
Screen-door dithering is a technique that creates transparency effects while keeping geometry in the opaque render pass:How It Works
Instead of using alpha blending (which requires transparency sorting and disables early-Z), fragments are discarded based on a dither pattern:Benefits
Visual Quality:
At 0.3s animation duration (60fps = ~18 frames), the dithering pattern is barely noticeable and provides smooth visual feedback without the performance cost of true transparency.
GPU Vegetation Config
All vegetation visual effects are configured viaGPU_VEG_CONFIG:
Distance Fade
Trees automatically fade out at distance using the same Bayer dithering pattern:- FADE_START (40m): Trees begin to fade
- FADE_END (60m): Trees fully dissolved (culled)
Near Camera Fade
Trees near the camera fade to prevent clipping through the viewport:- NEAR_CAMERA_FADE_START (0.1m): Begin fade
- NEAR_CAMERA_FADE_END (0.05m): Fully transparent
Related Documentation
- Tree Collision Proxy - Collision detection improvements
- Resource System - Resource depletion and respawn
- GPU Materials - TSL shader system
- WebGPU Rendering - Rendering pipeline