p5.js noise関数が拓く「秩序あるカオス」:アルゴリズムによる生命の創出
random() が生み出す無秩序な点描では、どこか生命感が欠けてしまう。パーティクルはただ散らばり、線はただ震える。もっと滑らかで、予測不能でありながらも連続性のある変化を、どうすればコードで描けるのか。この問いは、クリエイティブコーディングの道を歩む多くの人が一度は直面する壁かもしれません。p5.js が提供する noise() 関数、その背後にある パーリンノイズ の思想にこそ、その鍵が隠されています。本稿では、この「秩序あるカオス」とも言えるノイズの美学を紐解き、あなたのジェネラティブアートに有機的な「ゆらぎ」をもたらすための思考と実践を探求します。
プロローグ:ランダムから「ゆらぎ」へ、アルゴリズムが紡ぐ自然の詩
私たちのデジタルキャンバスにおける表現の根源をたどると、しばしば random() 関数に行き着きます。それは純粋な偶然性、予測不可能性の化身です。次の値が何になるか、過去の値からは一切推測できません。この性質は、星空のきらめきや、雨粒の落下位置といった、互いに無関係な事象を表現するには非常に有効です。しかし、私たちが目を向ける自然界の風景は、果たして本当にそのような「完全なランダム」で満たされているでしょうか。
雲の形、海岸線の凹凸、木々の枝分かれ、あるいは大理石の模様。これらは一見すると不規則ですが、その内部にはある種の連続性と相関性が潜んでいます。ある地点の標高は、その隣の地点の標高と無関係ではなく、緩やかにつながっています。雲のある部分の密度は、すぐ隣の部分の密度と極端には違いません。ここに存在する不規則性は、random() が生み出すデジタルなノイズとは異質な、「有機的なゆらぎ」と呼ぶべきものです。ジェネラティブアート の世界で私たちが追い求める「生命感」とは、この連続性を伴った不規則性の表現に他ならないのかもしれません。
パーリンノイズの誕生とnoise()関数:秩序あるカオスを理解する
この有機的なゆらぎをアルゴリズムで実現するために生み出されたのが、パーリンノイズ です。1980年代初頭、コンピュータ科学者のケン・パーリンが、映画『トロン』の制作過程で、当時のCGが持つ無機質さを克服するために開発しました。彼が求めたのは、完全にランダムではなく、入力値がわずかに変化すれば、出力値もまた滑らかに変化するような、連続性のある擬似乱数でした。p5.js の noise() 関数は、このパーリンノイズのアルゴリズムを実装したものです。
noise() 関数の基本的な使い方はシンプルです。引数に数値を一つ与えると、0から1の間の値を返します。
function draw() {
let xoff = frameCount * 0.01;
let n = noise(xoff);
let x = map(n, 0, 1, 0, width);
ellipse(x, height / 2, 24, 24);
}
このスケッチでは、時間経過 (frameCount) を少しずつ変化する入力値 xoff として noise() に渡しています。結果として得られる値 n は、フレームごとに急激にジャンプするのではなく、滑らかに変化します。random() を使った場合、円は画面上で瞬間移動を繰り返しますが、noise() を使った場合は、まるで意思を持っているかのように、予測不能ながらも連続的な動きを見せるはずです。これが noise() の本質、すなわち「隣り合う入力値に対して、隣り合う出力値を返す」という特性です。この秩序だったカオスこそが、自然アルゴリズム に基づく表現の出発点となります。
ジェネラティブアート実践:ノイズが描く地平線、雲、そして生命の形
noise() の真価は、その次元を拡張したときにさらに明らかになります。引数を二つ取ることで、2次元のノイズ空間を生成できます。これは、座標 (x, y) に対して一つの値を返す、滑らかに変化する値のフィールドと考えることができます。この2Dノイズは、静的なイメージに自然なテクスチャや地形を与えるための強力なツールとなります。
例えば、キャンバス上のすべてのピクセルの色を、その座標を入力としたノイズ値によって決定してみましょう。
function setup() {
createCanvas(400, 400);
pixelDensity(1);
}
function draw() {
loadPixels();
let xoff = 0.0;
for (let x = 0; x < width; x++) {
let yoff = 0.0;
for (let y = 0; y < height; y++) {
let bright = map(noise(xoff, yoff), 0, 1, 0, 255);
let index = (x + y * width) * 4;
pixels[index] = bright;
pixels[index + 1] = bright;
pixels[index + 2] = bright;
pixels[index + 3] = 255;
yoff += 0.01; // y方向に進む
}
xoff += 0.01; // x方向に進む
}
updatePixels();
noLoop();
}
このコードが生成するのは、まるで雲や霧、あるいは未踏の惑星の地表を思わせるモノクロームのテクスチャです。xoff と yoff の増分(ここでは 0.01)を調整することで、ノイズの「周波数」が変化し、模様の細かさが変わります。このスケール感をコントロールする感覚は、クリエイティブコーディング における重要な表現技術の一つです。さらに noiseDetail() 関数を用いることで、ノイズの複雑さ(オクターブ)と、周波数が高くなるほど影響が減衰する度合い(フォールオフ)を調整でき、よりリッチで深みのある質感を追求できます。
時間と空間の変奏曲:多次元ノイズが拓く表現の可能性
もし2次元のノイズが静的な地形図であるならば、3次元のノイズは時間と共に変化する風景そのものです。noise() 関数は最大で3つの引数を取ることができ、3つ目の引数を時間軸として扱うことで、動的なアニメーションを生み出す扉が開かれます。
先ほどの2Dノイズによる地形生成のコードに、時間軸を加えてみましょう。
let t = 0;
function draw() {
loadPixels();
let xoff = 0.0;
for (let x = 0; x < width; x++) {
let yoff = 0.0;
for (let y = 0; y < height; y++) {
// 3番目の引数に時間を加える
let bright = map(noise(xoff, yoff, t), 0, 1, 0, 255);
// (ピクセルへの代入は省略)
yoff += 0.01;
}
xoff += 0.01;
}
updatePixels();
t += 0.005; // 時間を進める
}
noise(xoff, yoff, t) とすることで、私たちは2Dのノイズ空間を、時間軸 t に沿って「スライス」しながら見ていることになります。結果として、雲のようなテクスチャは静止せず、ゆっくりと形を変えながら流れ始めます。これは、水面の揺らぎ、炎のまたたき、風にそよぐ草木といった、生命的な動きをシミュレートするための根源的なテクニックです。
さらにこの考えを発展させ、ジェネラティブアートの古典的な手法である「フローフィールド」を構築することもできます。2Dノイズ空間の各点における値を、直接的な色の値としてではなく、パーティクルが向かうべき「角度」として解釈するのです。その流れの場に無数のパーティクルを放てば、それらは個々の意志を持たないにもかかわらず、全体として渦を巻いたり、川のように流れたりする、驚くほど複雑で有機的な振る舞いを見せます。これこそが、p5.js noise を用いた、ボトムアップ的な生命の創出と言えるでしょう。
ノイズは問いかける:非線形性とデジタルアートにおける生命感
なぜパーリンノイズが生成するパターンは、これほどまでに私たちの心を捉え、自然らしさや生命感を感じさせるのでしょうか。その答えの一端は、ノイズが持つ「非線形性」と、予測可能性と不可能性の間の絶妙なバランスにあるのかもしれません。ノイズの生成プロセスは完全に決定論的なアルゴリズムに基づいています。同じ入力値を与えれば、何度でも同じ出力値が返ってきます。しかし、その結果として現れるパターンは極めて複雑で、人間の直感では容易に予測できません。
この性質は、自然界に見られるフラクタル構造や自己組織化現象と深く響き合います。海岸線や雲の輪郭が、どのようなスケールで拡大しても似たような複雑さを見せるように、パーリンノイズもまた、スケールを超えて類似した不規則性を保持する特性を持っています。私たちは、この決定論的なプロセスから立ち現れる予測不可能な複雑さの中に、生命の本質的な振る舞い、すなわち単純な規則から複雑なシステムが生まれる「創発」の影を見ているのではないでしょうか。
したがって、クリエイティブコーディングにおける noise() の探求は、単なる視覚効果ツールの習熟に留まりません。それは、世界の複雑さをシミュレートし、非線形的なシステムを理解するための、一種の思考実験でもあるのです。コードを通じて、私たちは秩序とカオスの境界線を歩き、デジタルな素材から生命の息吹を彫り出す術を学びます。
エピローグ:無限のキャンバスに、ノイズの呼吸を宿す
random() がもたらす唐突な「驚き」と、noise() がもたらす連続的な「ゆらぎ」。これらは対立する概念ではなく、表現者が自らの意図に応じて使い分けるべき、パレットに並ぶ異なる絵の具です。時には両者を組み合わせることで、突発的な変化と滑らかな推移が共存する、より深みのある表現を生み出すこともできるでしょう。
p5.js の noise() 関数を使いこなす道は、単にAPIの仕様を覚えることではありません。それは、私たちの周りの世界に偏在するパターンを注意深く観察し、その背後にある数理的な美を見出し、そして自らの手でデジタルなキャンバスの上に再構成する、創造的なプロセスそのものです。地平線を撫でる風の形、水底で揺れる光の模様、細胞が分裂していくリズム。それらすべてが、ノイズという名のアルゴリズムの詩によって描き出されるのを待っています。
あなたの次のスケッチに、この静かで力強い、ノイズの呼吸を吹き込んでみてはいかがでしょうか。そこにはきっと、あなたがまだ見たことのない、有機的で生命力あふれる風景が広がっているはずです。
