数理シミュレーション

ここまでの内容を経て,プログラム(スケッチ)を通じて視覚的な形状を作り出すことを, 再構成をキーワードに行ってきました.結果として,このような手法は何かをデザインする 手前における,シミュレーションやプロトタイピングとしての機能があることがわかります. 例えば先程のモンドリアンのスケッチでは,グリッドやカラーリングの様々なバリエーションを自動で 生成し,自分で気に入る結果を簡単に探索することができます.手を使って描画するよりも 非常に高速になります.

糸掛け数楽アートとは,シンプルなルールに則って円形に配置されたピンに糸を掛けることで,様々な形状を作り出す作品の 名称です.

1すすめて,2すすめる

糸掛けのシンプルな例として,糸を掛けるピンの番号(円の各頂点)を $ P_{2n-1}, P_{2n}, ただし n \in \mathcal{N} $ とした場合, $$ P_{2n-1} = n \\ P_{2n} = 2n \\ $$ を $P_n$ が円を一周するまで続け,通った頂点を線分で結ぶ.

これがアルゴリズムになります.実際に糸掛けをする場合は,円を60分割した各頂点を使いますが, 今回はプログラム上わかりやすく,360/5 = 72 頂点に分割して考えます.以上のアルゴリズムを プログラムに記述すると下記の通りです.

sample01.pde
void setup() {
  size(500, 500);
}
void draw() {
  int step = 2;
  background(255);
 
  float r = 0.9*width/2;
 
  noFill();
  stroke(24, 48, 151, 150);
  beginShape(LINES);
  int i, j;
  for ( i = 0, j = 0; i < 360; i=i+5, j=j+5*step ) {
    vertex(width/2 + r*cos(2*3.14*(i/360.0)), height/2 + r*sin(2*3.14*(i/360.0)));
    vertex(width/2 + r*cos(2*3.14*(j/360.0)), height/2 + r*sin(2*3.14*(j/360.0)));
  }
  endShape(CLOSE);
}
 
void keyPressed()
{
  save("output.png");
}

beginShape(LINES)は糸掛けの意味からすると、厳密にはbeginShape()としたほうがよいのですが、 こちらで記述すると透明度が再現されない問題がありました。原因はまだわかっていないのですが、みなさんも お気をつけください。

課題

上記の糸掛けプログラムのパラメータを調整することで、一枚の糸掛け絵を提出してください。上記プログラムではプログラムの実行中にキーボードを押す(どこでもよい)とpdeファイルと同じ場所に output.png というファイルが出力されます。

上記のプログラムでは、数列的なアルゴリズムでした。一つ進む点、2つ進む点を線でつなげた結果、ユニークな模様が描けるものでした。次のアルゴリズムは、画素情報をベースとして、自身の画素とその周辺画素との関係から自身の画素情報を更新するアルゴリズムです。これは古くから存在するGAME OF LIFE(https://ja.wikipedia.org/wiki/ライフゲーム)と呼ばれるアルゴリズムになります。一般にセル・オートマトンなどとも呼ばれています。https://ja.wikipedia.org/wiki/セル・オートマトン

GAME OF LIFE

GAME OF LIFEとはセル・オートマトン(格子上セルそれぞれに同一のルールを与えるアルゴリズム)の一種になります。詳しくはwikipediaを参照してください。 ルールは下記の通りです。

  • 誕生
    • 死んでいるセルに隣接する生きたセルがちょうど3つあれば、次の世代が誕生する。
  • 生存
    • 生きているセルに隣接する生きたセルが2つか3つならば、次の世代でも生存する。
  • 過疎
    • 生きているセルに隣接する生きたセルが1つ以下ならば、過疎により死滅する。
  • 過密
    • 生きているセルに隣接する生きたセルが4つ以上ならば、過密により死滅する。

では実際にプログラムを記述してみます。下記コードChallengeのウェブサイトにてダニエルがテンションアゲアゲでライブコードしてくれるので 一緒にやってみましょう。

波紋のシミュレーション(セル・オートマトンの応用として)

先程のゲームオブライフのアルゴリズムを応用し、今度は周辺画素情報の和を取るアルゴリズムに変更してみます。 まず、ある画素の点を$P_{x,y} $(ただしx,yはそれぞれの座標値)とします。1 frame前の画素情報を $P'_{x,y}$ と した場合、$P_{x,y}$を次のように定義する。 \[ P_{x,y} = \frac{P'_{x+1,y} + P'_{x-1, y} + P'_{x, y+1} + P'_{x, y-1}}{2} - P_{x,y} \]

その後、$P, P'$の画素情報を入れ替える。波紋を広げる箇所には、$P'_{x,y}$の任意の座標に500等の適当に大きい数値を 代入すればよい。このアルゴリズムに関しては GAME OF LIFE同様にコーディングChallengeにて、学習教材が提供されているので、 その動画と一緒に記述することができます。授業では馬場と一緒に0からコードを書いてみましょう。

なお、上記画像を生成するサンプルプログラムは下記の通り。

ripple.pde
int cols;
int rows;
 
float[][] current;
float[][] previous;
 
float damping = 0.99;
 
void setup()
{
  size(600, 400);
  cols = width;
  rows = height;
  current = new float[cols][rows];
  previous = new float[cols][rows];
}
 
void mouseMoved()
{
  previous[mouseX][mouseY] = 2055;
}
 
void keyPressed()
{
  save("output.png");
}
 
void draw()
{
 
  background(0);
 
  int x = (int)random(0,(int)width);
  int y = (int)random(0,(int)height);
  previous[x][y] = random(2000);
 
  loadPixels();
  for ( int  i = 1; i < cols-1; i++ ) {
    for ( int j = 1; j < rows-1; j++ ) {
      current[i][j] = (
        previous[i-1][j]+
        previous[i+1][j]+
        previous[i][j-1]+
        previous[i][j+1])/2.0 - current[i][j];
 
      current[i][j] = current[i][j]*damping;
      int index = i + j * cols;
      pixels[index] = color(100-current[i][j]);
    }
  }
 
  updatePixels();
 
  float[][] temp = previous;
  previous = current;
  current = temp;
 
}

すべてのオブジェクトに対して共通のルールを適応することで、簡単な群衆シミュレーションを作成することができます。 下記アルゴリズムはBoidsアルゴリズムと呼ばれ、鳥や魚の群れなど様々なところで利用されています。詳細は下記リンクから。

  • lecture/design_with_prototyping/06.数理シミュレーション.txt
  • 最終更新: 2018/12/11 14:44
  • by baba