ウォークスルーは3次元CGシーンの中を歩き回る効果のことを言います. これは視点の移動によるアニメーションです.マウスで視点の位置を動かすプログラムを作ってみましょう. これまでに作ったプログラムをベースを改造するのが手っ取り早いと思いますが,うまく行かなければ下の手順を参考にしてください. ソースファイル名は prog3.c としてください.
下のプログラムはタイル状の床に四つの立方体を置いたシーンを静止画で表示します. 立方体の表示には glutSolidCube() という関数を用いています. ただし,このプログラムでは,これを display() ではなく,別の関数 scene() の中で実行しています.
#include <stdlib.h> #include <GL/glut.h> void scene(void) { /* 物体の色 */ static GLfloat red[] = { 0.8, 0.2, 0.2, 1.0 }; static GLfloat green[] = { 0.2, 0.8, 0.2, 1.0 }; static GLfloat blue[] = { 0.2, 0.2, 0.8, 1.0 }; static GLfloat yellow[] = { 0.8, 0.8, 0.2, 1.0 }; static GLfloat ground[][4] = { { 0.6, 0.6, 0.6, 1.0 }, { 0.3, 0.3, 0.3, 1.0 } }; int i, j; /* 赤い箱 */ glPushMatrix(); glTranslated(0.0, 0.0, -3.0); glMaterialfv(GL_FRONT, GL_DIFFUSE, red); glutSolidCube(1.0); glPopMatrix(); /* 緑の箱 */ glPushMatrix(); glTranslated(0.0, 0.0, 3.0); glMaterialfv(GL_FRONT, GL_DIFFUSE, green); glutSolidCube(1.0); glPopMatrix(); /* 青い箱 */ glPushMatrix(); glTranslated(-3.0, 0.0, 0.0); glMaterialfv(GL_FRONT, GL_DIFFUSE, blue); glutSolidCube(1.0); glPopMatrix(); /* 黄色い箱 */ glPushMatrix(); glTranslated(3.0, 0.0, 0.0); glMaterialfv(GL_FRONT, GL_DIFFUSE, yellow); glutSolidCube(1.0); glPopMatrix(); /* 地面 */ glBegin(GL_QUADS); glNormal3d(0.0, 1.0, 0.0); for (j = -5; j < 5; ++j) { for (i = -5; i < 5; ++i) { glMaterialfv(GL_FRONT, GL_DIFFUSE, ground[(i + j) & 1]); glVertex3d((GLdouble)i, -0.5, (GLdouble)j); glVertex3d((GLdouble)i, -0.5, (GLdouble)(j + 1)); glVertex3d((GLdouble)(i + 1), -0.5, (GLdouble)(j + 1)); glVertex3d((GLdouble)(i + 1), -0.5, (GLdouble)j); } } glEnd(); } void display(void) { static GLfloat lightpos[] = { 3.0, 4.0, 5.0, 1.0 }; /* 光源の位置 */ static double ex = 0.0, ez = 0.0; /* 視点の位置 */ static double r = 0.0; /* 視点の向き */ /* 画面クリア */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* モデルビュー変換行列の初期化 */ glLoadIdentity(); /* 視点の移動 */ glRotated(r, 0.0, 1.0, 0.0); glTranslated(ex, 0.0, ez); /* 光源の位置を設定 */ glLightfv(GL_LIGHT0, GL_POSITION, lightpos); /* シーンの描画 */ scene(); glFlush(); } void resize(int w, int h) { /* ウィンドウ全体をビューポートにする */ glViewport(0, 0, w, h); /* 透視変換行列の指定 */ glMatrixMode(GL_PROJECTION); /* 透視変換行列の初期化 */ glLoadIdentity(); gluPerspective(30.0, (double)w / (double)h, 1.0, 100.0); /* モデルビュー変換行列の指定 */ glMatrixMode(GL_MODELVIEW); } void keyboard(unsigned char key, int x, int y) { /* ESC か q をタイプしたら終了 */ if (key == '\033' || key == 'q') { exit(0); } } void init(void) { /* 初期設定 */ glClearColor(1.0, 1.0, 1.0, 0.0); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH); glutCreateWindow(argv[0]); glutDisplayFunc(display); glutReshapeFunc(resize); glutKeyboardFunc(keyboard); init(); glutMainLoop(); return 0; }
この視点を,例えば車を運転するように, マウスのドラッグに従って自由に移動できるようにしてください. どういう移動の仕方をするかは自分で考えて下さい. うまい方法が思い付かなければ,以下の方式を参考にして下さい.
例えば,マウスカーソルがウィンドウの中心にある時に静止するとして, そこからマウスを前(マウスカーソルは上)に動かせば前進,後ろ(マウスカーソルは下)に動かせば後退, 右に動かせば右旋回,左に動かせば左旋回するようにします.中心から離れるにつれて速く動くようになるようにしましょう.
上のプログラムでは,視点を移動するかわりに 物体の方を逆方向に動かすことを前提にしています.このため ex, ez および r の値は, 進行方向とは逆に設定する必要がありますので,注意してください.
scene() の図形は自分なりに色々変えてみてください. ただし,あまり複雑なものを描くと表示が遅くなります.部品には glutSolidCube() のほか,glutSolidSphere(), glutSolidCone(), glutSolidDodecahedron(), glutSolidOctahedron(), glutSolidIcosahedron(), glutSolidTetrahedron(), glutSolidTorus(), それに glutSolidTeapot() などが用意されています.詳しくはオンラインマニュアル等を参照してください.
glutSolidTetrahedron() などはサイズを指定することができませんから, これらの大きさを変えたいときは glScaled() を使ってください(サイズが指定できる glSolidCube() などをこれで拡大縮小すると,法線ベクトルがずれて陰影付けがおかしくなります)
なお,これはあくまで「一例」に過ぎません. 自分の思う方法で歩き回り方を考えてくれれば結構です.ただし, ちゃんと物体の背後に「回り込む」ことができるようにして下さい.