BioErrorLog Tech Blog

試行錯誤の記録

Generative Art #6 - Processing作品

おはよう。@bioerrorlogです。

ProcessingによるGenerative Art作品
6作目を記録します。

自作品まとめはこちら: www.bioerrorlog.work

Output

f:id:BioErrorLog:20191216083138p:plain f:id:BioErrorLog:20191216083206p:plain f:id:BioErrorLog:20191216083232p:plain f:id:BioErrorLog:20191216083258p:plain

フル解像度/その他出力パターンはこちら:
Generative_6 - BioErrorLog - pixiv


Material

使用言語: Processing 3.5.3

Processingというプログラミング言語に聞き覚えがない、という方は是非こちらをご参考ください:
www.bioerrorlog.work


Source Code

GitHubはこちら

Cell[][] _cellArray;
int _cellSize = 1; // Cellの大きさ(pixel)
int _numX, _numY; // ディスプレイのCell格子


void setup() { 
  size(1920, 1080);
  _numX = floor(width/_cellSize);
  _numY = floor(height/_cellSize);
  restart();
} 


void restart() {
  // _cellArrayに画面分のCellを入れる
  _cellArray = new Cell[_numX][_numY];    
  for (int x = 0; x<_numX; x++) {
    for (int y = 0; y<_numY; y++) {    
      Cell newCell = new Cell(x, y);  
      _cellArray[x][y] = newCell;      
    }               
  }                 

  
  for (int x = 0; x < _numX; x++) {
    for (int y = 0; y < _numY; y++) {  
      
      int above = y-1;        
      int below = y+1;        
      int left = x-1;         
      int right = x+1;            
      
      // 画面端の処理
      if (above < 0) { above = _numY-1; }    
      if (below == _numY) { below = 0; } 
      if (left < 0) { left = _numX-1; }  
      if (right == _numX) { right = 0; } 

     _cellArray[x][y].addNeighbour(_cellArray[left][above]);    
     _cellArray[x][y].addNeighbour(_cellArray[left][y]);        
     _cellArray[x][y].addNeighbour(_cellArray[left][below]);    
     _cellArray[x][y].addNeighbour(_cellArray[x][below]);   
     _cellArray[x][y].addNeighbour(_cellArray[right][below]);   
     _cellArray[x][y].addNeighbour(_cellArray[right][y]);   
     _cellArray[x][y].addNeighbour(_cellArray[right][above]);   
     _cellArray[x][y].addNeighbour(_cellArray[x][above]);       
    }
  }
}


void draw() {
  background(200);
                    
  for (int x = 0; x < _numX; x++) {
    for (int y = 0; y < _numY; y++) {
     _cellArray[x][y].calcNextState();
    }
  }
                        
  translate(_cellSize/2, _cellSize/2);     
                        
  for (int x = 0; x < _numX; x++) {
    for (int y = 0; y < _numY; y++) {
     _cellArray[x][y].drawMe();
    }
  }
}


void keyPressed(){
    /*
    ENTERキー押下: 画像を保存する
    BACKSPACEキー押下: setup()を呼ぶ
    */
    
    if (keyCode == ENTER){
        saveFrame("generative_5_####.png");
    }
    if (keyCode == BACKSPACE){
        setup();
    }
}


class Cell {
  float x, y;
  float state;         
  float nextState;  
  float lastState = 0; 
  Cell[] neighbours;
  
  Cell(float ex, float why) {
    x = ex * _cellSize;
    y = why * _cellSize;
    
    // Cellの初期状態を定義
    // 画面の真ん中のCellは255, それ以外は2
    if(ex == width/2 && why == height/2){
      nextState = 255;
    }else{
      nextState = 2;
    }

    state = nextState;
    neighbours = new Cell[0];
  }
  
  void addNeighbour(Cell cell) {
    neighbours = (Cell[])append(neighbours, cell); 
  }
  
