移動、回転、拡大・縮小

OpenGLの難しさはテクニックについてあまり書かれた本や情報が少ないことではないだろうか?例えばモデルを移動、回転、拡大・縮小する際にやり方が色々ありどのやり方がベストなのかよく分らない。今読んでいる『OpenGL SuperBible 第4版』も一般的なことしか書かれていないので、テクニックは書かれていない。以下は調査した結果。

  • 移動
    • glTranslatef()でモデル自体を動かす
    • gluLookAt()でカメラを動かす

注1) ビューで見た時に、同じ量動かした際にモデル自体の大きさに依存しないで移動量が同じになるように移動量を調整する必要がある。例えば、半径5の球をX方向に10動かした時と半径1000の球をX方向に10動かしたのでは、モデルがビューにフィットしている状態では後者は微妙にしか動かない。実際は同じくらいの動きになって欲しい。

注1) オイラー角による回転は、ジンバルロックなどの問題を引き起こすため良くない。
注2) クォータニオンなどによる任意点の回転は、モデルを回転前に回転中心を原点に移動して回転後、元の位置に戻せばよい。
注3) オイラー角による回転はglRotatef()で行う。クォータニオンによる回転は、回転クォータニオンを計算し、マトリックスに変換したものをglMultMatrixf()に渡す。

  • 拡大・縮小
    • glScale()でモデル自体を拡大・縮小
    • glTranslatef()でモデルをZ方向に移動する
    • glOrtho()で視体積を調整する

注1) glScale()による拡大縮小は、法線も拡大縮小されてしまうため照光処理でおかしくなる。そのためモデル描画の前後でglEnable(GL_NORMALIZE)とglDisable(GL_NORMALIZE)を呼び出して法線を正規化する必要あり。
注2) glTranslatef()による方法だと、移動の所で挙げた同様の問題点が発生するため、あまり良い方法ではないかも。


これ以外にもやり方があるかもしれない。あと、まだモデルをビューにフィットさせる処理のやり方が分らないが、現在のビューでのモデルの最大最小座標値が分かれば良いと思うので、ピッキング辺りの章を読めば分かるかもしれない。ネットで調べても見つからない。


追記(2009/3/17):

ビューにフィットさせる方法がOpenGLのFAQの8.070に載っていた。モデルを球で近似しているので現在のモデルの向きを考慮したBounding Boxで近似した方がより良いかも。


手順は以下の通り。

  • モデルを包含する球の中心(c.x, c.y, c.z)と直径(diam)を計算
  • クリッピングプレーンのzNearとzFarを以下のように計算
zNear = 1.0;
zFar = zNear + diam;
  • glOrthoを以下のように設定(Windowの幅と高さが同じ場合)
GLdouble left = c.x - diam;
GLdouble right = c.x + diam;
GLdouble bottom c.y - diam;
GLdouble top = c.y + diam;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(left, right, bottom, top, zNear, zFar);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
  • Windowの幅と高さが違う場合、以下のように調整
GLdouble aspect = (GLdouble) windowWidth / windowHeight;
if ( aspect < 1.0 ) { // window taller than wide
  bottom /= aspect; top /= aspect;
} else {
  left *= aspect; right *= aspect;
} 
  • 視点の調整
GluLookAt (0., 0., 2.*diam, c.x, c.y, c.z, 0.0, 1.0, 0.0);


追記2(2009/3/17):

拡大縮小もFAQの8.040に載っていた。モデルのScaleを調整するとzNearとzFarでモデルが切れる可能性があるのでglOrtho()や同等物のglFrustum()を使用した方が良いらしい。