OpenGL Programming/Particle systems

This is a Work In Progress

A particle system is an optimized way to deal with a huge number of objects (several thousands to several millions).

The naive approach is to draw each object independently (as we did in most other tutorials), but drawing thousands of objects implies preparing and calling DrawArray/DrawElements thousands of times per frame, each implying an OpenGL round-trip, which is plain inefficient.

Instead, the goal is to draw loads of similar objects in one go.

We identify 2 mains way to render particle systems:

  • Manipulating attributes on the CPU and rendering them on the GPU:
    • On start-up, upload a single VBO of points (fast sprites with GL_POINTS), or a set of 3D objects all in a single VBO+EBO.
    • At each frame, manipulate them on the CPU, uploading a VBO of attributes.
    • At each frame, draw them with a single DrawArray/DrawElements call (same shader for all objects).
  • Full-GPU particle system, computing with a tex1 = fragment_shader(tex2, tex3, ...) pattern:
    • On start-up, store all particles initial attributes in textures (one texel = one particle's attribute).
    • On start-up, upload a huge, static array of GL_POINTS (one per texel).
    • At each frame, render a quad to a new result texture of the same size, combining the initial attributes in the fragment shader and storing the next particle state (e.g.: its next position). Several attributes can be computed with several shaders. Textures can be swapped to update old state to new state.
    • At each frame, draw the static array of points: in the vertex shader, lookup the particle attributes (e.g. position) in the result texture(s).
    • No per-frame upload!
  • Special, intermediate case for non-incremental transformations (uniforms instead of attributes, e.g. linear motions): full-GPU if you compute the position procedurally in the vertex shader (no attributes manipulation)