It's a creative coding battlefield of Reaction vs. Diffusion.

One of the Reaction-Diffusion implementation.


An animation with a Reaction-Diffusion system.

It's a creative coding animation made with the 'Processing'. It draws the expansion of the territory.

I wanted to make some another display of Reaction-Diffusion when I was playing with the code from @pal_rex.

https://www.openprocessing.org/sketch/861742

And I had an idea to draw lines with each point that has similar attributes. I drew a line if the neighbor's point has a similar Reaction-Diffusion calculated value.
And I also changed Reaction-Diffusion feed/kill parameters to add a variation to the animation.







 

The 'Processing' example code.

This code does not display any images on the screen but generates image files in frames directory. You can make an animation with these files.

Please feel free to use this example code under the terms of the GPL.
To see other works based on my code is my pleasure. And my honor.




/**
 * The Battle Rages On.
 * One of the Reaction-Diffusion implementation.
 *
 * Processing 3.5.3
 * @author @deconbatch
 * @version 0.1
 * created 0.1 2020.03.31
 */

void setup() {

  size(720, 720);
  colorMode(HSB, 360, 100, 100, 100);
  smooth();

}

void draw() {

  int frmMax = 8 * 10; // 8fps x 10sec animation
  int frmChg = 12;     // change per frames
  ReactionDiffusion rd = new ReactionDiffusion(random(360.0), 10, 10);

  // to start with proceeded frames
  for (int i = 0; i < 30; i++) {
    rd.calculate();
  }

  for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {
    background(0, 0, 90, 100);

    rectMode(CENTER);
    rd.drawResults();
    rectMode(CORNER);
    casing();

    saveFrame("frames/" + String.format("%04d", frmCnt) + ".png");

    // to change animation style
    if (frmCnt % (frmChg * 2) == 0) {
      rd.randomDot();
    }
    if (frmCnt % frmChg == 0) {
      rd.randomParam();
    }
    rd.calculate();
  }
  exit();
}

/**
 * ReactionDiffusion : calculate and draw Reaction-Diffusion
 */
public class ReactionDiffusion {

  float dA = 1.2;
  float dB = 1.5;
  float feed = 0.05;
  float kill = 0.05;

  float rd[][][][];
  float hueBase;
  int xMult;
  int yMult;
  int xGrid;
  int yGrid;
  int curr;
  int prev;
  int a;
  int b;

  /**
   * ReactionDiffusion Constructor : 
   * @param  _hueBase      : drawing color.
   * @param  _xMult, _yMult: Reaction-Diffusion particle size.
   */
  ReactionDiffusion(float _hueBase, int _xMult, int _yMult) {

    hueBase = _hueBase;
    xMult   = _xMult;
    yMult   = _yMult;
    xGrid   = floor(width / xMult);
    yGrid   = floor(height / yMult);
    rd      = new float[xGrid][yGrid][2][2]; // x, y, a/b, current/previous

    // index value of array rd
    a    = 0;
    b    = 1;    
    curr = 0;
    prev = 1;

    for (int x = 0; x < xGrid; x++) {
      for (int y = 0; y < yGrid; y++) {
        rd[x][y][a][curr] = 1.0;
        rd[x][y][b][curr] = 0.0;
        rd[x][y][a][prev] = 1.0;
        rd[x][y][b][prev] = 0.0;
      }
    }

    randomDot();
    randomParam();
  }
  
  /**
   * randomDot : put Reaction-Diffusion seed.
   */
  public void randomDot() {
    if (random(1.0) < 0.5) {
      rd[floor((xGrid * 0.25))][floor((yGrid * 0.25))][a][prev] = 0.0;
      rd[floor((xGrid * 0.25))][floor((yGrid * 0.25))][b][prev] = 1.0;
      rd[floor((xGrid * 0.75))][floor((yGrid * 0.75))][a][prev] = 0.0;
      rd[floor((xGrid * 0.75))][floor((yGrid * 0.75))][b][prev] = 1.0;
    } else {
      rd[floor((xGrid * 0.25))][floor((yGrid * 0.75))][a][prev] = 0.0;
      rd[floor((xGrid * 0.25))][floor((yGrid * 0.75))][b][prev] = 1.0;
      rd[floor((xGrid * 0.75))][floor((yGrid * 0.25))][a][prev] = 0.0;
      rd[floor((xGrid * 0.75))][floor((yGrid * 0.25))][b][prev] = 1.0;
    }
  }

  /**
   * randomParam : change Reaction-Diffusion feed/kill parameters.
   */
  public void randomParam () {
    feed = random(0.01, 0.09);
    kill = random(0.01, 0.09);
  }

