ウォークスルーは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() などをこれで拡大縮小すると,法線ベクトルがずれて陰影付けがおかしくなります)
なお,これはあくまで「一例」に過ぎません. 自分の思う方法で歩き回り方を考えてくれれば結構です.ただし, ちゃんと物体の背後に「回り込む」ことができるようにして下さい.