パーリンノイズ(2D基礎)

Processingでランダムな数を生成するには主に以下の2通りがあります。

  1. random(high) = 0~highまでの範囲で、完全なランダムな数を返す
  2. noise = 0~1までの範囲で、__ある程度規則性のある__ランダムな数を返す

このnoise関数の”ある程度の規則性”というのが曲者で、noise関数をわかりづらくしている原因だと思います。どのように"ある程度の規則性"を記述するのか、例を使って調べてみましょう。

それぞれの座標の色をnoise(nx, ny)変化で作成しています。このnx, nyは座標ではありません。
nxとnyには適当な初期値を与えます。
x座標とy座標を移動させるにつれ、nxとnyの値を少しずつ(=stepずつ)変化させているのがポイントです。

  • nxを変化させる=画像が横方向に移動する
  • nyを変化させる=画像が縦方向に移動する
  • stepを変化させる=模様の粒度が代わる

今回は平面(2次元)における"ある程度の規則性"を表現してみます。

  r = noise(nx, ny);

のように記述した場合、noise関数が返す値、すなわちrの値は0~1の乱数となります。

色を作成するために0~255の範囲の乱数を作成する場合は以下のように記述してもよいでしょう。

  int c = (int)(noise(nx, ny) * 255);

繰り返しますが、ここで(nx, ny)は"生成する乱数がどの程度変化するか"を指定するパラメータであり、
座標でないことに注意して下さい。

nxを変化させてどのように出力が変わるか試してみました。

float r0 = noise(50, 10);
float r1 = noise(50 + 0.01, 10);
float r2 = noise(50 + 0.1, 10);
float r3 = noise(50 + 1, 10);

println("r1=" + r1 + "  (r0-r1)="+(r0-r1));
println("r2=" + r2 + "  (r0-r2)="+(r0-r2));
println("r3=" + r3 + "  (r0-r3)="+(r0-r3));

出力結果は以下の通りでした(出力結果は実行の都度変化します)。

r1=0.5738846  (r0-r1)=-5.67019E-4
r2=0.6137203  (r0-r2)=-0.04040271
r3=0.18662459  (r0-r3)=0.386693

nxのずれが大きくなるほど生成される値のばらつきが大きくなっていることがわかります。
ただし、乱数なので必ずしもこの規則が成立するわけではありません。
「nxのずれが小さいほど、近い値の乱数が生成される可能性が高い」という方が良いかもしれません。

この特徴を利用して、

  1. x軸の値が移動する度にnxの値を微妙に変化させる
  2. y軸の値が移動する度にnyの値を微妙に変化させる
  3. nxとnyを使ってnoise関数で乱数を生成し、その値を元に (x,y)座標における色を作成する
    という作業をくりかえすことで模様を描画したのが上のサンプルです。

Javaのサンプル

float nx, ny, step=0.01;

void setup() {
  size(500, 500);
}

void draw() {
  loadPixels();
  ny = 1;
  for (int y = 0; y < height; y++) {
    nx = 1;
    for (int x = 0; x < width; x++) {
      int c = (int)(noise(nx, ny) * 255);
      pixels[y*width+x] = color(c,c,c);
      nx += step;
    }
    ny += step;
  }
  updatePixels();
}

2次元の模様をランダムに作成するので、y軸とx軸の2重ループを作成します。
loadPixels命令を実行すると、画面のピクセル値(各点の色)が、pixelsという配列に読み込まれます。
x軸方向の変化分を変数nxで、y軸方向の変化分を変数nyで保持しています。
それぞれループの度に、stepずつ変化させています。
pixels配列の更新がおわったらupdatePixels関数を実行して、配列の内容を画面に反映しています。

nx, ny, stepの値をいろいろ変化させてみて、出力される画像がどう変わるか見てください。