クリエイティブ・コーディングで描画したものが、見た目の意味でのアートらしくなるためには、色彩、それもただ綺麗な色で塗るということではなく、美しいと感じるような色の組み合わせや色の配置が必要です。
だけど、これが難しい。
私、どう配色したらいいかさっぱりわかりません。何か作ろうというときも、いつも色付けで苦労しています。「ここはこの色!」とビビっとくることもなく、自分に色彩感覚があるとは思えないです。
色付けが苦手ならどうすればいいか?勉強と訓練しかありません!
やるなら楽しくやりたいので、テキサスの 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();
}
}