surolog

AI・機械学習・データ分析 と 本 など

パーリンノイズを可視化する

NATUREofCODE

processingを用いたプログラミングの書籍として、「NATUREofCODE」というとてもおもしろいものがあります。ざっくりいうとprocessingを使って物理シミュレーションを行う内容なのですが、高校の物理の教科書に出てくるような簡単な物理法則の式を実装・適用するだけで、驚くほど生き生きと物体をシミュレートすることができます。
勉強をかねて、コードを実装していきます。

Nature of Code -Processingではじめる自然現象のシミュレーション-

Nature of Code -Processingではじめる自然現象のシミュレーション-


パーリンノイズ

物理現象をシミュレーションする上で、ランダム性を取り入れることは有効です。
ランダムな変化は自然を表現する上で活用されており、例えば最近だとMinecraftなどはランダムな地形生成でマップを作成しているようです。
このとき、数学的に正しいランダム性を使って地形を生み出すと、あまりに脈絡のないものになり「自然に」感じられません。自然の中のランダム性は、ランダムでありながら連続性があり有機的なものになります。これを表現するのに用いられるのがパーリンノイズです。processingではデフォルトのnoise関数として使用する事ができます。

ランダムノイズとパーリンノイズの時間変化を描画したものが下のグラフになります。パーリンノイズはランダムですが滑らかに変化していきます。

Fig1.パーリンノイズ
f:id:sator926:20160209213328p:plain
Fig2.ランダムノイズ
f:id:sator926:20160209213335p:plain

このノイズをx,y座標に組み込んで平面上を移動する円を描画すると以下のようになります。

f:id:sator926:20160209214211g:plain

ランダムな動きですが、なんとなく生物的な有機的な動きに感じられます。
次に、全てのピクセルにこのノイズを適用し、連続的に明度を変更すると、以下のような表現になります。

f:id:sator926:20160209221018p:plain

どんよりした曇り空、煙、あるいは鉱物の表面のようにも見えます。ノイズの変化率や色合いを調整することで、様々な質感を表現できます。今後は、このパーリンノイズを用いて自然現象を表現していきます。


せば


以下ソースコードです

  • 平面上をパーリンノイズに従いランダムに移動する円
import gifAnimation.*;
gifAnimation.GifMaker gm;
int fl=300; //framelimit

Walker w;

void setup(){
  size(500,300);
  w = new Walker();
  background(255);
  
  frameRate(50);
  gm = new gifAnimation.GifMaker(this,"perlinnoise_1D.gif");
  gm.setRepeat(0);
  gm.setDelay(20); //animetion
}

void draw(){
  w.step();
  w.display();
  
  gm.addFrame();
  if(frameCount >= fl){
    gm.finish();
    exit();
  }
}

class Walker{
  float x,y;
  float tx,ty;
  
  Walker(){
    tx=0;
    ty=10000;
  }
  
  void step(){
    x = map(noise(tx), 0,1,0,width);
    y = map(noise(ty), 0,1,0,height);
    
    tx+=0.01;
    ty+=0.01;
  }
  
  void display(){
    fill(200);
    ellipse(x,y,16,16);
  }
}
  • パーリンノイズで生成された二次元テクスチャ
float increment=0.02;

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

void draw(){
  background(0);
  loadPixels();
  
  float xoff=0.0;
  for(int x=0; x<width; x++){
    float yoff=0.0;
    for(int y=0; y<height; y++){
      float bright=map(noise(xoff,yoff),0,1,0,255);
      pixels[x+y*width]=color(bright);
      yoff+=increment;
    }
    xoff+=increment;
  }
  
  updatePixels();
}