Back to Overview

GPU Particles

Overview

Particle simulations - this time in parallel! Since the simulation is run as a shader on the GPU, it can handle millions of particles at once!

Design Decisions

Each particle is being represented as a pixel in a simulation texture. Because every pixel has 4 color channels, 4 floating point numbers can be stored per particle. The first two represent the 2D position (x and y coordinate), the second two usually get used for velocity. Since the particles in this particular simulation will be travelling at constant speeds, I decided to only store the direction instead and keep a free channel for additional data, like mass. At each time step we use a fragment shader to update the simulation texture, by calculating the new velocity and position using a simple Euler integration step. The updated colors are written to one of two framebuffers, that get swapped each frame (Ping-Pong Shader).

Data texture containing the particle information
Data texture containing the particle information. Each pixels color represents position and velocity of an according particle.

Drawing to the screen

Obviously we don't want a noisy image like in the figure above, so how do we draw the particles to the screen? That happens in the Vertex Shader. For each pixel of the simulation texture, a vertex is created, whose coordinates get read from the red and green channels of the according pixel. Since the simulation is only 2D, the z coordinate of all particles is set to 0. Using the handy GL_POINTS rendering mode, these vertecies can then be drawn to the screen as points!

Rounding errors from using 8bit integer textures
Initial results. What happened here?

What happened? The particles should be moving outwards in a straight line, but instead they are all collecting in the upper right corner! This error is caused by the numeric precision of the texture. By default, textures store color values as unsigned 8bit integers - that means only 256 values ranging [0, 1] are available. That might be fine for the typical color data stored in textures, but a simulation requires both higher precision and range. I opted for 32bit floating point textures, which allow for arbitrary unclamped values with very high numeric precision.

Particle Simulation using a 512x512 simulation texture
Screenshot of the working particle simulation.

This looks a lot more like it! With the basic simulation up and running, many other concepts can be explored. One possibility would be to add force fields or interactions between particles. In the demo above, the particles get initialized with different starting directions and turn towards the center when they're outside of a predefined circle. Depending on the initial conditions, interesting geometric patterns can form. One other example I'll be exploring soon, are agent based simulations of slime molds.