Save Expand icon

Ron Valstar
front-end developer

Experiment: procedural fire with sparks in GLSL

Here’s a hot shader: fire with sparks. The fire is Simplex noise, nothing special apart from some displacement to fake realism. But the sparks might need some explanation.

The shader is entirely procedural. So the sparks flying upward are calculated for each pixel. We could calculate the sparks in advance as particles and put them into the shader by uniform. But there’s no fun in that.
The technique I wanted to implement here is similar to one I previously used in plain JavaScript in an earlier experiment.

A grid, a prng and some trigonometry

The gist of it is as follows: calculate a grid, feed the grid positions into a pseudo random number generator (prng), use the random number to rotate a particle inside the grid.
Compared to the snow experiment the mental approach is a bit like coding it the other way around (we don’t really displace particles, we displace the input variables). Plus we cannot exceed the grid boundaries (we’re calculating pixels, not particles). If you click without dragging you will see the displaced grid. Notice the sparks are moving in circles within each grid cell.

First we create a grid. To do that we use modulo grid-size on the xy position: mod(gl_FragCoord,40.0), line 68. This will give us a grid of linear gradients (from zero to one) that we can use to create a spherical gradient.
If you change the very last line to: gl_FragColor = vec4(mod(gl_FragCoord,40.0)/40.0,0.0,1.0); you’ll see a pattern like this. The green and red are going from zero to one every 40 pixels.

modulo grid

The axes are divided by the size of the grid and floored to get the seeds for the random number. So the coordinates for the bottom left grid cell become 0,0 (the default origin for gl_FragCoord is the bottom left corner). Defining the grid index is done here.
Again a simple example: gl_FragColor = vec4(floor(gl_FragCoord.x/40.0)/4.0,floor(gl_FragCoord.y/40.0)/3.0,0.0,1.0); makes this:

grid indices

The floored indices are the numbers we’ll use as input for our prng. The prng we’ll be using is one by David Hoskins who says: The magic numbers were chosen by mashing the number pad, until it looked OK!. Haha, well fractional parts beats LCG and Mersenne Twister in this case.
This gets us the following gl_FragColor = vec4(prng(floor(gl_FragCoord.xy/40.0)),0.0,0.0,1.0);:

random grid indices

Let there be sparks

This random number is used to define the size of the spark as well as it’s rotation and it’s life expectancy. The input derived from gl_FragCoord is also displaced around a bit to create some flow direction and randomness.

And that is really all there is to it.
The source code is below. I’ve also ported this over to Shadertoy (with minor some adjustments to get it working there) so you can easily tweak and/or fork it.