厚みゼロの世界
OpenGLで作るiPhone SDKゲームプログラミング - 6章
レースゲーム(3D)
そもそも6章自体30ページ程しかないわけだが。
6-3までは3Dの基本的な説明と、今までの2Dゲームの見た目を3Dっぽくするところまで実践しました。
6-1 3Dの基礎
・正射影 glOrthof関数を使う
・透視射影 glFrustumf関数を使う
glFrustumf(左のX座標, 右のX座標, 下のY座標, 上のY座標, 手前のZ座標, 奥のZ座標);
手前のZ座標は、原点(0, 0, 0)から視界に入る最前面のZ座標を指定する。
奥のZ座標は、どこまで遠くが見えるかを指定する。
深度テストで物体の前後関係を処理する。
以下、導入方法。
// レンダラの属性にとっておく GLuint depthRenderbuffer; // レンダラの初期化時に深度バッッファを作成する(init) glGenRenderbuffersOES(1, &depthRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth,backingHeight); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer); // 深度バッファのサイズを変更する(resizeFromLayer) glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer); // レンダリング処理で深度バッファを有効にする(renderMain) glEnable(GL_DEPTH_TEST); // 描画処理 // アルファブレンディングするときは深度テストを無効にする。 glDisable(GL_DEPTH_TEST); // レンダラが描画をやめるとき解放(とりえあずdeallocでやっとく) if (depthRenderbuffer) { glDeleteRenderbuffersOES(1, &depthRenderbuffer); depthRenderbuffer = 0; }
6-2 見た目の3D化
OpenGLでの視点は原点(0, 0, 0)に固定されている。
従って、注視点のZ値はマイナスに固定されている。
視点や視野を設定するには、画面全体をマトリクス変換する。
2次元描画と3次元描画を併用するには、
・まず3Dオブジェクトを表示し、
・その後で座標系を再設定した上で2D描画を行う。
その他、書籍には詳しい解説がないので、言われるがままにコードを写しました。
おまじない的コードの部分は相変わらずノータッチなので、まったく分からない。
だんだん、「後はサンプルソース見ておいてね」ってスタンスになってきてます。
とにかく言われた通りに、主にrenderMainを修正すると・・・
ふむ。
これはこれはぺらっぺらな3Dですな。
ポイントは、パーズアイビューなるものを実現するために、画面全体をマトリクス変換するというところだったと思います。
//--少し引き気味の地点から見るために、奥方向に移動させる glTranslatef(0.0f, 0.0f, -1.0f); //--視点を少し上にするために、逆に全体を下方向に移動させる glTranslatef(0.0f, -0.2f, 0.0f); //--X軸を中心に全体を80°回転させる glRotatef(-80.0f, 1.0f, 0.0f, 0.0f);
6-3 3Dのポリゴン
今まで、
x, y, x, y, x, y, ...
という一次元配列を作成していたところを
x, y, z, x, y, z, ...
とするだけで、特に難しいことはないようです。
ここでやることは、
・コース全体を囲む四方に壁を作る
・タイヤバリアを八角柱にして新しいテクスチャを使って立体にする
壁はマトリクス変換で四方に設置します。
以下実装コードですが、
「マトリクス変換は直前の指定から順に適用される」という点に再度注意。
// 外壁を描画する for (int i = 0; 4 > i; ++ i) { glPushMatrix(); // Z軸回りに回転させて、四方を囲むようにする glRotatef(90.0f * i, 0.0f, 0.0f, 1.0f); // 壁をコースの上端まで移動させ、同時に半分埋まっている分、引き上げる glTranslatef(0.0f, 1.0f, 0.025f); // X軸を中心に回転させて、壁を立てる glRotatef(90.0f, 1.0f, 0.0f, 0.0f); _wall.Draw(_wallTexture.raw); glPopMatrix(); }
外壁があるだけでも、というか、Z方向を持つオブジェクトが1つあるだけでも、ちょっと3Dっぽくは見えてきますね。(ここではマトリクス変換を使って世界をX軸周りに-80°回転されているので、画面の上方向がZ正方向に見えます)
次に、タイヤバリアを八画柱で表現するということをしたのですが、タイヤバリアの頂点配列作成はかなりのごり押しでした。ガチCのコードを130行ほど・・・ここには掲載しないでおきます。しかも、この後にVBOで作り直しのタスクが控えていました。。。