パーリンノイズで模様作り

12月 21st, 2011

Processing Advent Calendar 2011(21日目)

パーリンノイズで模様作り

今回は、Processingのnoise()を利用していろいろな模様を作ります。

乱数とパーリンノイズ

ランダム

Processingで乱数を得る方法は、random()とnoise()の2種類があります。
まず、random()は、文字通りランダム値を返すものです。


図は横方向を試行回数とし、高さをrandom()で決めたものです。
random()には規則性が見られません。

final int ELLIPSE_SIZE = 10;
 
size(400, 400);
smooth();
background(0);
 
for(int x = 0; x < width; x += ELLIPSE_SIZE){
  float y = random(height);
  ellipse(x, y, ELLIPSE_SIZE, ELLIPSE_SIZE);
}

ノイズ

続いてノイズです。これはパーリンノイズという技法で作られる乱数の一種です。


noise()には、座標の様な形でパラメータを与えます。
図のように、noise()にはある程度の連続性が見られます。これがノイズの特徴です。
パラメータとして同じような数値を与えれば、同じような結果が返ってきます。
ランダムだけども、連続性もある、そんな定数と乱数の中間の様なものを得ることができます。

なお、パラメータには小さな値を入れると連続性が高まります。このため、今回はDIVISION(=100)で割った値を利用しています。

final int ELLIPSE_SIZE = 10;
final float DETAIL = 100; //  noise()の連続性の具合
 
size(400, 400);
smooth();
background(0);
 
for(int x = 0; x < width; x += ELLIPSE_SIZE){
  float y = noise(x / DIVISION) * height;
  ellipse(x, y, ELLIPSE_SIZE, ELLIPSE_SIZE);
}

noise()を使ってみよう

1次元のnoise()


アプレットはこちら
noiseに引数を1つ与えた場合です。縦それぞれに対して、得た値の分だけ上から白い線を引いています。
山脈のシルエットの様な模様が描かれました。

final float DETAIL = 100; //  noise()の連続性の具合
int counter = 0;
 
void setup(){
  size(400, 400);
}
 
void draw(){
  background(0);
  stroke(255);
 
  for(int x = 0; x < width; x++){
    float y = noise((x + counter) / DETAIL) * height;
    line(x, 0, x, y);
  }
 
  counter++;
}

2次元のnoise()


アプレットはこちら
noiseに引数を2つ与えた場合です。各ピクセルごとに、それぞれ得た値を白の濃さとして描いています。
霧の様な模様が描かれました。

final float DETAIL = 100; //  noise()の連続性の具合
final int MAX_COLOR = 255;
int counter = 0;
 
void setup(){
  size(400, 400);
  noStroke();
}
 
void draw(){
  background(0);
 
  loadPixels();
  for(int y = 0; y < height; y++){
    for(int x = 0; x < width; x++){
      float whity = noise((x + counter) / DETAIL, (y + counter) / DETAIL) * MAX_COLOR;
      pixels[y * width + x] = color(whity);
    }
  }
  updatePixels();
 
  counter++;
}

3次元のnoise()


アプレットはこちら
noiseに引数を3つ与えた場合です。3次元空間に対して、得た値が高いところのボックスを明るく・大きくしています。
流れる煙の様な模様が描かれました。

final float DETAIL = 100; //  noise()の連続性の具合
final int MAX_POWER = 20;  //  その空間の強さの最大(色と大きさにも使われる)
int counter = 0;
 
void setup(){
  size(400, 400, P3D);
  noStroke();
}
 
void draw(){
  //  回転させるために、軸を中央に移動。
  translate(width / 2, height / 2, -width / 2);
  rotateY(radians(counter/ 2.0));
 
  //  描画のために、基準点を元に戻す
  translate(-width / 2, -height / 2, width / 2);
 
  background(0);
  for(int z = 0; z > -width; z -= MAX_POWER){
    for(int y = 0; y < height; y += MAX_POWER){
      for(int x = 0; x < width; x += MAX_POWER){
        pushMatrix();
        translate(x, y, z);
 
        float deep = noise(x / DETAIL, y / DETAIL, (z + counter * 5) / DETAIL) * MAX_POWER;
        fill(255, deep * deep / 4);
        box(deep * 2);
        popMatrix();
      }
    }
  }
 
  counter++;
}

不思議な動き


アプレットはこちら

今まではnoise()の値をそのまま使っていましたが、ここで、値を少し加工してみることにします。
今回は、noise()の値を0~100にするとして、10、50、80前後のみ色をつけるようにしてみました。
すると、何か奇妙な物体がうねうねしているようなものを作ることができました。

final float DETAIL = 100; //  noise()の連続性の具合
 
final int MAX_MAP = 100;
int[] valueMap = new int[MAX_MAP];  //  noise()で得た値を変換するためのマップ
 
float counter = 0;
 
void setup(){
  size(400, 400); 
  createMap();
}
 
//  予め、0~99の各値に対して、変換する値を計算しておくもの。
void createMap(){
 
  //  基本は0とする。
  for(int i = 0; i < MAX_MAP; i++){
    valueMap[i] = 0;
  }
 
  //  20付近に値を与える
  for(int i = 0; i < 20; i++){
    int value = (10 - i);
    valueMap[i + 10] = value * value * 2;
  }
 
  //  50付近に値を与える
  for(int i = 0; i < 20; i++){
    int value = (10 - i);
    valueMap[i + 50] = value * value * 2;
  }
 
  //  80の前後を白くする。
  for(int i = 0; i < 20; i++){
    int value = (10 - i);
    valueMap[i + 80] = value * value * 2;
  }
}
 
void draw(){
  background(0);
 
  loadPixels();
  for(int y = 0; y < height; y++){
    for(int x = 0; x < width ; x++){
      //  noise()の値を得る
      int d = (int)(noise(x / DETAIL, y / DETAIL, counter / DETAIL) * 100);
 
      //  noise()で得た値を、マップを使って変換する。
      int id = x + y * height;
      pixels[id] = color(valueMap[d]);
    }
  }
  updatePixels();
 
  counter += 0.4;
}

おまけ


アプレットはこちら
noise()のパラメータは必ずしも座標にマッチさせる必要はありません。色の赤・緑・青それぞれに割り当てるとこのようになります。

final float DETAIL = 100; //  noise()の連続性の具合
final int MAX_COLOR = 128;
final int BASE_COLOR = 128;
int counter = 0;
 
void setup(){
  size(400, 400);
  noStroke();
}
 
void draw(){
  background(0);
 
  loadPixels();
  for(int y = 0; y < height; y++){
    for(int x = 0; x < width; x++){
      float r = noise((x * 1 + counter) / DETAIL, (y * 1 + counter) / DETAIL) * MAX_COLOR + BASE_COLOR;
      float g = noise((x * 2 + counter) / DETAIL, (y * 2 + counter) / DETAIL) * MAX_COLOR + BASE_COLOR;
      float b = noise((x * 3 + counter) / DETAIL, (y * 3 + counter) / DETAIL) * MAX_COLOR + BASE_COLOR;
      pixels[y * width + x] = color(r, g, b);
    }
  }
  updatePixels();
 
  counter++;
}

Tags: , ,
Posted in Processing Advent Calendar2011 | No Comments »

Comments

Leave a Reply

 Comment Form