クリエイティブ・コーディングの定番「ノード・ガーデン」:基礎編

2021年10月3日日曜日

p5.js テクニック 初心者向け

t f B! P L

比較的簡単に、かっこいい絵が作れる「ノード・ガーデン」。 クリエイティブ・コーディングの定番手法のひとつです。

👉 Read this article in English.


この記事では、作って楽しく、いろいろと応用も効くこの「ノード・ガーデン」を、サンプルコードを交えて基礎からやさしく解説します。

 

コード例は p5.js で

コードは p5.js (JavaScript) で書いていきます。

p5.js を書くのが初めての方は、OpenProcessingp5.js Web Editor を使うのがお勧めです。Web ブラウザ上でコードを書いて実行できるので、環境構築の手間も無く手軽に使えます。

OpenProcessing の使い方はこちらでも紹介していますので、よろしければ参考にしてください。

趣味としてのクリエイティブ・コーディング:102:OpenProcessing を使おう

JavaScript の文法などはこの記事では説明しませんが、JavaScript や p5.js が初めてという方も、この記事にそってコードを書くところから始めてみてもよいと思います。 まずは手を動かしてみて、その後でわからないところを調べるというのも、学習のよい方法です。

 

「ノード・ガーデン」の考え方

「ノード・ガーデン」の作り方は簡単です。

  • 点(ノード)を配置する
  • ノード間に線を引く

これだけです。

ノードを配置して、


ノードの間に線を引くと、あら不思議!格好いい「ノード・ガーデン」のできあがりです。


ノードをどう配置するか、どういう条件で線を引くかによって、いろんな表現を行うことができます。

 

「ノード・ガーデン」のサンプルコード

シンプルな「ノード・ガーデン」を描くサンプルコードがこちらです。

p5.js でのサンプルコード


/*
 * Node Garden 基礎編 サンプルコード
 */

const w = 640;
const h = 480;
const nodeNum = 10;
const nodes = new Array();

function setup() {
  // キャンバスの設定
  createCanvas(w, h);
  background(240);
  noFill();
  stroke(100);

  // ノードを配置
  for (let i = 0; i < nodeNum; i++) {
    let x = random(w);
    let y = random(h);
    ellipse(x, y, 10, 10);
    nodes.push(createVector(x, y));
  }

  // 線を引く
  for (let i = 0; i < nodeNum - 1; i++) {
    let n = nodes[i];
    for (let j = i + 1; j < nodeNum; j++) {
      let m = nodes[j];
      line(n.x, n.y, m.x, m.y);
    }
  }
}

 

コードの解説

※わからない部分はひとまず読み飛ばして先に進んで構いません。

まずは初期設定。


const w = 640;
const h = 480;
const nodeNum = 10;
const nodes = new Array();

キャンバスサイズを横 640、縦 480 ピクセル、ノードの数は 10個と設定します。 'nodes' はノードを格納する配列です。

キャンバスの設定。


  // キャンバスの設定
  createCanvas(w, h);
  background(240);
  noFill();
  stroke(100);

背景色を '240' (だいたい白)、塗りは無しで、線の色を '100' (灰色)にします。

ノードの配置。


  // ノードを配置
  for (let i = 0; i < nodeNum; i++) {
    let x = random(w);
    let y = random(h);
    ellipse(x, y, 10, 10);
    nodes.push(createVector(x, y));
  }

ノードの位置をランダムに決めて、そこに大きさ 10 の円を描き、配列にもその位置を格納します。 これを 'nodeNum' 個分繰り返します。

線を引く。


  // 線を引く
  for (let i = 0; i < nodeNum - 1; i++) {
    let n = nodes[i];
    for (let j = i + 1; j < nodeNum; j++) {
      let m = nodes[j];
      line(n.x, n.y, m.x, m.y);
    }
  }

配列からノードを順に取り出しながら、'line()' で線を引きます。 これを全ノードについて繰り返します。


実行結果はこうなります。


 

線を引く条件に制約を加えてみる

サンプルコードでは全てのノード間に線を引いています。ここに条件を加えて「ある距離以下」のノード間にだけ線を引くようにしてみましょう。


      if (dist(n.x, n.y, m.x, m.y) < 100) {
        line(n.x, n.y, m.x, m.y);
      }

ノード間の距離を dist() で測り、100 より短ければ線を引くようにしてみました。その結果はこうなります。

…ずいぶん寂しいですね。

ノードの数を 100個にしてみると、


const nodeNum = 100;

どうです? ちょっとかっこいいでしょう?

 

描画を工夫する

ここまでの描画結果だと、ノードが線に隠れて目立ちません。ノードをもっとくっきり目立つように描画を工夫してみます。

今までは線を引く前にノードを配置していたので、ノードが線の中に埋もれてしまっていました。


  // ノードを配置
  for (let i = 0; i < nodeNum; i++) {
    let x = random(w);
    let y = random(h);
    ellipse(x, y, 10, 10);      // ここでノードを描画
    nodes.push(createVector(x, y));
  }
  
  // 線を引く
  for (let i = 0; i < nodeNum - 1; i++) {
    let n = nodes[i];
    for (let j = i + 1; j < nodeNum; j++) {
      let m = nodes[j];
      line(n.x, n.y, m.x, m.y); // ここで線を引いている
    }
  }

順番を逆にして、線を引いた後にノードを描画するようにしてみます。下記のコードを線を引くコードの後ろに挿入してください。


  fill(240);
  for (let i = 0; i < nodeNum; i++) {
    let n = nodes[i];
    ellipse(n.x, n.y, 10, 10);
  }


fill(240); でバックグラウンドと同じ色で塗りつぶしているところがミソです。これが無いとこうなってしまいます。


線の太さを変えたりしても、雰囲気がずいぶん変わります。


  strokeWeight(10);


四角形を使ってノードを歯車風にしてみたりとかも面白いですね。


rectMode(CENTER);
for (let i = 0; i < nodeNum; i++) {
  let n = nodes[i];
  for (let r = 0; r < TWO_PI; r += TWO_PI / 3) {
    push();
    translate(n.x, n.y);
    rotate(r);
    rect(0, 0, 50, 50);
    pop();
  }
}


四角形を長方形にするとこんなのも描けます。

 

ノードガーデンの作品例

Processing での作例になりますが、ノードを動かしてアニメーションにした作品を2つご紹介します。

The node-garden animation nodes go back and forth on a straight line.

A geometrical shape animation with a node-garden technique.

 

ノードガーデンで遊んでみて!

今回紹介した基礎テクニックは、サンプルコードで遊ぶだけでも楽しいし、描画やノードの配置に工夫を加えることでいろんな作品を作れる「ネタ」としてもとても優秀です。

ぜひ遊んでみてください。

 

QooQ