パーリンノイズ(とんぼ)

パーリンノイズを使ってトンボの動きを表現してみました。またrandomを使った場合とnoiseを使った場合を簡単に比較できるようにしてみました。

DragonFlyクラス

トンボはDragonFlyクラスで表現しています。プロパティとメソッドは以下の通りです。

  • pos = 自分の座標
  • xn = X軸のパーリンノイズ変数
  • yn = y軸のパーリンノイズ変数
  • img = トンボの画像
  • paint = トンボを移動させて描画します。

paintメソッド

perlinMode変数がtrueのときはパーリンノイズ(noise関数)、falseのときはランダム(random関数)を使ってxとyの移動量を計算しています。どちらのモードでも-0.5~0.5の範囲の数値を生成しています。
パーリンノイズのときはノイズ用の変数を都度0.005増やしています。これによってある程度規則性をもった数値が取得できるようになります。

移動量x, yがもとまったら、次の座標をpos.x, pos.yに設定します。今回はxとyの値を10倍していますが、この数を変えるとトンボの移動するスピードが変化します。画像を回転するために、atan2関数を使ってxとyから回転角を求めています。あとは、描画する場所を原点に移動して、座標系をrotateで回転し、image関数で画像を描画しています。

モードの切り替え

スペースキーを押下すると、noise→random→noise→…と切り替わります。

class DragonFly {
  PVector pos;
  PImage img;
  float xn = 0, yn = 0;
  DragonFly(float x, float y) {
    pos = new PVector(x, y);
    img = loadImage("tombo.png");
    xn = random(100);
    yn = random(100);
  }
  
  void paint() {
    float x, y;
    if (perlinMode) {
      x = noise(xn) - 0.5;
      y = noise(yn) - 0.5;
      xn += 0.005;
      yn += 0.005;
    } else {
      x = random(1) - 0.5;
      y = random(1) - 0.5;
    }

    pos.x += x*10;
    pos.y += y*10;
    float theta = atan2(y, x);
    pushMatrix();
    translate(pos.x, pos.y);
    rotate(theta);
    image(img, 0, 0);
    popMatrix();
  }
}

boolean perlinMode = true;
PImage back;
ArrayList<DragonFly> tombos = new ArrayList<DragonFly>();

void setup() {
  back = loadImage("aki.png");
  size(800, 570);
  for (int i = 0; i < 5; i++) {
    tombos.add(new DragonFly(random(800), random(570)));
  }
}

void draw() {
  imageMode(CORNER);
  background(210, 120, 30);
  image(back, 0, 0);
  imageMode(CENTER);
  for (DragonFly t : tombos) {
    t.paint();
  }
}

void mousePressed() {
  tombos.add(new DragonFly(mouseX, mouseY));
}

void keyPressed() {
  if (key == ' ') {
    perlinMode = !perlinMode;
  }
}