CAVE Programming


5. 3Dモデリング

より複雑な3次元物体のモデリングを行う方法について学習します。
複雑な形状も幾つかの基本図形の組み合わせに分解することができます。ここでは、モデリング変換によって基本図形を組み合わせることで、より複雑なモデルを表現する方法について学びます。


5.1 モデリング変換

立方体や球などの基本図形のプリミティブは、座標系の原点を中心に定義されています。そのため、必要な場所にこれらの基本図形を配置するためには座標変換を行わなくてはなりません。また、これらの基本図形を移動させて組み合わせることで、複雑な形状を表現することが可能になります。
基本図形を定義している座標系をローカル座標系、仮想空間を定義している座標系をワールド座標系と言います。3次元CGのモデリングでは、モデリング変換によってローカル座標系で表された基本図形の位置や姿勢、大きさを変化させ、最終的にワールド座標系の中で仮想物体の表現を行います。
モデリング変換で行われる座標変換としては、平行移動、回転、拡大・縮小等があります。
下図は、モデリングにおける座標変換の様子を図示したものです。これ例ではローカル座標系で定義された円柱を平行移動、回転によってワールド座標系の所定の位置に配置しています。


図5.1:基本図形を用いたモデリング変換

以下は、これらの操作を行うために用意されている関数です。

・void glTranslatef(GLfloat x, GLfloat y, GLfloat z);
ローカル座標系のオブジェクトに対して (x, y, z) の平行移動を行います。

・void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
ローカル座標系のオブジェクトに対して、(x, y, z) 方向の軸を回転軸として右回りに angle (度)の回転を行います。

・void glScalef(GLfloat x, GLfloat y, GLfloat z);
x軸、y軸、z軸に沿ってそれぞれ x, y, z の割合で拡大、縮小を行います。マイナスの値の時は座標が反転します。

以下は、sample2 の display() 関数内で行われているモデリング変換の部分を示したものです。

  void display(void)
  {
  .....
   /* table */
  glPushMatrix();

  glTranslatef(0.0, 0.0, 0.60);
  glRotatef(90.0, 1.0, 0.0, 0.0);
  Cylinder(0.8, 0.02, 30);

  glTranslatef(0.5, -0.3, 0.5);
  Cylinder(0.02, 0.30, 30);
  glTranslatef(-1.0, 0.0, 0.0);
  Cylinder(0.02, 0.30, 30);
  glTranslatef(0.0, 0.0, -1.0);
  Cylinder(0.02, 0.30, 30);
  glTranslatef(1.0, 0.0, 0.0);
  Cylinder(0.02, 0.30, 30);
  .....
  }

ここでは新しく定義した円柱を描画する関数 myCylende() を用い、平行移動と回転を行いながらテーブルのモデルを作成しています。テーブルの板を描画するために、glRotatef がコールされた後は、(x, y, z) の各軸の方向が変化していることに注意して下さい。


 
5.2 スタック

モデリング変換によって基本図形を組み合わせて複雑なモデルを作成していく場合、座標変換が繰り返されることによって座標系の把握が困難になります。また変換による誤差が蓄積されていくという問題が生じます。このような問題を回避するために、スタックを用いて座標系を保存しておき、必要に応じて座標系を復元して使用するという方法を行うことができます。
スタックは最後に入れたデータを先に取り出せるデータ構造であり、OpenGLではモデルビュー変換行列と投影変換行列のスタックが用意されています。これらのスタックに対して、glPushMatrix()、glPopMatrix() の関数を用いて変換行列の保存、復元を行います。


    図5.2:スタックの原理

各関数の意味は以下の通りです。

・void glPushMatrix(void);
現在の行列をglMatrixMode()で選択されている行列のスタックにプッシュします。スタックの内容は1段ずつ押し込まれます。

・void glPopMatrix(void);;
glMatrixMode()で選択されている行列スタックから最上位の内容を取り出し現在の行列とします。スタックの内容は1段ずつポップします。

sample2のプログラムでは、テーブルを描画するために座標変換を繰り返すため、テーブルの描画前にモデルビュー変換行列をスタックにプッシュしておき、テーブル描画後にポップして、ティーポットの描画を行っています。

  display()
   {
  .....
  glPushMatrix();

  /*table */
  ..........
  /* teapot */
  glPopMatrix();
  glTranslatef(0.0, 0.0, 0.76);
  glRotatef(90.0, 1.0, 0.0, 0.0);
  glutSolidTeapot(0.2);
   .....
  }