Skip to main content

Arena Performance Optimizations (February 2026)

Commit: c20d0fc09ff44219a306d869b9f71bef6f39a25b
PR: #938
Author: Ting Chien Meng (@tcm390)

Summary

Massive rendering performance improvement for the duel arena system by converting ~846 individual meshes to InstancedMesh (97% draw call reduction) and replacing 28 dynamic PointLights with GPU-driven TSL emissive materials.

Performance Impact

Before

  • Draw Calls: ~846 individual meshes
  • Lights: 28 dynamic PointLights (expensive per-pixel shading)
  • FPS: Significant drops in arena areas

After

  • Draw Calls: ~20 InstancedMesh batches (97% reduction)
  • Lights: 0 dynamic lights (replaced with TSL emissive materials)
  • FPS: Smooth performance in all arena areas

Changes

1. InstancedMesh Conversion

Converted repeated geometry to instanced draws: Fence Components (4 draw calls):
  • Posts: 288 instances → 1 draw call
  • Caps: 288 instances → 1 draw call
  • X-Rails: 36 instances → 1 draw call
  • Z-Rails: 36 instances → 1 draw call
Pillar Components (3 draw calls):
  • Bases: 32 instances → 1 draw call
  • Shafts: 32 instances → 1 draw call
  • Capitals: 32 instances → 1 draw call
Other Instanced Geometry:
  • Brazier bowls: 24 instances → 1 draw call
  • Border strips: 24 instances → 2 draw calls (N/S + E/W)
  • Banner poles: 12 instances → 1 draw call
Individual Meshes (still needed for raycasting):
  • Arena floors: 6 meshes (need unique arenaId userData)
  • Forfeit pillars: 12 meshes (need unique entityId for interaction)
  • Banner cloths: 12 meshes (3 shared materials)

2. Dynamic Light Elimination

Removed: 28 PointLights (24 arena corner torches + 4 lobby braziers) Replaced With: TSL emissive material on brazier bowls GPU-Driven Flicker:
Benefits:
  • Zero CPU cost per frame (all calculations on GPU)
  • No per-light state updates
  • Consistent flicker across all braziers
  • Eliminates expensive per-pixel lighting calculations

3. Fire Particle Shader Enhancement

Removed: “torch” particle preset (redundant) Enhanced: “fire” preset with improved fragment shader New Features:
  • Smooth Value Noise: Bilinear interpolated hash lattice for organic flame shapes
  • Soft Radial Falloff: Designed for additive blending - overlapping particles merge into cohesive flame
  • Turbulent Vertex Motion: Per-particle jitter for natural flickering
  • Height-Based Color Gradient: White-yellow core → orange-red tips
  • Scrolling Noise: Upward motion feel with organic edges
Particle Count:
  • Fire: 18 → 28 particles (tighter spawn spread compensates)
  • Torch: Removed (unified on fire preset)
Configuration:

4. Dead Code Removal

Removed unused functions:
  • createArenaMarker() - Number markers (1-6 dots) were never used
  • createAmbientDust() - Dust particles were never registered
  • createLobbyBenches() - Benches were never added to scene

Implementation Details

Shared Materials

All instanced meshes share materials (compiled once during init):

Instance Matrix Updates

All instance matrices are set once during initialization:
No per-frame matrix updates needed (static geometry).

TSL Time Uniform

Single time uniform drives all brazier glow animations:
All 28 braziers share this uniform - GPU handles per-brazier phase offset.

Migration Guide

For Developers

No migration needed - changes are fully backward compatible. If you’re adding new arena geometry:
  1. Use InstancedMesh for repeated geometry:
  2. Use TSL emissive materials instead of PointLights:
  3. Keep individual meshes only when needed for raycasting/interaction:
    • Floors (need layer 0+2 for click-to-move)
    • Interactive objects (need unique entityId userData)

For Asset Creators

Fire Particles: Use the unified “fire” preset:
Torch Preset Removed: All fire emitters now use the enhanced “fire” preset with better visual quality.

Performance Metrics

Draw Call Reduction

Lighting Performance

Memory Usage

Visual Quality

Maintained

  • ✅ Stone texture detail (TSL procedural materials)
  • ✅ Fire particle appearance (enhanced shader)
  • ✅ Brazier glow (TSL emissive matches old PointLight flicker)
  • ✅ Overall arena atmosphere

Improved

  • ✅ Fire particles: More organic flame shapes with noise
  • ✅ Brazier glow: Consistent flicker across all instances
  • ✅ Performance: Smooth 60 FPS in arena areas

Removed

  • ❌ Arena number markers (1-6 dot patterns) - never used
  • ❌ Lobby benches - never added to scene
  • ❌ Ambient dust particles - never registered

Modified

  • packages/shared/src/systems/client/DuelArenaVisualsSystem.ts - Main arena rendering system
  • packages/shared/src/entities/managers/particleManager/GlowParticleManager.ts - Fire particle shader

Workflow

  • .github/workflows/deploy-vast.yml - Deployment with maintenance mode

Future Improvements

Potential Optimizations

  1. Texture Atlasing: Combine stone textures into single atlas
  2. LOD System: Reduce geometry detail at distance
  3. Frustum Culling: Skip rendering off-screen arenas
  4. Occlusion Culling: Skip rendering occluded geometry

Monitoring

  • Track FPS in arena areas
  • Monitor draw call count via DevTools
  • Profile GPU usage with Chrome DevTools Performance

References