lecture:design_with_prototyping:パターンの再構成

パターンの再構成

先の例ではコンポジションを生成することを行いました。絵を描くことには様々な手法があるだけでなく、写真技術、産業技術、デジタル技術の台頭により「パターン」が表現として使われることが増えてきました。近代に限らず、織物では絨毯やキルトなどの製作工程において、このようなパターンはよく使われています。

  • ある決められたプロセスを何度も繰り返すことで一つの模様が完成する
  • これを何度も繰り返す

この手順でパターンを生成し、私達の服やパッケージ、ポスターなど様々なファッション、グラフィック分野で活用されているのをよく目にするかと思います。

最初に以下の記事を読んでみてください。

このように簡単なプログラムでパターン(模様を生成することができます)。このようなパターンをプログラムで書くことも観察と実装(デッサンとスケッチ)を実現する上でよい訓練になります。このページではみなさんがよく見るパターンをよく観察することで、実際にパターンを生成するだけでなく、ベースとなるプログラムからパラメータを調整することで、そのパターンにバリエーションをもたせるところまでをやってみます。

Mina Perhonen

日本人デザイナーである皆川明(みながわ・あきら)さんが設立したファッションブランド。工業的な均一のパターンというよりも、歪みやブレ、素朴な模様が特徴的です。今回はウェブサイトから「Sunny candy」というテキスタイルをピックアップし、これをプログラムで生成することを目指します。

https://www.mina-perhonen.jp/textile/0512より掲載

