CAVE Programming


3. 3次元CGと座標変換

3次元図形を描画するための基本的な座標変換方法について学習します。
3次元CGをディスプレイ上に描くためには、モデリング変換、投影変換等の座標変換のための行列計算が行われます。ここでは、これらの座標変換とそれを実行する関数との関係について学びます。


3.1 座標変換

3次元CGでは、コンピュータ内部の3次元座標系で表現されたモデルをディスプレイ上の2次元座標系に変換して描画する必要があります。コンピュータ内部の3次元座標系をワールド座標系、ディスプレイ上の2次元座標系をスクリーン座標系と言います。
OpenGLでは、ワールド座標系で定義された3次元モデルをスクリーン座標系の2次元映像として描画するために、@モデリング変換→Aビューイング変換→B投影変換→Cビューポート変換 のプロセスによって座標変換が行われます。各座標変換で行われる処理内容は、以下の通りです。

@モデリング変換:
3次元CGでは、まず描画すべきモデルを計算機内に構築する必要があります。モデリング変換では、ワールド座標系の中で3次元図形の移動、回転、拡大、縮小等を行い、描画モデルの生成を行います。
Aビューイング変換:
OpenGLでは、視線を原点に置き-z軸方向に向けた状態が初期状態になっています。ビューイング変換では、ワールド座標系の中で設定された視点位置から見た映像を得るための座標変換を行います。
B投影変換:
ワールド座標系で表現された3次元モデルを2次元のスクリーン座標系に投影するための座標変換を行うのが投影変換です。特にVRのプログラムでは、投影線が一点に集まる透視投影変換が行われます。
Cビューポート変換:
投影面に投影された2次元映像を、スクリーン座標系で表されたウインドウ上の指定領域であるビューポート内に表示するための変換を行います。

下図は、以上の各座標変換の仕組みを図示したものです。


            図3.1:座標変換の仕組み


 
3.2 座標変換の関数

各座標変換を行うために、OpenGLでは以下に示す幾つかの関数が用意されています。
座標変換は、同次座標で表された頂点座標に座標変換を表す行列を乗算する行列計算  v'=Mv  によって計算が行われます。モデリング変換とビューイング変換は、モデルを動かすか視点を動かすかの違いで両者は同じ効果を表すため、OpenGLでは両者を合わせて、モデルビュー変換行列として扱われます。 また投影変換は、投影変換行列で表されます。

・void glMatrixMode(GLenum mode)
設定する変換行列の指定を行います。modeの引数が GL_MODELVIEW の場合はモデルビュー変換行列、GL_PROJECTION の場合は投影変換行列を指定します。

・void glLoadIdentity(void)
指定されている変換行列を単位行列に初期化します。

・void gluLookAt(GLdouble ex, GLdouble ey, GLdouble ez, GLdouble cx, GLdouble cy, GLdouble cz, GLdouble ux, GLdouble uy, GLdouble uz)
視点位置と視線方向を指定し、ビューイング変換のための行列の設定を行います。最初の3つの引数 (ex, ey, ez) は視点位置、次の3つの引数 (cx, cy, cz) は注視点位置、最後の3つの引数 (ux, uy, uz) は視線の上方向ベクトルを表します。

・void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far)
左右対称の錐台の視体積を指定し、透視投影変換行列の設定を行います。引数 fovy は視野の角度、aspect は錐台の縦横比(幅/高さ)、near, far は近接、遠方のクリップ面までの距離を示します。


     図3.2:gluPerspectiveで指定する視体積

・void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far)
左右非対称の錐台の視体積を指定することができ、透視投影変換行列の設定を行います。left, right, bottom, top, near, top の各パラメータが表す内容は下図に示す通りです。near, farは近接、遠方のクリップ面までの距離で、視点が原点にある状態で、(left, bottom, -near)、(right, top, -near) はそれぞれ近接クリップ面の左下、右上の隅の座標を示します。


      図3.3:glFrustumが指定する視体積

・void glViewport(GLint x, GLint y, GLsizei w, GLsizei h)
ウインドウ内のビューポート領域を指定することで、ビューポート変換のための行列を設定します。最初の2つの引数 (x, y) は領域の左下隅の位置、後の2つの引数 (w, h) はビューポートの幅と高さを画素で指定します。


 
3.3 display関数

sample1のプログラムでは、3次元モデルをレンダリングする各座標変換の処理は display() 関数の中で記述されています。ここでは、display関数内で行われている各座標変換の内容について確認します。ビューポート変換、投影変換、ビューイング変換、モデリング変換の各変換行列の設定の順番が逆になっていることに注意して下さい。

  void display(void)
  {
  /* viewport transform */
  glViewport(0, 0, 500, 500);

  /* projection transform */
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(90.0, 1.0, 0.1, 100.0);

  /* viewing transform */
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt(0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

  /* modeling transform */
  glColor3f(0.0, 1.0, 0.0);
  glutSolidTeapot(1.0);
  glFlush();
  }

glViewport(0, 0, 500, 500);
ビューポート変換の設定を行っています。ここでは500×500ピクセルとしてウインドウ内の全面を表示領域として使用しています。

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.0, 1.0, 0.1, 100.0);
投影変換行列を指定し、単位行列に初期化した後、視野角90度、アスペクト費1.0の対称の錐台の視体積を定義し、透視投影変換行列の設定を行っています。

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
モデルビュー変換行列を指定し、単位行列に初期化した後、視点位置を (0.0, 0.0, 3.0)、注視点を (0.0, 0.0, 0.0)、上方向ベクトルを (0.0, 1.0, 0.0)としたビューイング変換行列の設定を行っています。

OpenGLでは、z軸のプラス方向が視点に向く右手座標系を基本として用いますが、CAVEシステムを使ったVRのアプリケーションではxy平面を床面としてz軸を上向きに取る右手座標系で表すことが多いため、ここではz軸を上向きに取った座標系で仮想世界を考えることにします。

 
    図3.4:通常のOpenGLの座標系とVRアプリケーションの座標系


※練習:

視点位置、注視点位置、視体積、ビューポートの各パラメータの値を変えてサンプルプログラムを実行し、パラメータ値が描画映像にどのような影響を与えるか試してみましょう。