Experiment


11. ウオークスルー

仮想世界の中をダイナミックに移動するためのウオークスルー機能の実装方法について学習します。
仮想世界をインタラクティブに体験するための機能としてウオークスルーがあげられます。ここではこれまでに制作した仮想世界の中を大きく移動するためのウオークスルー機能の原理と実装方法を学びます。


11.1 ウオークスルーと座標系

バーチャルリアリティにおけるインタラクション機能としては、ディスプレイ空間内での身体動作による局所的な視点移動の他に、仮想世界の中での利用者の存在位置の大域的な移動があげられます。このようなディスプレイサイズを超える移動は、ソフトウエアによるウオークスルーの機能として実行されます。
ディスプレイ空間内での視点移動だけを考慮すればいい場合は、ディスプレイの座標系は仮想世界のワールド座標系に一致、あるいは固定されています。これに対してウオークスルーを行う場合は、ワールド座標系の中でのディスプレイ座標の位置が移動することになります。この場合、利用者の視点位置はディスプレイ座標系の中での位置に加えて、ワールド座標系に対するディスプレイ座標の位置の変化を合わせて考える必要があります。下図は、ウオークスルーによる座標系の移動の関係を示したものです。


     図11.1:ウオークスルーによる座標系の移動


 
11.2 キーボード入力

一般に、ウオークスルーを実行するためのインタフェースデバイスとしては、キーボード、ジョイスティック、ゲームコントローラ、データグローブ等が使用されます。ここでは最も基本的なデバイスとして、キーボード操作によるウオークスルーを実装します。

ウオークスルー機能を入れたサンプルプログラムとして sample4 があります。以下の手順でダウンロードして下さい。

  ・http://green.cc.tsukuba.ac.jp/tetsu/lecture/exp/ にアクセスし、
   sample4.tarをダウンロード
  ・% tar xvf sample4.tar によりファイルを展開

このサンプルプログラムでは、'a'で前進、'b'で後退、'c'で右向き、'd'で左向きの動作を行います。以下は samaple4 の実行中の例です。



              図11.2:ウオークスルーによる視点の移動

OpenGLでキーボードからの入力を受けるには、次の関数を使用します。

・void glutKeyboardFunc(void (*func)(unsigned int key, int x, int y))
この関数ではキーボードからASCII文字が押されたときに呼び出す関数 func を指定します。コールバックパラメタの key が入力されたASCII値を示します。また x, y はキーが押されたときのマウスの位置を示しますが、ここでは使用しません。

以下は sample4 のプログラムにおける glutKeyboardFunc() の使用例を示したものです。キーが押されたときの処理は keyboard() の関数で指定しています。walk[3]、turn[3] はワールド座標系に対するディスプレイ座標の位置と方向を示しています。ここでは、2次元平面上でのウオークスルーだけ行っているので、walk[0], walk[1] によるx方向、y方向の移動と turn[2] によるz軸周りの回転だけ使用しています。'a','b'のキー操作では 0.01 の距離の移動、'c','d'のキー操作では 1.0度の回転を行っています。また'z'キーで初期状態に戻ります。

  float walk[3], turn[3];

  void keyboard(unsigned char ckey, int x, int y)
  {
   switch(ckey){
   case 'a':
    walk[0]=walk[0]+0.01*sin(turn[2]/180.0*3.141592);
    walk[1]=walk[1]+0.01*cos(turn[2]/180.0*3.141592);
    break;
   case 'b':
    walk[0]=walk[0]-0.01*sin(turn[2]/180.0*3.141592);
    walk[1]=walk[1]-0.01*cos(turn[2]/180.0*3.141592);
    break;
   case 'c':
    turn[2]=turn[2]+1.0;
    break;
   case 'd':
    turn[2]=turn[2]-1.0;
    break;
   case 'z':
    walk[0]=walk[1]=walk[2]=0.0;
    turn[0]=turn[1]=turn[2]=0.0;
    break;
   }
  }

  int main(int argc, char **argv)
  {
  ..........
  glutDisplayFunc(display);
  glutIdleFunc(idle);
  glutKeyboardFunc(keyboard);

  /* main loop */
  glutMainLoop();
  return 0;
  }


11.3 ウオークスルー機能の実装

キー入力によるディスプレイ座標の移動をウオークスルー機能として映像に反映させるには、座標系の移動量だけ視点位置を動かすことが必要です。具体的には display() 関数内の gluLookAt() の視点位置の引数にディスプレイ座標の移動量を加えた値を指定します。以下はウオークスルー機能を追加したサンプルプログラムの記述例を示したものです。

  void display(void)
  {
  ..........
  /*** Left Eye ***/
  ..........
  /* viewing transform */
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt(viewpos[0][0]+walk[0], viewpos[0][1]+walk[1], viewpos[0][2],
          viewpos[0[0]+walk[0]+sin(turn[2]/180.0*3.141592),
         
viewpos[0][1]+walk[1]+cos(turn[2]/180.0*3.141592),
          viewpos[0][2], 0.0, 0.0, 1.0);

  ..........
  /*** Right Eye ***/
  ..........
  /* viewing transform */
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt(viewpos[1][0]+walk[0], viewpos[1][1]+walk[1], viewpos[1][2],
          viewpos[1][0]+walk[0]+sin(turn[2]/180.0*3.141592),
          viewpos[1][1]+walk[1]+cos(turn[2]/180.0*3.141592),
          viewpos[1][2], 0.0, 0.0, 1.0);

  ..........
  }

ここでは、ウオークスルーによって視点位置が、(walk[0], walk[1], 0.0) だけ平行移動し、z軸に関してturn[2] だけ回転移動しています。一般に2次元平面上を移動するウオークスルーでは、平面上の移動とz軸の周りの回転だけを考えればいいですが、空間を3次元的に移動するフライスルーの場合には、z軸方向の移動やx軸、y軸周りの回転も考慮する必要があります。