Imaginary Code

from kougaku-navi.net

ちょっと変わった方法で円とか四角形をプルプルさせる - Processing

ellipse()やrect()などの描画命令が並んでいる場所をfilter.begin()とfilter.end()で挟み込むと、その範囲内で描画した円や四角形がプルプルするようになる、というのを実験的に作りました。



メインのコードはこんな感じ。普通のアイデアだったら、ellipse()とかrect()の座標値を直接random()でブラすコードを書くところですが、そうなってないのがミソ。

Filter filter; // プルプルフィルタ

void setup() {
  size(400, 300);
  filter = new Filter(this); // プルプルフィルタの準備
}

void draw() {  
  background(222);
  stroke(0);
  strokeWeight(4);

  filter.begin(); // ここからプルプル

  fill(0, 255, 0);
  rect(50, 90, 110, 110); // 四角形

  fill(255, 0, 0);
  ellipse(290, 150, 150, 150); // 円

  filter.end(); // ここまでプルプル
}


プルプル処理を担っているFilterクラスの中身はこんな感じ。

class Filter extends PGraphicsJava2D {
  protected PApplet app;

  public Filter(PApplet parent) {
    app = parent;
    setParent(parent);
    setSize(parent.width, parent.height);
  }

  public void begin() {
    if (app.recorder == null) {
      app.recorder = this;
      beginDraw();
      super.image( app.get(), 0, 0 );
      
      // keep parameters
      super.stroke( app.g.strokeColor );
      super.strokeWeight( app.g.strokeWeight );
      super.strokeCap( app.g.strokeCap );
      super.fill( app.g.fillColor );
      super.rectMode( app.g.rectMode );
      super.imageMode( app.g.imageMode );
      super.ellipseMode( app.g.ellipseMode );      
    }
    pushMatrix();
  }

  public void end() {
    popMatrix();
    if ( app.recorder != null ) {  
      endDraw();
    }
    app.recorder = null;    
    app.image( this.get(), 0, 0 );
  }

  @Override
  public void ellipse( float x, float y, float a, float b ) {
    super.ellipse( x+random(-4, 4), y+random(-4, 4), a, b );
  }

  @Override
  public void rect( float x, float y, float w, float h ) {
    super.rect( x+random(-4, 4), y+random(-4, 4), w, h );
  }
}

からくり

別にプルプルさせることにはあまり意味はなくて、肝心なのはそのしかけです。
ポイントは3つ。

  1. PAppletの中にrecorderなるメンバ変数がいる。これにPGraphicsJava2Dの派生クラス(ここではFilter)のインスタンスを渡しておくとdraw()内に記述されている描画処理がそっちにも行くようになる。ちなみに3Dの描画を行っている場合はPGraphicsJava2Dの代わりにPGraphics3Dにすれば良い。
  2. PGraphicsJava2Dの派生クラスの中でellipse()やrect()などの描画系メソッドをオーバーライドすることによって、通常とは異なる独自の描画処理をさせられるようになる。
  3. PGraphicsJava2Dの派生クラスに対してget()メソッドを使うとPImage型の画像データ(描画結果)を得られるので、これをimage()で描画すればバックグラウンドで描いた絵に差し替えることができる。

1と2のテクニックはPickingライブラリで使われているもので、今回はそれを真似て作りました。begin()〜end()で挟むだけでその範囲の描画命令に別な効果を付与できるしかけはなかなか面白いです。メソッドのオーバーライドが成せる技ですね。今回は例としてプルプルさせましたが、他にもellipse()とかrect()が使われた回数をカウントしたりとか、ちょっとしたアクロバットができそうです。