  void calcNextState() {
    /*
    1. もし隣接するセルの状態の平均が255であれば状態は0に
    2. もし隣接するセルの状態の平均が0であるなら状態は255に
    3. そうでなければ、新しい状態=現在の状態+隣接セルの状態の平均ー前の状態の値
    4. もし新しい状態が255を超えたら255にし、
    5. もし新しい状態が0以下ならそれを0にする
    */
                
    float total = 0;              
    for (int i=0; i < neighbours.length; i++) { 
       total += neighbours[i].state;        
    }                   
    float average = int(total/8);
                
    if (average == 255) { // 1.
      nextState = 0;
    } else if (average == 0) {
      nextState = 255; // 2.
    } else {
      nextState = state + average;
      if (lastState > 0) { nextState -= lastState; } // 3.
      if (nextState > 255) { nextState = 255; } // 4.
      else if (nextState < 0) { nextState = 0; } // 5.
    }
 
    lastState = state;  
  }
  
  void drawMe() {
    state = nextState;
    noStroke();
    fill(state);    
    rect(x, y, _cellSize, _cellSize);
  }
}

Discussion

マット・ピアソン「ジェネラティブ・アート―Processingによる実践ガイド」7章で紹介される、セルオートマトンのケーススタディを改変して作成。

画面中央のピクセルから徐々にセルオートマトンを波及させていきます。

今回のセルオートマトンの規則は次の通り(「ジェネラティブ・アート―Processingによる実践ガイド」より引用)。

  • もし隣接するセルの状態の平均が255であれば状態は0に
  • もし隣接するセルの状態の平均が0であるなら状態は255に
  • そうでなければ、新しい状態=現在の状態+隣接セルの状態の平均ー前の状態の値
  • もし新しい状態が255を超えたら255にし、もし新しい状態が0以下ならそれを0にする


脳の染色画像のような、あるいは悪い夢を見ているときのような、不思議で不気味なパターンが面白いところです。


See also

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

Reference


Generative Art #5 - Processing作品

おはよう。@bioerrorlogです。

ProcessingによるGenerative Art作品
5作目を記録します。

自作品まとめはこちら: www.bioerrorlog.work

Output

f:id:BioErrorLog:20191214201153p:plain f:id:BioErrorLog:20191214201733p:plain f:id:BioErrorLog:20191214201814p:plain f:id:BioErrorLog:20191214201836p:plain

フル解像度/その他出力パターンはこちら:
Generative_5 - BioErrorLog - pixiv


Material

使用言語: Processing 3.5.3

Processingというプログラミング言語に聞き覚えがない、という方は是非こちらをご参考ください:
www.bioerrorlog.work


Source Code

GitHubはこちら

int _num = 50; // 1クリックで生成するCircleの数
Circle[] _circleArr = {};


void setup(){
    size(1920,1080);
    background(255);
    smooth();
    strokeWeight(1);

    addCircles(); // はじめにCircleを生成
}


void draw(){
    // 配列に格納されたCircleすべてをupdate

    for (int i=0; i<_circleArr.length; i++){
        Circle thisCircle = _circleArr[i];
        thisCircle.updateMe();
    }
}


void keyPressed(){
    /*
    ENTERキー押下: 画像を保存する
    BACKSPACEキー押下: setup()を呼ぶ
    */
    
    if (keyCode == ENTER){
        saveFrame("generative_5_####.png");
    }
    if (keyCode == BACKSPACE){
        setup();
    }
}


void mouseReleased(){
    // マウスクリックでCircleを追加生成
    addCircles();
}


void addCircles() {
    // Circleを生成、配列に加える

    for (int i=0; i< _num; i++){
        Circle thisCircle = new Circle();
        _circleArr = (Circle[])append(_circleArr, thisCircle);
    }
}


class Circle{
    /*
    このCircle自身は描画されない
    他のCircleとの重複部分に円(または四角形)を描画する
    */

    float x, y;
    float xMove, yMove;
    float radius;
    float alpha;
  
    Circle(){
        x = random(width);
        y = random(height);

        xMove = random(10) - 5;
        yMove = random(10) - 5;

        radius = random(500) + 50;
    }


