マスクを使ってPGraphicsの内容をくりぬいて使用する

12月 6th, 2011

Processing Advent Calendar 2011 (6日目)

マスクとは


引き続き、PGraphicsの記事を書きます。今回はPGraphicsでマスクを利用する方法です。
マスクを使うと、上記画像の様にPGraphicsの内容を好きな形でくりぬくことができます。

マスクを使う

マスクの概念

マスクは、グレースケール(白黒画像)で表します。
PGraphicsとマスクを重ねた際に、マスクの白さが「不透明率」として合成されます。

まずはソースコードです。

PGraphics pg;
PGraphics mask;
PFont font;
final int ELLIPSE_SIZE = 30;
void setup() {
  size(400, 400);
  smooth();
  background(0);
 
  pg = createGraphics(width, height, P2D);
  mask = createGraphics(width, height, P2D);
 
  pg.beginDraw();
  pg.smooth();
  pg.background(0);
  for (int y = 0; y < pg.height; y += ELLIPSE_SIZE) {
    for (int x = 0; x < pg.width; x += ELLIPSE_SIZE) {
      pg.fill(random(176, 255), random(176, 255), random(176, 255));
      pg.ellipse(x, y, ELLIPSE_SIZE, ELLIPSE_SIZE);
    }
  }
  pg.endDraw();
 
  mask.beginDraw();
  mask.smooth();
  mask.background(0);
  mask.noStroke();
  mask.fill(255);
  mask.ellipse(mask.width / 2, mask.height / 2, mask.width, mask.height);
  mask.endDraw();
 
  pg.mask(mask);  
  image(pg, 0, 0);
}

今回はPGraphicsを描画用、マスク用と、計2つ用意します。
描画用PGraphicsには描画したいものを描きます。今回は円を敷き詰めています。
マスク用PGraphicsは、切り取る内容を描画します。白さが「不透明率」になるので、完全に残すところには白を。残さない場所には黒を。灰色にすると、その濃さが透明度になります。 今回は、背景を黒くし、その後中央に白い円を描いたものをマスクにしました。

PGraphicsにマスクを適用するには、PGraphics.mask()を使います。
すると、PGraphicsには、指定したマスクがかかります。

図にすると、下記のようになります。

半透明のマスクを使う

マスクに灰色を利用すれば、PGraphicsをだんだん透明にしていくこともできます。

この時のマスクは次の画像のように、グラデーションになっています。

PGraphics pg;
PGraphics mask;
PFont font;
final int ELLIPSE_SIZE = 30;
void setup() {
  size(400, 400);
  smooth();
  background(0);
 
  pg = createGraphics(width, height, P2D);
  pg.smooth();
  mask = createGraphics(width, height, P2D);
 
  pg.beginDraw();
  pg.background(0);
  for (int y = 0; y < pg.height; y += ELLIPSE_SIZE) {
    for (int x = 0; x < pg.width; x += ELLIPSE_SIZE) {
      pg.fill(random(176, 255), random(176, 255), random(176, 255));
      pg.ellipse(x, y, ELLIPSE_SIZE, ELLIPSE_SIZE);
    }
  }
  pg.endDraw();
 
  mask.beginDraw();
  mask.smooth();
  mask.background(0);
  mask.noStroke();
  for (int w = mask.width; w > 0; w -= 10) {
    mask.fill(255 - w * 255 / mask.width);
    mask.ellipse(mask.width / 2, mask.height / 2, w, w);
  }
  mask.endDraw();
 
  pg.mask(mask);  
  image(pg, 0, 0);
}

反射効果とグラデーションを組み合わせてみよう

先日の反射効果と合わせて使うと、反射部分の文字の上部を徐々に透明にでき、よりよいエフェクトにすることができます。

PGraphics pg;
PGraphics mask;
PFont font;
void setup() {
  size(400, 200);
  background(0);
  imageMode(CENTER);
 
  font = createFont("MS Gothic", 48);
  pg = createGraphics(320, 50, P2D);
  mask = createGraphics(320, 50, JAVA2D);
 
  //  PGraphicsに文字を描画する
  pg.beginDraw();
  pg.background(0);
 
  pg.textFont(font);
  pg.textAlign(LEFT, BASELINE);
  pg.text("ReflectEffect", 0, pg.height);
  pg.endDraw();
  translate(width / 2, height / 2 - pg.height / 2);
  image(pg, 0, 0);
 
  //  反射用のマスクを作る
  mask.beginDraw();
  for(int y = 0; y < mask.height; y++){
    float whityRatio = (float)y / mask.height;
    float whity = whityRatio * whityRatio;
    mask.stroke(whity * 255);
    mask.line(0, y, mask.width, y);
  }
  mask.endDraw();
 
  //  反射している文字を描画する。
  translate(0, pg.height);
  scale(1, -1);  //  上下反転
  pg.beginDraw();  
  pg.filter(BLUR, 2);  //  "ぼけ"をかける
  pg.mask(mask);
  pg.endDraw();
  image(pg, 0, 0);
}

この時のマスクは下記のようになっています。

ちなみに、ソースコード中でマスクのグラデーションの白色(変数whity)を二乗しております。理由は二乗にするとはっきり見える部分(白い部分)をよりはっきり残しつつ、消える部分(黒い部分)が増えるため、ベタな数値を使うよりも良いと考えているからです。

Tags:
Posted in Processing Advent Calendar2011 | No Comments »

Comments

Leave a Reply

 Comment Form