クリエイティブ・コーディング・カラースタディ:SORTING / SEQUENCES

2022年8月15日月曜日

p5.js お勉強

t f B! P L

クリエイティブ・コーディングで描画したものが、見た目の意味でのアートらしくなるためには、色彩、それもただ綺麗な色で塗るということではなく、美しいと感じるような色の組み合わせや色の配置が必要です。

だけど、これが難しい。

私、どう配色したらいいかさっぱりわかりません。何か作ろうというときも、いつも色付けで苦労しています。「ここはこの色!」とビビっとくることもなく、自分に色彩感覚があるとは思えないです。

色付けが苦手ならどうすればいいか?勉強と訓練しかありません!

やるなら楽しくやりたいので、テキサスの Visual artist、 Tyler Hobbs さんのエッセイ「COLOR ARRANGEMENT IN GENERATIVE ART」を元に、コードを書きながら勉強していきたいと思います。

👉 Read this article in English.

 

HSB の3要素でソートした配色

まずは「SORTING」。色をソートするにあたって、RGB だとやりづらいので、HSB モードでやります。 HSB それぞれの要素 Hue(色相)、Saturation(彩度)、Brightness(明度) の値でソートしてみましょう。

HSB に不慣れな場合、こちらを参照ください。
「カラフルな作品作りは難しい? 簡単便利な色指定方法 HSB のススメ : Processing Tips」

使うコードはこちら。


/**
 * Color Study : SORTING
 * @author @deconbatch
 * @license CC0 https://creativecommons.org/publicdomain/zero/1.0/
 * @version 0.1
 * p5.js 1.1.3
 * created 2022.08.14
 */

const w = 640;
const h = 480;
const margin = h * 0.05;
const lineCnt = 40;
const colorAry = new Array(lineCnt);

function setup() {
  createCanvas(w, h);
  colorMode(HSB, 360, 100, 100, 100);
  noStroke();
  
  // set random colors
  for (let l = 0; l < lineCnt; l++) {
    colorAry[l] = createVector(
      random(240, 360), // hue
      random(30, 80),   // sat
      random(50, 90)    // bri
    );
  }
  
  /* sort colors by hue
  colorAry.sort(function (a, b) {
    return a.x - b.x;
  });
  */

  // background gray
  background(0, 0, 90, 100);
  
  // draw lines
  translate(0, margin);
  noFill();
  strokeWeight(h * 0.005);
  for (let l = 0; l < lineCnt; l++) {
    let lRatio = l / lineCnt;
    let lY = (h - margin * 2) * lRatio;
    let lC = colorAry[l];
    push();
    translate(0, lY);
    stroke(lC.x % 360, lC.y, lC.z);
    drawWave(PI * lRatio, 5 * (1 + lRatio));
    pop();
  }
}

function drawWave(_phase, _cycle) {
  const amp = h * 0.02;
  beginShape();
  for (let x = 0; x < width; x++) {
    let xRatio = x / width;
    let y = amp * xRatio * sin(_phase + PI * _cycle * xRatio);
    vertex(x, y);
  }
  endShape();
}


HSB の値はランダムに設定しておきます。


      random(240, 360), // hue
      random(30, 80),   // sat
      random(50, 90)    // bri


ソートせずランダムな値のままの描画はこのようになりました。


 

色相でソート

Hue(色相)の昇順にソートして、上から下へと描画してみます。


 // sort colors by hue
 colorAry.sort(function (a, b) {
   return a.x - b.x;
 });


色相のソートは見た目に分かりやすいですね。途中に入るランダムな彩度と明度の違いによる変化が「味」になるようです。

 

彩度でソート

今度は、Saturation(彩度)の昇順にソート。


 // sort colors by sat
 colorAry.sort(function (a, b) {
   return a.y - b.y;
 });


色相がランダムになると、パッと見ソートされているようには見えません。彩度が増すにつれて、線がくっきり活き活きとして見えます。

 

明度でソート

最後は Brightness(明度) で、こちらは降順にソート。


 // sort colors by bri
 colorAry.sort(function (a, b) {
   return b.z - a.z;
 });


下に行くほど暗くすることで、重さと軽さを表現してみました。

 

ソートというよりグラデーション?

HSB の3要素でソートしてみましたが、こうしてみるとグラデーションに近い表現ですね。変化が不均一なグラデーション、あるいは途中でランダムにノイズが入るグラデーション、そんな描画結果になりました。

 