    void updateMe(){
        x += xMove;
        y += yMove;

        // 画面外に出たときは反対側に移動
        if (x > (width + radius)){x = 0 - radius;}
        if (x < (0 - radius)){x = width + radius;}
        if (y > (height + radius)){y = 0 - radius;}
        if (y < (0 - radius)){y = height + radius;}

        // 他の円と接触しているとき、その接触範囲に円(または四角)を描画する
        for (int i=0; i<_circleArr.length; i++){
            Circle otherCircle = _circleArr[i];

            if (otherCircle != this){
                float distance = dist(x, y, otherCircle.x, otherCircle.y);
                float overLap = distance - radius - otherCircle.radius;

                if ((overLap < 0)){ // 他の円と接触している場合
                    float midX, midY;
                    midX = (x + otherCircle.x) / 2;
                    midY = (y + otherCircle.y) / 2;

                    // 円または四角の描画
                    alpha = random(3);
                    stroke(0, alpha);
                    // stroke(random(255), random(255), random(255), alpha); // 微妙に色をつける
                    noFill();
                    overLap *= -1; // overLapを正の値に
                    rect(midX, midY, overLap, overLap); // 重複分の幅を持った四角を描画
                    // ellipse(midX, midY, overLap, overLap); // 重複分の幅を持った円を描画
                }
            }
        }
    }
}

Discussion

マット・ピアソン「ジェネラティブ・アート―Processingによる実践ガイド」6章で紹介されるオブジェクト指向プログラミングのケーススタディを改変して作成。

Circleクラスから円を生成し、それぞれの円の重複部分に、新たに円や四角形を薄く描画していきます(Circleクラスから生成した円自身は描画しません)。

Circleクラスから生成される円自身はごく簡単な挙動を取りますが、それらの相互作用から現れる新たな円は、えんぴつで描き殴ったような予測不能なパターンをみせる、というところに風情を感じます。


See also

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

Reference


Generative Art 自作品まとめ - Processing

こんにちは、@bioerrorlogです。

主にProcessingで制作したGenerative artの作品/サンプルを、こちらにリストアップしていきます。
ソースコード/出力結果は各詳細ページにて記述しています。

Processingというプログラミング言語に聞き覚えがない、という方は是非こちらもご参考ください:
www.bioerrorlog.work

作品リスト

GenerativeArtNFT

https://cdn-ak.f.st-hatena.com/images/fotolife/B/BioErrorLog/20220702/20220702181725.png

GenerativeArtNFTで使ったアート画像生成ロジックをまとめています。

TokenIdをinputとして無限で多様なGenerative Artを生成する、というのがやりたかったことです。

www.bioerrorlog.work


Boids Flocking

エサを追いかけるような、可愛げのあるboidsたちの動きがなかなかのお気に入りです。

※こちらはProcessingの実装ではなく、Godot Engineを用いた実装です。詳しい実装は以下の記事をご覧ください。

www.bioerrorlog.work


Generative #14

序盤の規則的な四角い造形から、斜め方向に走るパターンが現れ、徐々に雨降る道路の水たまりのような、複雑な状態になっていく過程が面白いところです。

www.bioerrorlog.work


Generative #13

せわしなく動くクラゲの大群のような、あるいは解像度の低い煙のような雰囲気が面白いです。

www.bioerrorlog.work


Generative #12

生き物の初期胚が必死さが見えるような、少し神秘的でどこか微笑ましい雰囲気が気に入っています。

www.bioerrorlog.work


Generative #11

粒子が中央に集まったあともそのまま通り過ぎては拡散し、そしてまた中央へ収縮をはじめる、という繰り返しが気持ちいいです。

www.bioerrorlog.work


Generative #10

滑らかな樹の表面のような質感が好きです。パラメータをいじることで多様な絵を出力しています。

www.bioerrorlog.work


Generative #9

一つ一つの線の長さやノイズにかけ合わせる数の大きさによって、出力の雰囲気が大きく異なるのも面白いところです。

www.bioerrorlog.work


Generative #8

