Texture pooling
By Robin Dowling · 4 months ago
Rendering thousands of organisms in a browser comes with constraints. Each organism rendered as individual sprites creates thousands of draw calls and consumes significant GPU memory. As the simulation scaled, this became a bottleneck, especially on mobile devices.
The solution was texture pooling, generating organisms as static textures that can be reused across visually similar organisms. Instead of rendering each organism from scratch every frame, the client generates a texture once for a given combination of species, size, and traits, then reuses that texture for all organisms matching those characteristics.
This is standard rendering stuff, but I'm new to it.
For motile organisms, I implemented a hybrid approach. The body is pooled as a static texture, but the eyes remain as live sprites layered on top. This preserves the blinking animation while achieving a 90% reduction in vertex count—from about 1400 vertices per organism down to around 106.
For sessile organisms like plants, the entire organism is pooled as a single static texture since they don't have animated features. The swaying motion is acheived simply by swaying the texture.
The system automatically adjusts pooling aggressiveness based on device capabilities. High-end desktops get 5 texture variants per combination with mass bucketed every 5 units. Mobile devices get 2 variants with mass bucketed every 7 units. Low-end devices pool even more aggressively.
Textures that haven't been used in 2 minutes are automatically evicted, keeping memory footprint reasonable as species evolve and go extinct. The system maintains a hard cap of 5,000 textures across the entire pool to prevent unbounded growth in long-running sessions.
The result is a simulation that runs smoothly with thousands of organisms visible simultaneously, adapting automatically to whatever device is viewing it.