まずは上図をよく観察してください。水玉模様ではありますが、一つひとつのまるが微妙に異なっている点、配色が決まっている点、点の大きさに関してもある程度の幅が決められているように見えます。そこでまずは、

  • 指定された矩形領域(_x,_y,_w,_h)に対して指定された個数(_n)で指定された範囲の大きさ(_r_min, _r_maxの円を描く

ことから記述してみます。キーボードのスペースを押すと再描画、's'を押すとoutput.pngというファイルで画像を保存する機能をつけています。 それ以外は特に説明は不要かと思います。まずはシンプルなコードです。これで下記画像のように白い円が描かれます。

void drawPattern(float _x, float _y, float _w, float _h, float _r_min, float _r_max, int _n)
{
  noStroke();
  fill(255);
  for ( int i = 0; i < _n; i++ ) {
    float r = random(_r_min, _r_max);
    float x = random(_x, _w);
    float y = random(_y, _h);
    ellipse(x, y, r, r);
  }
}

void setup()
{ 
  noLoop();
  size(800, 400);
}

void draw()
{
  background(200);
  drawPattern(0, 0, width, height, 10.0, 100.0, 20);
  noLoop();
}

void keyPressed()
{
  if ( key == ' ' ) {
    loop();
  } else if ( key == 's' ) {
    save("output.png");
  }
}

青、薄青、オレンジ、黄色、グレー、ピンクがおもに利用されています。どれも比較的彩度をちょっと低くした配色になっています。配色のことを英語でカラースキームと読んでいますが、このような場合は Adobe社が提供する、Adobe Colorを利用すると非常に便利です。画像をドラッグアンドドロップすることで、その画像のカラースキームを簡単に抽出できます。

今回はそれぞれの色の数値を以下のようにします。また、描く円に少しだけ透明度を加えました。

  • 青:#3C88A6
  • 薄青:#C6D4C8
  • 黄色:#F2DC9B
  • オレンジ:#CB862C
  • ピンク:#D99C9C
  • 背景色:#F2E4DC
void drawPattern(float _x, float _y, float _w, float _h, float _r_min, float _r_max, int _n)
{
  int[] c = new int[]{#3C88A6, #C6D4C8, #F2DC9B, #CB862C, #D99C9C};
  noStroke();  
  for ( int i = 0; i < _n; i++ ) {
    float r = random(_r_min, _r_max);
    float x = random(_x, _w);
    float y = random(_y, _h);
    fill(c[int(random(c.length))], 200);
    ellipse(x, y, r, r);
  }
}

void setup()
{ 
  noLoop();
  size(800, 400);
}

void draw()
{
  background(#F2E4DC);
  drawPattern(0, 0, width, height, 10.0, 100.0, 40);
  noLoop();
}

void keyPressed()
{
  if ( key == ' ' ) {
    loop();
  } else if ( key == 's' ) {
    save("output.png");
  }
}

では次は形です。現時点では単純な円で表現していますが、sunny candyの円は筆やインクを落としたような歪んだ円になっています。そこで、ellipseで描画していた部分をオリジナルの描画コードにすることにします。関数名をsunnyCandyCircleとして関数化します。ただその前にこのような形の歪んだ円を確認はどうすればよいでしょうか? いろいろやり方はありますが、一般的によく使われるのは noise関数を利用したものです。すでにそれに関する記事も見つけたのでそちらを参照することで、sunnyCandyCircle()を実装したいと思います。このページではすぐに解答となりますが、ぜひ自分でノイズパラメータを理解して、動かしてみてください。

void sunnyCandyCircle(float _x, float _y, float _r)
{  
  _r = _r/2;
  float param_noise = random(1000);
  beginShape();
  for ( float angle = 0.0; angle < 360.0; angle = angle + 1.0 ) {
    float circle_noise = 10*noise(
      param_noise+cos(radians(angle)), 
      param_noise+sin(radians(angle))
      );
      
    vertex(
      _x + (_r+circle_noise)*cos(radians(angle)), 
      _y + (_r+circle_noise)*sin(radians(angle)));
  }
  endShape();
}

void drawPattern(float _x, float _y, float _w, float _h, float _r_min, float _r_max, int _n)
{
  int[] c = new int[]{#3C88A6, #C6D4C8, #F2DC9B, #CB862C, #D99C9C};
  noStroke();  
  for ( int i = 0; i < _n; i++ ) {
    float r = random(_r_min, _r_max);
    float x = random(_x, _w);
    float y = random(_y, _h);
    fill(c[int(random(c.length))], 200);
    sunnyCandyCircle(x, y, r);
  }
}

void setup()
{ 
  noLoop();
  size(800, 400);
}

void draw()
{
  background(#F2E4DC);
  drawPattern(0, 0, width, height, 10.0, 100.0, 40);
  noLoop();
}

void keyPressed()
{
  if ( key == ' ' ) {
    loop();
  } else if ( key == 's' ) {
    save("output.png");
  }
}

微妙な歪みが表現できているのがわかるかと思います。

簡単なことと難しいこと

さて、ここまでスケッチをすすめて、ある程度Sunny Candyのパターンに近いものを自動生成することができるようになりました。ただし下記のことに関してはまだ実装できていません。

  • 色同士の混ざり合い(布上なので、色が混ざるわけではなく、それぞれの色が細かくまだら状になる)
  • フィジカルな入力に対する偶発性
    • インクを落とした角度や量による広がり方や、その他環境に関わる要因は多種多様なため、これらすべてを網羅するのは困難。

これを実現するには、そもそも染色シミュレーションをする必要があるので、そんな簡単にはできません。参考までに染色のシミュレーションをやってる森本研究室のリンク張っておきます。興味ある人はどうぞ。

これまでのスケッチをベースにして、次は「デジタルだからできる表現」にチャレンジしてみます。パラメータ化する、対話的にする等ありますが、ここでは「アニメーションにする」をチャレンジします。とはいってもすでに静止画は生成できるようになっているので、そのSunny Candyのパターンがゆらぎながら動くようなアニメーションにしてみます。例えばあなたが空間デザイナーになって、ファッションデザイナーからインスタレーション用途の映像作成をお願いされたとします。このような場合は今回やったことを思い出してみましょう。もちろん友人のグラフィックデザイナーとのコラボレーション等でも活用できるのではないでしょうか。以下に馬場が作成したアンビエントなSunny Candy動画を載せておきます。コード汚いんですが、また時間があるときにきれいにします。

class Spot {
  Spot() {
    x = x_init = 0.0;
    y = y_init = 0.0;
    c = 0;
    r = 5.0;
    param_noise = random(10000.0);
    position_noise_x = random(10000.0);
    position_noise_y = random(10000.0);
    increment_noise = 0.005;
    increment_noise_position = 0.001;
  }
  void update(){
    param_noise += increment_noise;
    position_noise_x += increment_noise_position;
    position_noise_y += increment_noise_position;
    x = x_init + 100*noise(position_noise_x);
    y = y_init + 100 * noise(position_noise_y);
  }
  float x;
  float y;
  float x_init;
  float y_init;
  int c;
  float r;
  float param_noise;
  float position_noise_x;
  float position_noise_y;
  float increment_noise;
  float increment_noise_position;
};
class SunnyCandyPattern {
  SunnyCandyPattern() {
  }
  void setup(int _n, float _r_min, float _r_max) {
    spot = new Spot[_n];
    for ( int i = 0; i < _n; i++ ) {
      spot[i] = new Spot();
      spot[i].x = spot[i].x_init = random(width);
      spot[i].y = spot[i].y_init = random(height);  
      spot[i].c = c[int(random(c.length))];
      spot[i].r = random(_r_min, _r_max);
    }
  }
  void reset()
  {
     for ( int i = 0; i < spot.length; i++ ) {
      spot[i].x = spot[i].x_init = random(width);
      spot[i].y = spot[i].y_init = random(height);  
      spot[i].c = c[int(random(c.length))];
      
    }
  }
  void draw() {
    background(#F2E4DC);
    noStroke();    
    for ( int i = 0; i < spot.length; i++ ) {
      fill(spot[i].c,200);
      circle(i, spot[i].x, spot[i].y, spot[i].r);
      spot[i].update();
     
    }
  }
  void circle(int _index, float _x, float _y, float _r)
  {  
    float param_noise = random(2.0);
    
    beginShape();
    for ( float angle = 0.0; angle < 360.0; angle = angle + 1.0 ) {
      float circle_noise = 20*noise(
        spot[_index].param_noise+cos(radians(angle)), 
        spot[_index].param_noise+sin(radians(angle))
        );

      vertex(
        _x + (_r+circle_noise)*cos(radians(angle)), 
        _y + (_r+circle_noise)*sin(radians(angle)));
    }
    endShape();
  }

  int[] c = new int[]{#3C88A6, #C6D4C8, #F2DC9B, #CB862C, #D99C9C};
  Spot[] spot;
  
}

SunnyCandyPattern scp;
float x, y, r;
void setup()
{ 
  frameRate(60);
  scp = new SunnyCandyPattern();
  scp.setup(50, 5, 40);
  size(800, 400);
}

void draw()
{
  scp.draw();
}

void keyPressed()
{
  if ( key == ' ' ) {
    scp.reset();
  } else if ( key == 's' ) {
    save("output.png");
  }
}

練習

この他 https://www.mina-perhonen.jp/textile/ を参照するとたくさんのパターンがあります。自分で一つピックアップしてパターンを生成するプログラムを記述してみましょう。

  • lecture/design_with_prototyping/パターンの再構成.txt
  • 最終更新: 2019/11/07 14:25
  • by baba