写真をもとに、油絵のような雰囲気の出力を出しました。 様々な画風も演出できそうで面白いです。

www.bioerrorlog.work


Generative #7

モデル全体がまるで生きているような、一定の拍動を打つのが面白いところです。 静止画として切り出すと、各タイミングで全く違った絵になるのも不思議なもの。

www.bioerrorlog.work


Generative #6

脳の染色画像のような、あるいは悪い夢を見ているときのような、不思議で不気味なパターンが面白いところです。

www.bioerrorlog.work


Generative #5

えんぴつで描き殴ったような、予測不能なパターンに風情を感じます。 www.bioerrorlog.work


Generative #4

sinやcosを利用して線を薄く重ねることで、綺麗なパターンが現れてきます。

www.bioerrorlog.work


Generative #3

チェスのポーンの駒のような、滑らかながら唐突な変化を見せる表面のパターンが好きです。

www.bioerrorlog.work


Generative #2

シルクの布のような、滑らかで涼しげなパターンがお気に入りです。

www.bioerrorlog.work


Generative #1

薄く、細くらせんを重ね合わせたシンプルなモデルです。 各要素にrandom()やnoise()を使い、ランダムでふわふわに見える中にもある特定のパターンが表れてくるのが面白いところでした。

www.bioerrorlog.work


関連URL

ソースコードはGitHubにもまとめています: github.com

作成した動画作品はYouTubeにまとめています:
www.youtube.com

高解像度の出力結果はこちらPixivにまとめています: www.pixiv.net


Generative Art #4 - Processing作品

おはよう。@bioerrorlogです。

ProcessingによるGenerative Art作品
4作目を記録します。

自作品まとめはこちら: www.bioerrorlog.work

Output

f:id:BioErrorLog:20191212081809p:plain f:id:BioErrorLog:20191212081801p:plain

フル解像度/その他出力パターンはこちら:
Generative_4 - BioErrorLog - pixiv


Material

使用言語: Processing 3.5.3

Processingというプログラミング言語に聞き覚えがない、という方は是非こちらをご参考ください:
www.bioerrorlog.work


Source Code

GitHubはこちら

import processing.opengl.*;

int _radius = 400;

void setup(){
  size(1920, 1080, OPENGL); // OPENGLで3D描画
  background(255);
  stroke(0, 10);
  strokeWeight(0.01);
}


void draw(){
  /*
  3次元の球体をぐるぐる回転
  sinやconを利用した線の描画を薄く重ねる
  */

  translate(width/2, height/2, 0); // 出力範囲の中心を描画位置にする
  rotateX(frameCount * 0.04);
  rotateY(frameCount * 0.04);
  
  float s = 0;
  float t = 0;
  float lastX = 0;
  float lastY = 0;
  float lastZ = 0;

  while ( t < 180){ // OUTPUT1枚目はwhile条件 t<90
    s += 18;
    t += 1;
    float radianS = radians(s);
    float radianT = radians(t);
    
    float thisX = _radius * cos(radianS) * sin(radianT); // ここら辺を変えると多様なパターンが見られる
    float thisY = _radius * sin(radianS) * sin(radianT);
    float thisZ = _radius * cos(radianT);
    
    if (lastX != 0){
      line(thisX, thisY, thisZ, lastX, lastY, lastZ);
    }
    lastX = thisX;
    lastY = thisY;
    lastZ = thisZ;
  }
}


void keyPressed(){
  /*
  ENTERキー押下: 画像を保存する
  BACKSPACEキー押下: setup()を呼んでモデルをリセットする
  */

  if (keyCode == ENTER){
    saveFrame("generative_4_####.png");
  }
  if (keyCode == BACKSPACE){
    setup();
  }
}

Discussion

はじめての3D描画をOpenGLを用いて行いました。
sinやcosを利用して線を薄く重ねることで、綺麗なパターンが現れてきます。

OUTPUTの1枚目は各フレーム90度の球体の回転、2枚目は180度の回転を加えています。

私は1枚目のほうが、立体感が感じられて好きです。


See also

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

Reference


