simutils-0001: Gray-Scott reaction diffusion

This is part 2 of the discussion of the classes & processes provided by the recently released simutils package. The first part of this series dealt with Diffusion-limited Aggregation (DLA) and this next process too is related to the simulated diffusion of particles. However, whereas the DLA process dealt with individual particles, this next one is only looking at the concentrations of particles of different “substances” in a two-dimensional simulation space.

The Gray-Scott reaction diffusion model is a member of a whole variety of RD systems, popular largely due to its ability to produce a very varied number of biological looking (and behaving) patterns, both static and constantly changing. Some patterns are reminiscent of cell devision, gastrulation or the formation of spots & stripes on furry animals. As with all RD models, these patterns are the result of an iterative process evaluating each cell of the simulation space based on the concentrations of the two main parameters (for Gray-Scott usually named f and K) of the reaction equation as well as taking into account the concentrations of these 2 substances in neighboring cells. So conceptually the reaction diffusion system lies somewhere between the isolated DLA process working with individual particles and the entirely rulebased evaluation of a cell’s neighborhood in traditional cellular automatas, which we will deal with in the next post.

The image below, by Robert Munafo, is a fantastically helpful map of possible patterns resulting from various combinations of the f and K coefficients. Click the image to go to his website and explore the parameters in more detail (there’re close-ups and videos of all interesting combinations).

GS parameter map

As with the other classes of the simutils package, the GrayScott implementation comes with several small demos to help you get started. The most basic use case (HelloGrayScott) is just setting up a simulation with default parameters and then allows you to draw in the simulation space with the mouse. Each frame, the reaction is updated, its new state translated into grayscale pixels and then rendered to the screen. The important thing to know here is that there’re 2 separate results states available, normally called the u and v buffers.

GrayScott gs;

// create a new simulation instance
// the "false" refers to a non-tiled space with walls
// set to true to create tiling patterns
gs=new GrayScott(width,height,false);

// configure the simulation params to:
// f=0.023, K=0.074
// diffusion speed for u buffer = 0.095
// diffusion speed for u buffer = 0.03

The main draw() loop then just does this:

void draw() {
  if (mousePressed) {
    // set cells around mouse pos to max saturation
    gs.setRect(mouseX, mouseY,20,20);
  // update simulation by 10 time steps per frame
  for(int i=0; i<10; i++) gs.update(1);
  // read out the v buffer and translate into grayscale colors
  for(int i=0; i<gs.v.length; i++) {
    float cellValue=gs.v[i];
    // the cell values in v are usually in the range 0.0 .. 0.33 
    int col=255-(int)(min(255,cellValue*768));
    // use the col value for red, green and blue and set alpha to full opacity

To avoid this manual pixel pushing and enable us to make some of the subtle changes of densities more obvious, we can also use the handy (and also new) ToneMap class of the colorutils package. This allows us to map a number range to different positions (colors) on a multi-color gradient and so potentially better visualize the different densities. The basic usage of this class is shown below:

import toxi.color.*;

ToneMap toneMap;

// define a color gradient by adding colors at certain key points
// a gradient is like a 1D array with target colors at certain points
// all inbetween values are automatically interpolated (customizable too)
// this gradient here will contain 256 values
ColorGradient gradient=new ColorGradient();
gradient.addColorAt(0, NamedColor.BLACK);
gradient.addColorAt(128, NamedColor.RED);
gradient.addColorAt(192, NamedColor.YELLOW);
gradient.addColorAt(255, NamedColor.WHITE);

// now create a ToneMap instance using this gradient
// this maps the value range 0.0 .. 0.33 across the entire gradient width
// a 0.0 input value will be black, 0.33 white
toneMap=new ToneMap(0, 0.33, gradient);

Now we can refactor our Gray-Scott rendering code into something even simpler:

for(int i=0; i<gs.v.length; i++) {
    // take a GS v value and turn it into a packed integer ARGB color value

Btw. The ToneMap class is a nice example of the whole reusable “building block philosophy” of toxiclibs (and the object oriented approach in general). The class is simply a composition of other library classes and under the hood delegates everything to these elements:

ToneMap composition

All other GrayScott demos, as well as all Cellular Automata examples, make use of this ToneMap class, so do have a look at those for more reference…

Since a homogeneous configuration of the entire sim grid will always just provide one particular character/patterning, the GrayScott class has been designed with extension in mind. The CustomGrayScott demo shows how to impose a pattern on the actual simulation parameters themselves, so that cells at different positions are evaluated using different parameters:

class PatternedGrayScott extends GrayScott {

  // our constructor just passes things on to the parent class
  PatternedGrayScott(int w, int h, boolean tiling) {

  // this function is called for each cell
  // to retrieve its f coefficient
  public float getFCoeffAt(int x, int y) {
    // here we only take the x coordinate
    // and choose one of 2 options (even & odd)
    return 0==x%2 ? f : f-0.005;

  // this function is called for each cell
  // to retrieve its K coefficient
  public float getKCoeffAt(int x, int y) {
    // here we only use the y coordinate
    // and create a gradient falloff for this param
    return k-y*0.00004;

Instead of using the default GrayScott class, we only need to change one line in the setup() method to use our extended version instead:

GrayScott gs;

void setup() {
	gs=new PatternedGrayScott(width,height,false);

The result of this is shown below… Easy, huh? :)

Having this mechanism in place, it can be also used to create more interesting types of masking. For a commission to produce a cover design for Print Magazine in 2008, I generated a type face from simple line & arc segments and used it as mask to manipulate the concentrations of the f & K parameters to achieve two different types of patterning: one for the inside of the letter shapes, the other for the outside…

The frames of that animation were then stacked up along the Z axis in 3D space and with the help of the volumeutils classes turned into 3D mesh, exported as STL format (also see TriangleMesh.saveAsSTL()) and finally fabricated into the physical, 3D printed sculpture shown below. In a way, the sculpture can be seen as a map of its entire creation process…

Type & Form sculpture

Here’re some more rendered detail shots of the sculpture. More information about this project is here and the related flickr set.

Finally, the GrayScottImage demo shows another supported technique of using the library: the seeding of the simulation using a bitmap image.

Comments are closed.