パーリンノイズ(Perlin noise)

Processingでランダムな数を生成するには2つの方法があります。

  • random(最大値) = 0~最大値までで、一様に分布するランダムな数を生成する
  • noise(ノイズスペース) = 0~1までのランダムな数を生成する

サイコロで出る目はランダムです。1~6までが均等にでます。これはrandom関数です。
一方、雲の密度、湯気の動き、みたいなのはある程度前の状態を受けて次の値が決まります。ランダムだけれども、緩い規則性がある、そんなときにnoise関数を使います。

ジェネレーティブアートには欠かせないnoise関数ですが、引数の使い方がrandom関数ほど直感的ではありません。

r0 = noise(f0)
r1 = noise(f1)

f0とf1の差分が小さいほど(=f0とf1の値が近いほど)、乱数r0とr1のずれが小さくなります。
その引数の使い方を実感してもらえるようなサンプルを作ってみました。

  • 一番上の赤色がrandom関数を使った場合です。0~1の範囲で値を生成し、高さを100倍にしてプロットしています。
  • 2番目の緑色はnoiseの引数を1ずつ変化させたときです。randomほどではないですが広く分布していることが確認できます。
  • 3番目の青色はnoiseの引数を0.1ずつ変化させた場合です。ある程度連続性をもって変化していることが解ります。
  • 4番目の青色はnoiseの引数を0.01ずつ変化させた場合です。かなり連続性をもって変化していることが解ります。
  • 5番目の青色はnoiseの引数を0.001ずつ変化させた場合です。変化の度合いがかなり小さいことが解ります。

コンピュータできれいな幾何学模様を描画したりすることがありますが、そんなときはこのパーリンノイズが使われていることも多いようです。

Java

ArrayList<Float> p0 = new ArrayList<Float>();
ArrayList<Float> p1 = new ArrayList<Float>();
ArrayList<Float> p2 = new ArrayList<Float>();
ArrayList<Float> p3 = new ArrayList<Float>();
ArrayList<Float> p4 = new ArrayList<Float>();
float f1 = 0, f2 = 0, f3 = 0, f4 = 0;

void setup() {  
  for (int i = 0; i < 500; i++) {
    p0.add( random(1) );

    p1.add( noise(f1) );
    f1 = f1 + 1;

    p2.add( noise(f2) );
    f2 = f2 + 0.1;

    p3.add( noise(f3) );
    f3 = f3 + 0.01;

    p4.add( noise(f4) );
    f4 = f4 + 0.001;
  }

  size(500, 500);
  strokeWeight(3);
  textSize(30);
}

void draw() {
  background(255);
  for (int i = 0; i < 500; i++) {
    stroke(255, 0, 0);
    point(i, p0.get(i)*100);

    stroke(0, 255, 0);
    point(i, p1.get(i)*100+100);

    stroke(0, 0, 255);
    point(i, p2.get(i)*100+200);

    stroke(255, 0, 255);
    point(i, p3.get(i)*100+300);

    stroke(0, 255, 255);
    point(i, p4.get(i)*100+400);
  }

  p0.add(random(1));

  p1.add(noise(f1));
  f1 = f1 + 1;
  
  p2.add(noise(f2));
  f2 = f2 + 0.1;

  p3.add(noise(f3));
  f3 = f3 + 0.01;

  p4.add(noise(f4));
  f4 = f4 + 0.001;

  p0.remove(0);
  p1.remove(0);
  p2.remove(0);
  p3.remove(0);
  p4.remove(0);
}