Generative Art #3 - Processing作品

おはよう。@bioerrorlogです。

ProcessingによるGenerative Art作品
3作目を記録します。

自作品まとめはこちら: www.bioerrorlog.work

Output

f:id:BioErrorLog:20191211070556p:plain f:id:BioErrorLog:20191211070618p:plain

フル解像度/その他出力パターンはこちら:
Generative_3 - BioErrorLog - pixiv


Material

使用言語: Processing 3.5.3

Processingというプログラミング言語に聞き覚えがない、という方は是非こちらをご参考ください:
www.bioerrorlog.work


Source Code

GitHubはこちら

float _xStart;
float _xNoise, _yNoise;
float _radius;
float _ang;
float _centX, _centY;

void setup(){
  size(1920,1080); // 壁紙サイズ
  background(255); // 255: 白 0にすれば黒
  smooth();
  
  _xStart = random(10);
  _xNoise = _xStart;
  _yNoise = random(10);
  _radius = random(1);
  _ang = random(10);
  _centX = width /2;
  _centY = height /2;
}


void drawPoint(float x, float y, float noiseFactor){
  /*
  x, yを中心座標としてグレーの円を描く
  noiseFactorに渡すnoise関数で各要素に揺らぎを与える
  */

  pushMatrix();
  translate(x, y);
  rotate(noiseFactor * radians(360*4));

  float edgeSize = noiseFactor * 500;
  float grey = 50 + (noiseFactor * 120);
  float alpha = 100 + (noiseFactor * 120);

  noStroke();
  fill(grey, alpha);
  ellipse(0,0, edgeSize, edgeSize);

  popMatrix();
}

void draw(){
  _yNoise += 0.01;
  _xNoise += 0.01;
  _ang += 0.01;
  _radius += 1;

  float rad = radians(noise(_ang));
  drawPoint(_centX/2 + cos(rad) * _radius, _centY, noise(_xNoise,_yNoise)); // noise()を二次元にしたことに特に理由はない
}


void keyPressed(){
  /*
  ENTERキー押下: 画像を保存する
  BACKSPACEキー押下: モデルをリセットする
  */

  if (keyCode == ENTER){
    saveFrame("generative_3_####.png");
  }
  if (keyCode == BACKSPACE){
    setup();
  }
}

Discussion

丸を少しずつ右にずらしながら重ねたモデルです。
各要素の定義にnoise()を加えることで、丸の半径やグレーの色合い、フレームごとの丸の移動距離に揺らぎが生じます。

チェスのポーンの駒のような、滑らかながら唐突な変化を見せる表面のパターンが好きです。


See also

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

Reference


Generative Art #2 - Processing作品

おはよう。@bioerrorlogです。

ProcessingによるGenerative Art作品
2作目を記録します。

自作品まとめはこちら: www.bioerrorlog.work

Output

f:id:BioErrorLog:20191209232623p:plain f:id:BioErrorLog:20191209232705p:plain f:id:BioErrorLog:20191209232729p:plain f:id:BioErrorLog:20191209232756p:plain

フル解像度/その他出力パターンはこちら:
Generative_2 - BioErrorLog - pixiv


Material

使用言語: Processing 3.5.3

Processingというプログラミング言語に聞き覚えがない、という方は是非こちらをご参考ください:
www.bioerrorlog.work


Source Code

GitHubはこちら

float _angleNoise, _radiusNoise;
float _xNoise, _yNoise;

float _angle, _radius;
float _strokeCol = 254;
int _strokeChange = -1;


void setup(){
  size(1920,1080);
  background(255);
  smooth();
  noFill();
  
  _angleNoise = random(10);
  _radiusNoise = random(10);
  _xNoise = random(10);
  _yNoise = random(10);
}


