It's a creative coding example using the Turing Pattern.

Weird pattern image made with Processing.


The Turing Pattern on the window will scare you.

It's a creative coding animation work that creates weird image. The code is written in the 'Processing'.

I tried to make an animation with Turing Pattern. I used the Gray-Scott model. And change feed/kill parameters with 2D Perlin noise.

This code does not display any images on the screen but generates image files in frames directory. It may take a very long time to draw.

 

Reference book.








 

The 'Processing' example code.

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.

// Thru the Window.
// @author @deconbatch
// @version 0.1
// Processing 3.2.1
// 2018.09.02

/* main -------------------- */
void setup() {

  size(720, 720);
  colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
  blendMode(DIFFERENCE);
  rectMode(CENTER);
  smooth();
  noLoop();
  noStroke();

}

void draw() {
  
  int   frameCntMax = 15 * 6;
  Ecosystem eco = new Ecosystem(frameCntMax);

  for (int frameCnt = 0; frameCnt < frameCntMax; ++frameCnt) {
    eco.setTime(frameCnt);
    eco.initSchale();
    eco.plant();
    eco.culture();
    eco.observe();
    saveFrame("frames/" + String.format("%04d", frameCnt) + ".png");
  }

  exit();

}

/*  -------------------- */
public class Ecosystem {

  private Cell[][]    cells;
  private float[][][] initVs;
  private float hueBase;
  private float cellSize;
  private int   canvasW;
  private int   canvasH;
  private int   frameCntMax;
  private int   frameCnt;
  
  Ecosystem(int frameCntMax) {

    this.frameCntMax = frameCntMax;
    frameCnt = 0;

    cellSize = 3.0;
    hueBase  = random(360.0);

    canvasW  = floor(width / cellSize);
    canvasH  = floor(height / cellSize);
    
    cells    = new Cell[canvasW][canvasH];
    initVs   = new float[2][canvasW][canvasH];

    // constract cells
    for (int x = 0; x < canvasW; x++) {
      for (int y = 0; y < canvasH; y++) {
        cells[x][y] = new Cell();
        initVs[0][x][y] = 0.14 * (x % 5);
        initVs[1][x][y] = 0.05 * (y % 10);
        cells[x][y].setU(initVs[0][x][y]);
        cells[x][y].setV(initVs[1][x][y]);
      }
    }
    
    // set neighbor cells
    for (int x = 0; x < canvasW; x++) {
      for (int y = 0; y < canvasH; y++) {
        cells[x][y].setNeighbor(new Cell[] {
            // 8 directions
            cells[max(x-1,0)][max(y-1,0)],
            cells[min(x+1,canvasW-1)][max(y-1,0)],
            cells[max(x-1,0)][min(y+1,canvasH-1)],
            cells[min(x+1,canvasW-1)][min(y+1,canvasH-1)],
            cells[x][max(y-1,0)],
            cells[x][min(y+1,canvasH-1)],
            cells[max(x-1,0)][y],
            cells[min(x+1,canvasW-1)][y]
          });
      }
    }
  }

  public void setTime(int frameCnt) {
    this.frameCnt = frameCnt;
  }

  public void initSchale() {
    for (int x = 0; x < canvasW; x++) {
      for (int y = 0; y < canvasH; y++) {
        cells[x][y].setU(initVs[0][x][y]);
        cells[x][y].setV(initVs[1][x][y]);
      }
    }
  }
  
  public void plant() {
    float frameRate = sin(TWO_PI * map(frameCnt, 0, frameCntMax, 0.0, 1.0));
    float easeRate  = sin(TWO_PI * easeInOutCubic(map(frameCnt, 0, frameCntMax, 0.0, 1.0)));
    for (int x = 0; x < canvasW; x++) {
      for (int y = 0; y < canvasH; y++) {
        // change Gray-Scott model parameters with noise
        cells[x][y].setFeed(map(noise(x * 0.008 + easeRate * 0.1, y * 0.002 - frameRate * 0.1), 0.0, 1.0, 0.041, 0.118));
        cells[x][y].setKill(map(noise(x * 0.002 - frameRate * 0.1, y * 0.008 + easeRate * 0.1), 0.0, 1.0, 0.056, 0.067));
      }
    }
  }    

  float easeInOutCubic(float t) {
    t *= 2.0;
    if (t < 1.0) {
      return pow(t, 3) / 2.0;
    }
    t -= 2.0;
    return (pow(t, 3) + 2.0) / 2.0;
  }

  public void culture() {

    int cultureTimeMax = 800;

    for (int cultureTime = 0; cultureTime < cultureTimeMax; cultureTime++) {
      for (int x = 0; x < canvasW; x++) {
        for (int y = 0; y < canvasH; y++) {
          cells[x][y].laplacian();
        }
      }
      for (int x = 0; x < canvasW; x++) {
        for (int y = 0; y < canvasH; y++) {
          cells[x][y].react();
        }
      }
    }
  }

  public void observe() {
    background(0.0, 0.0, 20.0, 100.0);
    for (int x = 0; x < canvasW; x++) {
      for (int y = 0; y < canvasH; y++) {
        fill(
             hueBase,
             10.0,
             cells[x][y].getStandardU() * 100.0,
             100.0
             );
        rect(
             x * cellSize,
             height - y * cellSize,
             cellSize,
             cellSize
             );

        fill(
             hueBase,
             40.0,
             cells[x][y].getStandardV() * 100.0,
             100.0
             );
        rect(
             x * cellSize,
             height - y * cellSize,
             cellSize,
             cellSize
             );

      }
    }
  }
}

/* Gray-Scott model -------------------- */
public class Cell {
  private float difU  = 0.001;
  private float difV  = 0.000238;
  private float dt    = 1.0;
  private float dxPow = pow(0.085, 2);
  private float feed  = 0.0;
  private float kill  = 0.0;
  
  private float valU;
  private float valV;
  private float lapU;
  private float lapV;

  private Cell[] neighbor;

  Cell() {
    valU = 0.0;
    valV = 0.0;
    resetLaplacian();
  }

  private void resetLaplacian() {
    lapU = 0.0;
    lapV = 0.0;
  }

  public void setFeed(float init) {
    feed = init;
  }

  public void setKill(float init) {
    kill = init;
  }

  public void setV(float init) {
    valV = init;
  }

  public void setU(float init) {
    valU = init;
  }

  public void setNeighbor(Cell[] pNeighbor) {
    neighbor = new Cell[pNeighbor.length];
    for (int i = 0; i < pNeighbor.length; ++i) {
      neighbor[i] = pNeighbor[i];
    }
  }

  public float getRawU() {
    return valU;
  }

  public float getRawV() {
    return valV;
  }

  public float getStandardU() {
    return constrain(valU, 0.0, 1.0);
  }

  public float getStandardV() {
    return constrain(valV, 0.0, 1.0);
  }

  public void laplacian() {
    float sumU = 0.0;
    float sumV = 0.0;
    for (int i = 0; i < neighbor.length; ++i) {
      sumU += neighbor[i].getRawU();
      sumV += neighbor[i].getRawV();
    }
    lapU = (sumU - valU * neighbor.length) / dxPow;
    lapV = (sumV - valV * neighbor.length) / dxPow;
  }

  public void react() {
    float reaction = valU * valV * valV;
    float inflow   = feed * (1.0 - valU);
    float outflow  = (feed + kill) * valV;
    valU += dt * (difU * lapU - reaction + inflow);
    valV += dt * (difV * lapV + reaction - outflow);
    resetLaplacian();
  }
}

/*
  Copyright (C) 2018- 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/>
*/



 

Next Post Previous Post
No Comment
Add Comment
comment url