Imaginary Code

from kougaku-navi.net

ProcessingでCGと画像の合成をやるときの背景画像の描画

Processingにおいて3次元の描画モード(P3D)の時にimage()で画像を描くと、3次元空間中に画像が板状に配置された状態になる。これはこれで便利なのだが、ARのように3DCGと2Dの背景画像を合成するようなプログラムを作ろうとした時に、CGが背景画像に埋もれたり、隠れたりという状態が発生して若干めんどうなことになる。どうしたらいいかについて説明する。


解決策1:hint()を使ってzバッファを制御

通常はこの方法を使う。zバッファはオブジェクトの奥行き方向の重なりを正しく表現するための描画処理を担うバッファ。hint()はレンダラの動作条件を設定する関数で、パラメータとしてDISABLE_DEPTH_TESTを指定するとzバッファを無効化、ENABLE_DEPTH_TESTを指定するとzバッファを有効化する。

PImage bgimg; // 背景画像

void setup() {
  size( 640, 480, P3D );
  bgimg = loadImage("test.jpg"); // 背景画像のロード
}

void draw() {
  background(0);

  hint(DISABLE_DEPTH_TEST); // zバッファの無効化
  image( bgimg, 0, 0 );              // 背景画像の描画
  hint(ENABLE_DEPTH_TEST);  // zバッファの有効化
  
  // 3Dオブジェクトの描画
  perspective();
  translate( width/2, height/2, -30);  
  rotateX(radians(frameCount));
  rotateY(radians(frameCount));
  box(100);
}

解決策2:ピクセルをじかに操作して描く

もし解決策1でダメな時、あるいは何らかのピクセル処理が伴うとき。

PImage bgimg;  // 背景画像

void setup() {
  size(640, 480, P3D);
  bgimg = loadImage("test.jpg"); // 背景画像のロード
}

void draw() {
  background(0);

  // 背景画像の描画
  loadPixels();  // 画面のピクセル操作の準備
  bgimg.loadPixels();  // 画像のピクセル操作の準備
  for (int i=0; i<bgimg.width * bgimg.height; i++) {
    pixels[i] = bgimg.pixels[i];  // ピクセルデータの書き込み
  }
  updatePixels();  // 画面のピクセルの更新

  // 3Dオブジェクトの描画
  perspective();
  translate( width/2, height/2, -30);  
  rotateX(radians(frameCount));
  rotateY(radians(frameCount));
  box(100);
}

解決策3:ortho()を使う

これも別解。投影の方式を平行投影(ortho)にして2D描画する方法。ortho()の第6引数は、視点から2D平面までの距離+0.5。たぶん0.5はなくてもよいが、ぴったりにならないように保険の意味で微妙にずらしている。

PImage bgimg; // 背景画像

void setup() {
  size( 640, 480, P3D );
  bgimg = loadImage("test.jpg"); // 背景画像のロード
}

void draw() {
  background(0);

  // 背景画像の描画
  ortho(0, width, 0, height, 0, (height/2)/tan(radians(30)) + 0.5);
  image( bgimg, 0, 0 );

  // 3Dオブジェクトの描画
  perspective();
  translate( width/2, height/2, -30);  
  rotateX(radians(frameCount));
  rotateY(radians(frameCount));
  box(100);
}