ポリゴンが表示できたら、それをまわして見ましょう。
まぁ、いつものように適当にファイルが入っています。
main.cpp | これだけ。 |
あと、実行ファイル及び、プロジェクトファイルが入っています。
今回は、前回のプログラムを拡張して、3次元ポリゴンの表示を行います。
メイン関数も少し拡張しています。
main.cpp 0079: // --------------------------------------------------------------------------- 0080: // メイン関数 0081: // --------------------------------------------------------------------------- 0082: int main(int argc, char *argv[]) 0083: { 0084: // ウィンドウの作成 0085: glutInitWindowPosition(100, 100); // 表示位置 0086: glutInitWindowSize(512, 512); // サイズ 0087: glutInit(&argc, argv); // GLの初期化 0088: glutInitDisplayMode(GLUT_DOUBLE // 描画モード 0089: | GLUT_RGBA // wバッファ+RGBA+深度バッファ 0090: | GLUT_DEPTH); 0091: glutCreateWindow(argv[0]); // ウィンドウの生成 0092: 0093: // コールバック関数の設定 0094: glutDisplayFunc(display); // 描画関数 0095: glutReshapeFunc(resize); // 画面が変形したとき 0096: glutIdleFunc(idle); // ひまなとき 0097: 0098: // 一度だけすればいい設定 0099: glClearColor(0.0, 0.0, 0.3, 0.0); // 背景色の設定 0100: glEnable(GL_DEPTH_TEST); // 深度バッファの使用 0101: 0102: glutMainLoop(); // メインループ 0103: 0104: return 0; 0105: }
3次元で表示するためには、深度バッファを使います
(今回は1枚板だけなので、実は深度バッファは要らないのですが・・・)。
このためには、ディスプレイモードの設定 glutInitDisplayMode に、GLUT_DEPTH を追加します。
また、glEnable(GL_DEPTH_TEST) で、深度テストを有効にします。
その他に、画面がちらつかないように、ディスプレイモードにGLUT_DOUBLEを設定して、2重バッファを使います。
あと、ウィンドウの大きさや、表示位置も指定しました。
コールバックを追加しました。
一通り、処理が終わって、ひまになった時のアイドリング状態のときの関数の設定、glutIdleFunc() と、
リサイズのイベントが発生したときの、glutReshapeFunc()です。
リサイズのイベントが発生したときの関数は、resizeです。
このとき、ビューポートと、射影行列を設定します。
main.cpp 0053: // --------------------------------------------------------------------------- 0054: // 画面がリサイズされたとき 0055: // --------------------------------------------------------------------------- 0056: void resize(int w, int h) 0057: { 0058: // ビューポートの設定 0059: glViewport(0, 0, w, h); 0060: 0061: // 射影行列の設定 0062: glMatrixMode(GL_PROJECTION); 0063: glLoadIdentity(); 0064: gluPerspective( 60.0, // 画角 0065: 1.0, // アスペクト比 0066: 1.0, 100.0); // 前方面、後方面 0067: }
ビューポートは、表示領域の左上の座標と、大きさを指定します。
関数の引数にサイズが渡されるので、そのまま幅と高さに使いましょう。
射影行列は、glMatrixMode(GL_PROJECTION) で、
射影行列を設定することを宣言してから、行列を作成します。
gluPerspective という、射影行列を作成するそのままの関数があるので、それを使います。
設定内容は、DirectXと同じですね。
アイドリング中の処理を見ましょう。
今回は、ポリゴンを回すので、回転角度の変数を変化して、
glutPostRedisplay() で再描画のリクエストをします。
main.cpp 0012: // --------------------------------------------------------------------------- 0013: // オブジェクト 0014: // --------------------------------------------------------------------------- 0015: static float r = 0.0f; // ポリゴンの回転角 0016: 0068: // --------------------------------------------------------------------------- 0069: // ひまなときに実行される 0070: // --------------------------------------------------------------------------- 0071: void idle() 0072: { 0073: // ポリゴンの回転 0074: r = r + 3.0f; 0075: while (360.0f < r) r -= 360.0f; 0076: 0077: glutPostRedisplay(); // 再描画リクエスト 0078: }
それでは、描画関数を見ましょう。
画面をクリアするときに、深度バッファもクリアします。
main.cpp 0017: // --------------------------------------------------------------------------- 0018: // 画面描画 0019: // --------------------------------------------------------------------------- 0020: void display(void) 0021: { 0022: // 画面のクリア 0023: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 0024: 0025: // ビュー行列の設定 0026: glMatrixMode(GL_MODELVIEW); 0027: glLoadIdentity(); 0028: gluLookAt( 0.0, 0.0, 3.0, // 視点 0029: 0.0, 0.0, 0.0, // 注目点 0030: 0.0, 1.0, 0.0); // 上方向 0031: 0032: // ----------------------------------------------------------------------- 0033: // ポリゴン描画 0034: 0035: glPushMatrix(); // ビュー行列が他のポリゴンでも使えるよう退避 0036: // rot x y z 0037: glRotated(r, 0.0, 1.0, 0.0); // ポリゴンの回転角を設定 0038: // ポリゴン描画 0039: glBegin(GL_TRIANGLE_STRIP); // ストリップ設定 0040: glColor3d(1.0, 0.0, 0.0); // 赤 0041: glVertex3d(-0.9, +0.9, 0.0); 0042: glColor3d(0.0, 1.0, 0.0); // 青 0043: glVertex3d(+0.9, +0.9, 0.0); 0044: glColor3d(0.0, 0.0, 1.0); // 緑 0045: glVertex3d(-0.9, -0.9, 0.0); 0046: glColor3d(1.0, 1.0, 1.0); // 白 0047: glVertex3d(+0.9, -0.9, 0.0); 0048: glEnd(); // ポリゴンの描画終了 0049: glPopMatrix(); // ビュー行列に現在の行列を戻す 0050: 0051: glutSwapBuffers(); // 画面の更新の終了 0052: }
モデル座標系から、カメラ座標系への変換行列は、1つになっています。
glMatrixMode(GL_MODELVIEW) で、ビュー行列を設定する宣言をしてから、行列を設定します。
ビュー行列は、gluLookAt で作成します。
あとは、ワールド行列をビュー行列にかけて、変換行列を作成します。
変換行列の作成には、Matrix stack を使います(DirectXでも、ID3DXMatrixStackってやつがありますね)。
Matrix stack は、行列を積み重ねることによって、行列計算の複数の実行を意識することなく行います。
ビュー行列を作成したあとに、glRotated 等で、各ポリゴンのワールド行列を作成します。
描画するときは、その時点までの行列計算が順次行われます。
このとき、glRotated だけでなく、glTranslated を書けば、平行移動が行えます。
注意することは、最後に設定した行列計算から実行されるということです。
よくある、普通の描画方法では、
ビュー行列 gluLookAt 平行移動 glTranslated 回転 glRotated スケーリング glScaled
の順で行列を設定する必要があります。
さらに、Matrix stack の大きな特徴として、行列を使いまわすことができます。
その時点までに設定された行列を glPushMatrix() で、退避します。
使い終わったら、glPopMatrix() で、退避した行列を元に戻せます。
今回は、ポリゴンが1つしか使わないですが、複数のオブジェクトを表示するときでも、
glPushMatrix でビュー行列を退避しておけば、ビュー行列を何度も設定しなくてもよくなります。
それ以外は、2Dの時とほとんど変わりません。glColor3dで3次元座標を設定するぐらいです。
最後の画面の更新でダブルバッファを切り替えます。 具体的には、glutSwapBuffers で、切り替えます。
これで、基本的な3D描画ができるようになりました。
あとは、応用して、いろいろなものを描画しましょう。