シームレスノイズ
今回のサンプルの実行結果
動的なノイズをシームレスに
前回は、プロシージャルにノイズを生成するプログラムを解説しました。
当サイトのオリジナルライブラリ noiseX.js を用いれば、動的なノイズ生成を簡単に行うことができます。生成したノイズは、最終的に canvas 上に出力されますので WebGL のテクスチャとして利用することも簡単です。
さて、今回も noiseX.js を使ってノイズを生成してみますが……今回はただノイズを生成するのではなく、これをシームレスなノイズにしてみます。
とは言っても、今回のサンプルのソースと、前回のサンプルのソース。見比べてみればわかりますが、変更点はほとんどありません。というか、ほぼまったく一緒です。違うのは、呼び出しているメソッドひとつだけです。
一応、サンプルのソースを載せておきます。
サンプルの HTML ソース
<html>
<head>
<script src="noiseX.js" type="text/javascript"></script>
<script type="text/javascript">
var octave = 5;
var offset = 3;
var persistence = 0.5;
var baseWidth = Math.pow(2, octave + offset);
var n = new noiseX(octave, offset, persistence);
n.setSeed(new Date().getTime());
onload = function(){
var i, j;
var canvas;
var noiseColor = new Array(baseWidth * baseWidth);
for(i = 0; i < baseWidth; i++){
for(j = 0; j < baseWidth; j++){
noiseColor[i * baseWidth + j] = n.snoise(i, j, baseWidth);
}
}
canvas = n.canvasExport(noiseColor, baseWidth);
document.body.appendChild(canvas);
};
</script>
<style type="text/css">
canvas {
margin: 5px;
}
</style>
</head>
<body>
</body>
</html>
変更箇所はたった一箇所。 noiseColor
という配列にデータを格納する際に呼び出しているメソッド名が noise
から snoise
に変わっています。両者では第三引数の有無が異なりますが snoise
の第三引数には canvas の一辺の幅を渡してやれば OK です。それ以外は、全て前回のプロシージャルノイズのサンプルと全く同じです。
シームレス化の仕組み
ソースコードに加えた変更点がたった一箇所のみというのもなんですので、せっかくなのでシームレス化の仕組みを考えてみることにします。
noiseX.js の中身を見てみればわかるのですが、今回登場した snoise
メソッドは内部で noise
メソッドを呼び出しています。その部分のコードを一部抜粋してみます。
snoise メソッドの内部コード
u = x / w;
v = y / w;
t = this.noise(x, y) * u * v
+ this.noise(x, y + w) * u * (1.0 - v)
+ this.noise(x + w, y) * (1.0 - u) * v
+ this.noise(x + w, y + w) * (1.0 - u) * (1.0 - v);
ここで出てくる x
と y
は引数として入ってくる縦横の座標位置です。また w
は同様に引数として入ってくるデータで、canvas の一辺の幅です。式をよく見るとわかりますが、要は noise
メソッドを四回呼び出し、全ての値を加算しています。
加算されるそれぞれの noise
メソッドの値には、変数 u
と変数 v
の値がそれ異なる形で掛けられます。この二つの変数が掛けられることで四つの noise
メソッドの値は正規化され、最終的な加算結果が大きくなりすぎてしまうことはありません。
シームレス化とは、要するに上下左右の各辺が継ぎ目なく繋がる状態を作ることですよね。このことを踏まえて考えると、四つの noise
メソッドの引数で、canvas の一辺の幅を表す変数 w
が加算されていることの意味がわかるのではないでしょうか。
たとえば、二つ目の noise
メソッドでは引数として入ってきた y
に対して w
が加算されます。仮に y
が 1 の状態で w
が 128 だとすると、引数として二番目の noise
メソッドに渡される値は 129 ということになります。つまり、本来の縦座標よりもさらに先にあるピクセルのノイズの値が返ってくることになるわけです。
このことからわかるとおり、シームレス化を行なう場合には、本来の右端や下端よりもさらに原点から遠いピクセルを擬似的に参照することで、本来の幅のその先に繋がるノイズを加味した演算を行なうことができるのですね。結果、上下左右のそれぞれの辺が継ぎ目なく繋がるシームレスなノイズを生成することができるのです。
まとめ
さて、シームレスなノイズの生成について理解できたでしょうか。当サイト自前のライブラリ noiseX.js を用いれば、シームレスノイズの生成は簡単です。上記でソースを載せましたが、メソッドの呼び出し一つで簡単にシームレスなノイズが生成できます。
WebGL で利用することを前提に考えると、たとえばスクロールする霧などを表現する際、シームレスでないノイズテクスチャでは使い物になりませんが、シームレス化されたノイズテクスチャであれば、そのテクスチャ座標を毎フレームずらしてやるだけで、自然なフォグを実現することもできるでしょう。
使いどころはいろいろ考えられるシームレスノイズ。よかったら使ってみてください。
実際に canvas にノイズを生成するサンプルは以下のリンクから。