void draw(){
  _radiusNoise += 0.005;
  _radius = (noise(_radiusNoise) * 1000) + 100;
  
  _angleNoise += 0.005;
  _angle += (noise(_angleNoise) * 2) - 1;
  if (_angle > 360){_angle -= 360;}
  if (_angle < 0){_angle += 360;}
  
  _xNoise += 0.01;
  _yNoise += 0.01;
  float centerX = width / 2 + (noise(_xNoise) * 100) - 50;
  float centerY = height / 2 + (noise(_yNoise) * 100) - 50;
  
  float rad = radians(_angle);
  float x1 = centerX + (_radius * cos(rad) *2);
  float y1 = centerY + (_radius * sin(rad));
  
  float opprad = rad + PI;
  float x2 = centerX + (_radius * cos(opprad) *2);
  float y2 = centerY + (_radius * sin(opprad));  
  
  _strokeCol += _strokeChange;
  if (_strokeCol > 254){_strokeChange = -1;}
  if (_strokeCol < 1){_strokeChange = 1;}
  stroke(_strokeCol, 10);
  strokeWeight(2);
  line(x1, y1, x2, y2);
}


void keyPressed(){
  if (keyCode == ENTER){
    saveFrame("generative_2-####.png");
  }
}

Discussion

マット・ピアソン「ジェネラティブ・アート―Processingによる実践ガイド」で紹介されるケーススタディ「Wave Clock」を少し改変して作成。

ひとつひとつの線の描画角度の差分を小さく、線の透明度を薄くすることで、シルクの布のような滑らかなパターンが現れました。

// 角度差を+-1以内とする
_angle += (noise(_angleNoise) * 2) - 1;

// 線の透明度(alpha)を低く(10)抑える
stroke(_strokeCol, 10);


See also

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

Reference


Generative Art #1 - Processing作品

おはよう。@bioerrorlogです。

ProcessingによるGenerative Art作品
記念すべき第一作目を記録します。

自作品まとめはこちら: www.bioerrorlog.work

Output

f:id:BioErrorLog:20191208205449p:plain

フル解像度/その他出力パターンはこちら:
Generative_1 - BioErrorLog - pixiv


Material

使用言語: Processing 3.5.3

Processingというプログラミング言語に聞き覚えがない、という方は是非こちらをご参考ください:
www.bioerrorlog.work


Source Code

GitHubはこちら

void setup(){
  size(1920,1080);
  background(0);
  strokeWeight(0.2);
  smooth();
}


void draw(){
  int centx = width / 2;
  int centy = height / 2;
  float x, y;
  for (int i = 0; i < 10; i++){
    float lastx = -999;
    float lasty = -999;
    float radiusNoise = random(10);
    float radius = 10;
    stroke(255, random(10));
    int startAngle = int(random(360));
    int endAngle = int(random(1440)) + 360 * 6;
    int angleStep = int(random(3)) + 1;
    for (float ang = startAngle; ang < endAngle; ang += angleStep){
      radiusNoise += 0.05;
      radius += 0.5;
      float thisRadius = radius + (noise(radiusNoise) * 200) - 100;
      float rad = radians(ang);
      x = (centx + (thisRadius * cos(rad)));
      y = centy + (thisRadius * sin(rad));
      if (lastx > -999){
        line(x, y, lastx, lasty);
      }
      lastx = x;
      lasty = y;
    } 
  }

  saveFrame("frames/generative_1_#####.png"); // 各フレームで画像を保存 
}

Discussion

薄く、細くらせんを重ね合わせたシンプルなモデルです。
各要素にrandom()やnoise()を使い、ランダムでふわふわに見える中にもある特定のパターンが表れてくるのが面白いところでした。

例えば中心部分では、上下左右に走るパターンが現れます(Fig. 1)。

f:id:BioErrorLog:20191209083349p:plain
Fig. 1 中心部のパターン

周辺部では、放射状に走るまっすぐな線のパターンが見られます(Fig. 2)。

f:id:BioErrorLog:20191209083526p:plain
Fig. 2 周辺部のパターン

これらのパターンはおそらくnoise()によるものなのでしょうが、どういう原理で起きているのか、いまの私にはよくわかりません。

noise()やrandom()の裏で動いているアルゴリズムがどんなものなのか、興味がそそられます。


See also

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work


Reference