  /**
   * calculate : Reaction-Diffusion calculate.
   */
  public void calculate() {
    // swap
    curr = (curr == 0) ? 1 : 0;
    prev = (prev == 0) ? 1 : 0;

    // calculate
    for (int x = 1; x < xGrid - 1; x++) {
      for (int y = 1; y < yGrid - 1; y++) {
        float vA = rd[x][y][a][curr];
        float vB = rd[x][y][b][curr];
        rd[x][y][a][prev] = vA + dA * laplace(a, x, y) - vA * vB * vB + feed * (1 - vA);
        rd[x][y][b][prev] = vB + dB * laplace(b, x, y) + vA * vB * vB - (kill + feed) * vB;

        rd[x][y][a][prev] = constrain(rd[x][y][a][prev], 0.0, 1.0);
        rd[x][y][b][prev] = constrain(rd[x][y][b][prev], 0.0, 1.0);
      }
    }
  }

  /**
   * laplace : laplace equation in Reaction-Diffusion calculate.
   * @param  _val   : value of A or B.
   * @param  _x, _y : coordinate.
   */
  public float laplace(int _val, int _x, int _y) {
    float vSum = 0.0;
    vSum += rd[_x][_y][_val][curr] * -1;
    vSum += rd[_x - 1][_y][_val][curr] * 0.2;
    vSum += rd[_x + 1][_y][_val][curr] * 0.2;
    vSum += rd[_x][_y + 1][_val][curr] * 0.2;
    vSum += rd[_x][_y - 1][_val][curr] * 0.2;
    vSum += rd[_x - 1][_y - 1][_val][curr] * 0.05;
    vSum += rd[_x + 1][_y - 1][_val][curr] * 0.05;
    vSum += rd[_x + 1][_y + 1][_val][curr] * 0.05;
    vSum += rd[_x - 1][_y + 1][_val][curr] * 0.05;
    return vSum;
  }

  /**
   * drawLines : draw a line between particles that have similar attributes.
   * @param  _rd            : attributes array.
   * @param  _fX, _fY       : coordinate of from point.
   * @param  _tX, _tY       : coordinate of from point.
   * @param  _xMult, _yMult : particle size.
   * @param  _diff          : particle attibute value difference.
   */
  public void drawLines(float[][][][] _rd, int _fX, int _fY, int _tX, int _tY, float _xMult, float _yMult, float _diff) {
    if (
        abs(_rd[_fX][_fY][b][prev] - _rd[_tX][_tY][b][prev]) < _diff &&
        abs(_rd[_fX][_fY][b][prev] - _rd[_tX][_tY][b][prev]) < _diff
        ) {
      line(_fX * _xMult, _fY * _yMult, _tX * _xMult, _tY * _yMult);
    }
  }

  /**
   * drawResults : draw Reaction-Diffusion calculation results.
   */
  public void drawResults() {

    float diff = 0.1;  // attibute value difference
    
    pushMatrix();
    translate(width * 0.5 / xGrid, height * 0.5 / yGrid);
    noStroke();
    for (int x = 0; x < xGrid; x++) {
      for (int y = 0; y < yGrid; y++) {
        float fHue = map(rd[x][y][a][prev], 0.0, 1.0, -120.0, 120.0);
        float fSat = map(rd[x][y][b][prev], 0.0, 1.0, 0.0, 80.0);
        float fBri = map(abs(rd[x][y][a][prev] - rd[x][y][b][prev]), 0.0, 1.0, 0.0, 90.0);
        fill((hueBase + 360.0 + fHue) % 360, fSat, fBri, 100);
        ellipse(x * xMult, y * yMult, xMult * 0.2, yMult * 0.2);
      }
    }

    noFill();
    strokeWeight(max(xMult, yMult) * 0.3);
    for (int x = 1; x < xGrid - 1; x++) {
      for (int y = 1; y < yGrid; y++) {
        float fHue = map(rd[x][y][a][prev], 0.0, 1.0, -60.0, 60.0);
        float fSat = map(rd[x][y][b][prev], 0.0, 1.0, 20.0, 50.0);
        float fBri = map(abs(rd[x][y][a][prev] - rd[x][y][b][prev]), 0.0, 1.0, 30.0, 80.0);
        if (fSat > 30.0) {
          stroke((hueBase + 360.0 + fHue) % 360, fSat, fBri, 100);
          drawLines(rd, x, y, x - 1, y - 1, xMult, yMult, diff);
          drawLines(rd, x, y, x, y - 1, xMult, yMult, diff);
          drawLines(rd, x, y, x + 1, y - 1, xMult, yMult, diff);
          drawLines(rd, x, y, x + 1, y, xMult, yMult, diff);
        }
      }
    }
    popMatrix();
  }
  
}

/**
 * casing : draw fancy casing
 */
private void casing() {
  fill(0.0, 0.0, 0.0, 0.0);
  strokeWeight(50.0);
  stroke(0.0, 0.0, 30.0, 100.0);
  rect(0.0, 0.0, width, height);
  strokeWeight(40.0);
  stroke(0.0, 0.0, 100.0, 100.0);
  rect(0.0, 0.0, width, height);
  noStroke();
  noFill();
}


/*
Copyright (C) 2020- deconbatch

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>
*/






One of the Reaction-Diffusion implementation.

One of the Reaction-Diffusion implementation.

 

Next Post Previous Post
No Comment
Add Comment
comment url