3分で読めるクリエイティブコーディングの小ネタです。 お題は「円弧に沿って綺麗に色が変化する図を描く」です。
普通にやると境目ができて不自然な変化になってしまいます。この記事でそれを解決するアイデアを紹介します。
このアイデアを使うと、このように綺麗に繋る色の変化を描けるようになります。
角度で変化するパーリンノイズ
色を自然に変化させるなら「パーリンノイズ 」を使いましょう。
「円弧に沿って綺麗に色を変化」は、角度でパーリンノイズを変化させればよさそうです。
noise(角度);
【参考】
パーリンノイズ : Wikipedia
noise() : p5js
noise() : Processing
参考記事:Processing/p5.js の noise() で遊ぼう! 前編
でも境目が出来ちゃう…
ところが、普通に noise(角度) とすると、角度が 0 と 2PI(=360度)のところで境目が出来てしまいます。
円弧が一周してきて接するところは、全然違う値であろう noise(0) と noise(2PI) が隣り合わせなので、急激に色が変わってしまって境目が出てしまうんですね。
ここで noise(sin(角度)) とすれば、角度が 0 と 2PI のときでどちらも noise(0) になり境目は出ませんが、今度は変化が周期的になってしまいます。
さて、どうしたものか?
アイデアひとつでうまくいく
この悩みを呟いてみたところ、山辺真幸(@masakick)さんからナイスなアイデアをいただきました。
無念。2周させて2周目は進むごとに段々と薄くして1周目に重ねるとか?
— 山辺真幸/データビジュアライズデザイナー (@masakick) April 15, 2025
このアイデアを元に以下のように透明度を操作すると、ご覧の通りうまくいきました。
- 一周目は薄く始めて濃く終わる
- 二周目は濃く始めて薄く終わる
※透明度の変化によって、若干彩度が落ちて一部 "くすみ" が感じられます。
極座標でパーリンノイズのサンプルコード(Processing / p5js)
角度だけでなく半径でも色が変化するように noise(角度, 半径) でコードを書いてみます。
【参考】
角度と半径で場所を指定する方式は「極座標系」と呼ばれます。よくある (x, y) で場所を指定するのは「直交座標系」です。
極座標系 : Wikipedia
直交座標系 : Wikipedia
Processing
/*
* クリコー 3分クッキング:極座標でパーリンノイズを綺麗に繋げたい
* Processing サンプルコード
*
* @author @deconbatch
* @version 0.1
* @license CC0 1.0 https://creativecommons.org/publicdomain/zero/1.0/deed.ja
* Processing 4.3.3
* 2025.05.03
*/
float marginRate = 0.1;
int cirMax = 7;
int arcMax = 60;
void setup() {
// キャンバスの設定
size(800, 800);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
background(0.0, 0.0, 90.0, 100.0);
noFill();
noStroke();
// 指定したパラメータから描画用の数値を計算
float margin = min(width, height) * marginRate;
float cirWidth = (min(width, height) * 0.5 - margin * 2) / cirMax;
float angleDiv = PI / arcMax;
//描画
translate(width * 0.5, height * 0.5);
strokeWeight(cirWidth * 0.8);
strokeCap(SQUARE);
ellipseMode(RADIUS); // arc を直径指定ではなく半径指定に
for (int cirCnt = 0; cirCnt < cirMax; cirCnt++) {
for (float angle = 0; angle < TWO_PI * 2; angle += angleDiv) {
float aHue = (noise(cirCnt * 0.1, angle * 0.2) * 720) % 360;
float aAlp = 100 * sin(angle / 4); // 一周目は薄くから濃く, 二周目は濃くから薄く終わる
stroke(aHue, 60.0, 60.0, aAlp);
arc(
0.0, 0.0,
margin + cirWidth * cirCnt, margin + cirWidth * cirCnt,
angle, angle + angleDiv
);
}
}
}
p5js
/*
* クリコー 3分クッキング:極座標でパーリンノイズを綺麗に繋げたい
* p5js サンプルコード
*
* @author @deconbatch
* @version 0.1
* @license CC0 1.0 https://creativecommons.org/publicdomain/zero/1.0/deed.ja
* p5js 2.0.0
* 2025.05.03
*/
const w = 800;
const h = w;
const marginRate = 0.1;
const cirMax = 7;
const arcMax = 60;
function setup() {
// キャンバスの設定
createCanvas(w, h);
colorMode(HSB, 360, 100, 100, 100);
background(0, 0, 90, 100);
noFill();
noStroke();
// 指定したパラメータから描画用の数値を計算
const margin = min(w, h) * marginRate;
const cirWidth = (min(w, h) * 0.5 - margin * 2) / cirMax;
const angleDiv = PI / arcMax;
//描画
translate(w * 0.5, h * 0.5);
strokeWeight(cirWidth * 0.8);
strokeCap(SQUARE);
ellipseMode(RADIUS); // arc を直径指定ではなく半径指定に
for (let cirCnt = 0; cirCnt < cirMax; cirCnt++) {
for (let angle = 0; angle < TWO_PI * 2; angle += angleDiv) {
let aHue = (noise(cirCnt * 0.1, angle * 0.2) * 720) % 360;
let aAlp = 100 * sin(angle / 4); // 一周目は薄くから濃く, 二周目は濃くから薄く終わる
stroke(aHue, 60, 60, aAlp);
arc(
0, 0,
margin + cirWidth * cirCnt, margin + cirWidth * cirCnt,
angle, angle + angleDiv
);
}
}
}
まとめ
ここまで、極座標系のパーリンノイズを使って、円弧に沿って境目なく色を変化させる方法を解説しました。
今回のサンプルコードを改造して、アニメーションにしたり、おなじみの直交座標系でのノイズと組み合わせてみたり、いろいろと楽しめると思います。
【アニメーション例】散布る#processing #creativecoding pic.twitter.com/ni5Iq3uv6D
— deconbatch (@deconbatch) April 18, 2025
【直交座標系でのノイズと組み合わせて】
あなたの丹田#processing #creativecoding pic.twitter.com/FEUsbepxRT
— deconbatch (@deconbatch) April 20, 2025
パーリンノイズに関する他記事も合わせてお楽しみください。
noise() 関数を用いてドット絵風のアニメーション|deconbatch