カラーパレットを順序づけした配色

次は「SEQUENCES」、これは複数の色を順番に並べていくことと理解しました。「SORTING」にひきつづき HSB モードを使います。

こちらが、順序づけた配色を使うコードと、その結果です。


/**
 * Color Study : SEQUENCES
 * @author @deconbatch
 * @license CC0 https://creativecommons.org/publicdomain/zero/1.0/
 * @version 0.1
 * p5.js 1.1.3
 * created 2022.08.14
 */

const w = 480;
const h = 640;
const margin = h * 0.05;
const lineCnt = 20;
const colorAry = new Array(lineCnt);

function setup() {
  createCanvas(w, h);
  colorMode(HSB, 360, 100, 100, 100);
  noStroke();

  // set sequential colors
  let hueVal = 0;
  for (let l = 0; l < lineCnt; l++) {
    if (l % 4 == 0) {
      hueVal = random(240);
    }
    colorAry[l] = createVector(
      hueVal, // hue
      60,   // sat
      80    // bri
    );
  }
  
  /*  set random colors
  for (let l = 0; l < lineCnt; l++) {
    colorAry[l] = createVector(
      random(240), // hue
      60,   // sat
      80    // bri
    );
  }
  */

  // background gray
  background(0, 0, 90, 100);
  
  // draw lines
  translate(0, margin);
  noStroke();
  for (let l = 0; l < lineCnt; l++) {
    let lRatio = l / lineCnt;
    let lY = (h - margin * 2) * lRatio;
    let lC = colorAry[l];
    push();
    translate(0, lY);
    fill(lC.x % 360, lC.y, lC.z);
    drawWave(PI * lRatio, 2 * (1 + lRatio));
    pop();
  }
}

function drawWave(_phase, _cycle) {
  const amp = h * 0.025;
  beginShape();
  for (let x = 0; x < width; x++) {
    let xRatio = x / width;
    let y = amp * xRatio * sin(_phase + PI * _cycle * xRatio);
    vertex(x, y);
  }
  endShape();
}


こちらはランダムな配色。


なんだかランダムな配色も悪くないように感じます。正直「順番に並べる配色」というのが、いまいちピンときていません。試行が足りないのか、解釈が間違ってるのか?

 

まとめ

いつも手癖でやっていた配色を、普段使わないソート等のルールをもとに試行してみました。考えながら作る、こういった基礎訓練的なことを行うと、自分の中の引出しが増える感覚があります。

今回学んだことを活かして、最後に一つコードを書いてみました。


/**
 * Color Study : example work
 * @author @deconbatch
 * @license CC0 https://creativecommons.org/publicdomain/zero/1.0/
 * @version 0.1
 * p5.js 1.1.3
 * created 2022.08.14
 */

const w = 480;
const h = 640;
const margin = h * 0.05;
const lineCnt = 8;

function setup() {
  createCanvas(w, h);
  colorMode(HSB, 360, 100, 100, 100);

  const wave = new Wave();

  // background gray
  background(0, 0, 90, 100);
  
  // draw lines
  translate(0, margin);
  for (let l = 0; l < lineCnt; l++) {
    let lRatio = l / lineCnt;
    let lY = h * lRatio;
    push();
    translate(0, lY);
    wave.drawWave(PI * lRatio, 3 * (1 + lRatio), lRatio);
    pop();
  }
}

class Wave {

  constructor() {
    this.colorCnt = 3;
    this.colorIdx = 0;
    this.colorAry = new Array(this.colorCnt);
    for (let i = 0; i < this.colorCnt; i++) {
      this.colorAry[i] = createVector(
        random(360),    // hue
        random(30, 50), // sat
        90.0            // bri
      );
    }
  }
  
  drawWave(_phase, _cycle, _lRatio) {
    const amp = h * 0.05;
    let sign = 1;

    noStroke();
    beginShape();
    for (let x = 0; x < width; x+=2) {
      let xRatio = x / width;
      let y = amp * (sin(_phase + _cycle * xRatio));
      if (sign * y < 0) {
        // change color
        this.colorIdx++;
        sign *= -1;
        endShape();
        beginShape();
      }
      let lC = this.colorAry[this.colorIdx % this.colorCnt];
      fill(lC.x % 360, lC.y, lC.z * (1.0 - _lRatio * 0.5));
      vertex(x, y);
    }
    endShape();
  }
}

 

QooQ