2011/06/15

Processingのカメラ行列にアクセスしたい

【何の役に立つか分からない技術コーナー】

Processing で 3D を扱っていて、地味に不便だなぁと感じるのが、カメラ行列(射影行列ではない)に直接アクセスできない事。

printCamera() メソッドでカメラ行列をコンソールに表示する事は可能だけど、これを眺めるだけでカメラの並進量や回転量を把握するのは、残念ながら普通の人には難しい。

加えて、そのカメラ行列をプログラム内で使う事は(現時点では)できないようである。

これができないと、たとえばデバッグカメラ(カメラ配置を第三者視点から確認する事)が多少やりづらい(工夫次第でなんとかなりそうだが)。

そこでひとまず、Processing 標準の camera() メソッドをエミュレートするものを作ってしまう事にした。

以下に当該メソッドのソースコードを示す。使い方は camera() メソッドと基本的に一緒。
  1. // 世界座標を、カメラに合わせて動かす  
  2. // 引数の意味は、camera()メソッドと同じ  
  3. void worldToCamera() {  
  4.   worldToCamera(  
  5.     width/2.0, height/2.0, (height/2.0) / tan(PI*60.0 / 360.0),   
  6.     width/2.0, height/2.00,       
  7.     010);  
  8. }  
  9. void worldToCamera(float eyeX, float eyeY, float eyeZ,  
  10.                    float centerX, float centerY, float centerZ,   
  11.                    float upX, float upY, float upZ) {  
  12.     
  13.   // カメラ座標空間の3軸  
  14.   PVector r3 = new PVector(eyeX-centerX, eyeY-centerY, eyeZ-centerZ);  
  15.   PVector r2 = new PVector(upX, upY, upZ);  
  16.   PVector r1 = r2.cross(r3);  
  17.   r2 = r3.cross(r1);  
  18.     
  19.   // 正規化  
  20.   r1.normalize();  
  21.   r2.normalize();  
  22.   r3.normalize();  
  23.     
  24.   /* ================================================== */  
  25.   /*  各軸まわりの回転量、および並進量を個別に求める例  */  
  26.   /* オイラー角表現はヘディング・ピッチ・バンクに準ずる */  
  27.   /* ================================================== */  
  28.   float h, p, b;  
  29.   p = asin(-r2.z);  
  30.   if (cos(p) != 0) {  
  31.     h = atan2(r1.z / cos(p), r3.z / cos(p));  
  32.     b = atan2(r2.x, r2.y);  
  33.   } else {  
  34.     b = 0;  
  35.     h = atan2(-r3.x, r1.x);  
  36.   }  
  37.   
  38.   resetMatrix();  
  39.   rotateY(h);  // ヘディング角  
  40.   rotateX(p);  // ピッチ角  
  41.   rotateZ(b);  // バンク角  
  42.   translate(-eyeX, -eyeY, -eyeZ);  
  43.   
  44.   /* ================================================== */  
  45.   // 別解:applyMatrix による一括変換の例  
  46.   /* ================================================== 
  47.    
  48.      // 並進成分の計算 
  49.      PVector t = new PVector( 
  50.        -(eyeX * r1.x + eyeY * r1.y + eyeZ * r1.z), 
  51.        -(eyeX * r2.x + eyeY * r2.y + eyeZ * r2.z), 
  52.        -(eyeX * r3.x + eyeY * r3.y + eyeZ * r3.z) 
  53.      ); 
  54.      // 変換行列の作成・適用 
  55.      resetMatrix(); 
  56.      applyMatrix(r1.x, r1.y, r1.z, t.x, 
  57.                  r2.x, r2.y, r2.z, t.y, 
  58.                  r3.x, r3.y, r3.z, t.z, 
  59.                   0.0,  0.0,  0.0, 1 
  60.      ); 
  61.  
  62.      ================================================== */  
  63. }  

このままでは camera() と一緒だけど、たとえば MyCamera クラスとかで包んでやって、カメラの並進量・回転量(あるいは行列そのもの)に対するアクセサを定義してやれば、もうちょっと高度なカメラ制御が可能になると思う。



【テスト】

適当な視点から箱を俯瞰するサンプルプログラムを作る。ただし、カメラの設定には、既存の camera() メソッドと新たに作った worldToCamera() メソッドを用意し、どちらを使用するかをマウスで切り替えられるようにした(デフォルトでは worldToCamera() メソッドが、マウスを押しているときだけ camera() メソッドが使用される)。


ソースコードは以下の通り。
  1. int boxSize = 90;  // 箱の大きさ  
  2. int nBox    = 10;   // 箱の数  
  3. int mergine = 50;   // 余白  
  4.   
  5. void setup() {  
  6.   size(800600, P3D);  
  7. }  
  8.   
  9. void draw() {  
  10.   background(0);  
  11.     
  12.   if(mousePressed) {  
  13.     // 既存の関数  
  14.     camera(800, -500700000110);  
  15.   } else {  
  16.     // 新しく作った関数  
  17.     worldToCamera(800, -500700000110);  
  18.   }  
  19.     
  20.   // 色を設定  
  21.   colorMode(HSB, nBox, 100100);  
  22.     
  23.   // 適当に箱をならべる  
  24.   pushMatrix();  
  25.   translate(-(nBox * (boxSize + mergine))/200);  
  26.   for(int i = 0; i < nBox; ++i) {  
  27.     pushMatrix();  
  28.     stroke(i, 9999);  
  29.     fill(i, 9999100);  
  30.     translate(i * (boxSize + mergine), 00);  
  31.     box(boxSize);  
  32.     popMatrix();  
  33.   }  
  34.   popMatrix();  
  35. }  

実際に走らせてみると両者に差はなく、きちんと camera() が再現されている事が判る。

これを応用すれば、既知のカメラ視点・注視点・鉛直軸より、並進・回転成分を抽出するメソッドを書く事も可能だろう。

で。

今日はちょっと忙しいのでここまで。中途半端でごめん。


【てきとう参考文献】

カメラの回転行列からオイラー角(ヘディング、ピッチ、バンク角)の回転量を取り出す箇所に関しては、Fletcher Dunn, Ian Parberry 著、松田 晃一訳『実例で学ぶ ゲーム 3D 数学』を参考にしたよ。

0 件のコメント:

コメントを投稿

ひとことどうぞφ(・ω・,,)