Overview
This particle system was designed to be easily extensible and flexible. There are 3 main steps to creating a particle system with my implementations. First create a compute shader with the prefix "particle_" (e.g. particle_spin.comp). Write your compute shader describing your particles behavior. Then call registerParticleSystem() to create compute pipelines and map that shaders name to its pipelines. This persists for the duration of the program. To create an instance of that particle system call createParticleSystem(). This takes parameters for the number of particles and some other options like origin, origin variance, and initial velocity variance. I used this to implement a few different systems and I will describe the process for the Lorenz attractor below.
I initialize 100,000,000 random positions and iterate on them with
the Lorenz attractor. They're rendered as points and colored by
their world space velocity, leading to the pretty pattern shown. The
particles are so dense at this volume that the attractor appears
solid until the camera gets almost inside path formed by the
attractor.
First initialize the particle data on cpu/host buffers then copy that
data into gpu/device buffers. I create two position buffers so that the
compute for the next frame can run while the rendering of the current
frame is going on in a classic ping-pong style buffer situation. On frame
N I write to buffer A. Start rendering while reading from buffer A. Then
without blocking I start compute for frame N+1 writing to buffer B, also
reading from buffer A. At particle counts as high in the example video
it doesn't matter so much since the bottleneck is the compute time, but
for lower particle counts and having multiple particle systems concurrently,
overlapping the work with the previous frame's rendering can be a valuable
optimization.
This setup can easily be extended to a more practical particle system
by instancing a billboarded quad with a sampled textures rather than colored
points, but the points are suffificent to show the concept and looked
good the visuzliation that I already wanted to make. The rendering work
for billboarded quads and texture fetches would be much slower than simple
shader currently used resulting in less particles but more quality per
particle. The current setup for calculating the next position is a single
compute shader which bases input purely on the previous position, which
is always available to read since it is necessary for the render.