ランダムは乱数.ノイズは雑音.一体何が異なるのでしょうか? p5.jsでもランダム及びノイズが用意されています.簡単にいうと,ランダムは乱数で,ノイズは連続性を持ったランダム(のような)乱数.のことです.例えば「1-100までの好きな数をランダムで3回で言って」となった場合は,ランダムの場合は40,87,23」のように値が飛び飛びになる一方,「1-100までの好きな数をノイズで3回言って」となる場合,40,42,39のように比較的値がつながった連続値になります.どのくらい値を飛ばしたいのか,といった調整もできるようになっていますが,まずはコードで確認していきましょう.
以下がオフィシャルのリファレンスページです.
引数にランダム出力をしたい数値や数値の範囲,配列等を渡すことでランダムを返してくれます.公式リファレンスがわかりやすいので上記リンクを参照してください.別段このページで改めて説明するまでもないですよね.
以下がオフィシャルのリファレンスページです.
touchDesignerではこのnoiseを頻繁に利用してアンビエントなグラフィック表現によく利用していますよね.「なんか適当な値を入れたい」という場合はrandomで十分な場合もありますが,例えばある時系列を持つ点を適当だけど,あんまり値が飛び飛びにならないようにスムーズに動かしたい.なんて場合にNoiseはとっても便利です.
noise関数の引数は浮動小数点を渡すことができます.例えば以下の画像はnoise関数の引数に順番に1,2,3および,0.1,0.2,0.3を渡して,y座標の高さで線分を結んだ結果を表示した画像です.0.1ずつ増やした結果のほうが変化量が少ない様子が観察できます.
2Dノイズは,引数に2つ用いることで平面画像のふわっとした模様を生成することができます.
このランダムとノイズの違いを表す端的な例として,一本の線を描く,ということをしてみます.線はline関数を使うことで二点間を指定して描くことができますが,ここではbeginShape()を利用して,いくつか点を打った上で,ランダムとノイズの振る舞いの違いを確認してみます.まずは以下のプログラムを実行して結果を確認してみましょう.
function setup(){ createCanvas(500,250); } function draw() { background(255); beginShape(); for( let i = 0; i < width; i += 10){ vertex(i, height/2); } endShape(); }
では次に上記のコードにおいて,yの値をrandomを使って上下+20, -20方向にずらしてみようと思います.以下は静止画ですが,実際は「ガチャガチャガチャ〜」っと線画描かれる様子が観察できます.これは描画するごとにrandom(-20,20)によって適当な値が入るためです.そりゃそうだと思っていただけると思います.
function setup(){ createCanvas(500,250); } function draw() { background(255); beginShape(); for( let i = 0; i < width; i += 10){ vertex(i, height/2+random(-20,20)); } endShape(); }
ではここで,ちょっと趣を変えます.この「ガチャガチャ〜」っていうのがうるさいので,少しなめらかに変化して「うにょにょにょ〜」みたいに変化してくんないかな〜って考えてみます.なめらかに変化していく様子に修正するには,noiseを利用すると良いです.ただしnoise関数は先程のrandomと違って,返す値は0.0-1.0と決まっていますので,その点注意してください.
function setup(){ createCanvas(500,250); } function draw() { background(255); beginShape(); for( let i = 0; i < width; i += 10){ vertex(i, height/2+50*(0.5-noise(i*0.01))); } endShape(); }
randomと比べて値がなだらかに変化している様子がわかります.ポイントはnoise関数への引数が大きく変化しないようにすることです.例えば noise(i) としてしまうと,randomと同様にガチャガチャした描画になってしまいます.試しにやってみてください.この引数の変化量に応じて値の滑らかさが変わる点に注意してください.
randomとはことなり,一度実行するとアニメーションが描画されません.これは実行時のnoise関数における初期値が変化しないため,何度描画しても同じ線分になるためです.この値は実行するたびに変化するので,確認してみてください.せっかくなのでなだらかに変化する様子をアニメーションにしてみたいと思います.
let offset = 0.0; function setup(){ createCanvas(500,250); } function draw() { background(255); beginShape(); for( let i = 0; i < width; i += 10){ vertex(i, height/2+50*(0.5-noise(i*0.1+offset))); } endShape(); offset += 0.01; }
では最後に頂点がカクカクしているので,vertexではなく,curveVertexを利用してみると,なだらかな変化になります.
let offset = 0.0; function setup(){ createCanvas(500,250); } function draw() { background(255); beginShape(); for( let i = 0; i < width; i += 10){ curveVertex(i, height/2+50*(0.5-noise(i*0.1+offset))); } endShape(); offset += 0.01; }
ではここまでの内容を踏まえて,ふにゃふにゃアニメーションする丸を描いてみます.まず最初に先程までの線を円上に並べ直してみます.極座標を使って描きなおします.極座標のrは,各角度毎にノイズのパラメータが決定すれば比較的フニャッとした円を描くことができます.
ちょっと見た目を可愛くするのに,drawingContextというものを利用しています.これを使うと自動で描画したグラフィックに影をつけることができます.
let offset = 0.0; function setup() { createCanvas(400, 400); drawingContext.shadowBlur = 10; drawingContext.shadowOffsetX = 5; //X軸正方向へのズレ drawingContext.shadowOffsetY = 5; //Y軸正方向へのズレ drawingContext.shadowColor = color(0, 0, 0, 150); //シャドウの色 } function draw() { background(255, 255); fill(140, 180, 80); strokeWeight(5); stroke(150); let r; beginShape(); for (let i = 0; i < 360; i += 12) { r = 100 + 100*noise(i*0.1+offset); curveVertex( width / 2 + r * cos(radians(i)), height / 2 + r * sin(radians(i)) ); } // もう一度最初の2点を指定するのは,curveVertexを閉じるため // https://infosmith.biz/blog/it/p5js-curvevertex-2 for (let i = 0; i < 36; i += 12) { r = 100 + 100*noise(i*0.1+offset); curveVertex( width / 2 + r * cos(radians(i)), height / 2 + r * sin(radians(i)) ); } endShape(); offset += 0.01; }
こんなんで,それっぽく見えるんですが,描かれた円の下側をみると微妙にとんがったところが見えます.これは,始点と終点の位置が大きくずれてしまっているためです.とは言ってもこのままでも気にならない場合は全然構わないと思います.
noiseを利用すればズレをなだらかに表示できたわけですが,結局始点と終点ではnoiseへの引数が異なるため,大きく値が異なってしまっているわけです.どのようにすればよいかですが,このページではnoiseにわたす引数をsin関数を用いて最初と最後の値が同じになるようにしてみました.
以上,randomとnoiseに関してでした.アンビエントな表現にはnoiseを多用すると良いでしょう.