おもちゃラボ

Unityで遊びを作ってます

OpenGLでゲームを作る 円を描画する

OpenGLで円を描画する

今回は、円を画面上に描画してみたいと思います。前回、OpenGLでゲームを作る 図形の描画 - おもちゃラボで様々な図形を描画しましたが、なんで円だけ別ページなんだ!と突っ込まれそうですが、円だけが特別なわけではなく、三角形が特別(というより基本図形)で、その他の図形は全て三角形から構成するのです。例えば円も、五角形も四角錐もゲーム中のキャラクタも、ぜーーーんぶ三角形が基本となって構成されています。

円を三角形で表現する

円も三角形から構成されると書きましたが、普通に考えると三角形で円を作れそうにありません。。。ただ、そこにはすごいトリックが!!なんてことはなく、ただ単にピザを切るみたいに円を細かく細かく分割していくと、なんとなく三角形だけで円が作れそうじゃぁないですか。これが三角形で円を作る方法なのです。これを応用すると、球も曲面もポリゴンも、細かく分割すると三角形で作れちゃうというわけです。

f:id:nn_hokuson:20140126090231j:plain

下に書いたプログラムが、円を描画するためのプログラムになります。変更点としてはmain文にglfwOpenWindowHintの関数が追加されている部分と、render関数の中が円を描画するプログラムになっている部分です。

#include <GL/glfw.h>
#include <cstdlib>
#include <cmath>

const int g_windowWidth  = 640;
const int g_windowHeight = 480;

void render()
{
    const int radius = 100;

    GLfloat vtx[32*2];
    for(int i = 0; i < 32; ++i){
        GLfloat angle = static_cast<GLfloat>((M_PI*2.0*i)/32);
        vtx[i*2]   = radius * std::sin(angle) + g_windowWidth/2;
        vtx[i*2+1] = radius * std::cos(angle) + g_windowHeight/2;
    }
    glVertexPointer(2, GL_FLOAT, 0, vtx);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    
    glEnable(GL_MULTISAMPLE);
    glMatrixMode(GL_MODELVIEW);
    glEnableClientState(GL_VERTEX_ARRAY);
    glPushMatrix();
    glDrawArrays(GL_TRIANGLE_FAN, 0, 32);
    glPopMatrix();
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisable(GL_MULTISAMPLE);
}

int main()
{
    if( !glfwInit() ){
        return -1;
    }
    
    // マルチサンプリング
    glfwOpenWindowHint(GLFW_FSAA_SAMPLES,4);
    if( !glfwOpenWindow(g_windowWidth, g_windowHeight, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) {
        return -1;
    }
    
    // モニタとの同期
    glfwSwapInterval(1);
    
    // 描画範囲の指定
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0f, g_windowWidth, 0.0f, g_windowHeight, -1.0f, 1.0f);
    
    // ゲームループ
    while (glfwGetWindowParam(GLFW_OPENED)) {

        // 画面の初期化
        glClearColor(0.2f, 0.2f, 0.2f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        
        render();
        
        // バッファの入れ替え
        glfwSwapBuffers();
    }
    
    glfwTerminate();
    
    return 0;
}

まずはrender()の中身から説明していきたいと思います。まず最初に三角形や四角形と同様に、頂点配列を生成していきます。今回は半径100pxの円を32当等分して描画したいと思います。円周上の頂点は媒介変数表示で表すと、

x = r*cosθ
y = r*sinθ

で表せますね。ここで、rは円の半径、θは円周上の角度です。これらの頂点座標を配列に詰めた後、glDrawArraysで一気に32個の三角形を描画します。glDrawArraysに渡す第一引数は、これまでGL_TRIANGLESを指定していましたが、今回はGL_TRIANGLE_FANを指定しています。この違いは頂点配列に入っている頂点座標をどのように使って三角形を描画していくかの違いによるものです。

下図のようにGL_TRIANGLESの場合には配列中の頂点を順番に3個ずつ使用して三角形を描画していきます。それに対して、GL_TRIANGLE_FANでは頂点配列の1つ目の座標を中心として2つ目以降の座標を利用しながら三角形を描画していきます。3つ目のGL_TRIANGLE_STRIPでは前の三角形の2つの頂点を利用する形で次の三角形を描画します。

f:id:nn_hokuson:20140126092448j:plain

さて、ここまで三角形を組み合わせて円を描画する方法を説明してきましたが、GL_TRIANGLE_STRIPとか頂点配列とか、ゲームを作るために必要なのかと言われれば、暫くの間は不要かもしれません。2Dゲームを作る場合、キャラクタや敵、弾などのオブジェクトは通常、画像としてOpenGLに読み込み、四角形のポリゴンに貼り付けるだけなので(これをスプライトといいます)わざわざ自分で三角形を組み合わせて絵を書くことは少ないからです。

じゃぁなんで、こんな難しい知識が必要になるんだよ!と思うかもしれません。確かにすぐには必要にならないかもしれませんが、テクスチャに使用する画像を置くメモリをケチりたい(もしくは余裕が無い)などの場合には手で描画するしかありませんし、今後3Dゲームを作ろうと考えているのなら必要な知識になります。なので、知っていると役に立つこともあると思い、今回説明した次第ですー

アンチエイリアス

今回は、最後にアンチエイリアス( anti aliasing )の処理について説明したいと思います。アンチエイリアスはギザギザの画像を綺麗に見せるための技術です。下図のように滑らかに見える画像も拡大してみると結構ギザギザしていて美しくないことがあります。そこで、アンチエイリアスを使ってギザギザの部分をいい感じに透明化してやることで、なめらか〜に見せようという技術なのです。

f:id:nn_hokuson:20140126085135j:plain

では、OpenGLではどのようにして有効にするのかというと、GL_POLYGON_SMOOTHというものがあるのですが、なぜかこれが上手くいかない。上手くいかないのでglfwの機能を利用して、glfwOpenWindowHintの引数にGLFW_FSAA_SAMPLESを渡してやり、マルチサンプリングという技術をつかうことでアンチエイリアスを有効にしています。

ということで、glfwでアンチエイリアスを使いたい場合には glfwOpenWindowを呼ぶ前にglfwOpenWindowHintを使用してglfwにアンチエイリアスを使用することを伝えます。次に描画する際にglEnable(GL_MULTISAMPLE);を使用して実際にglfwにアンチエイリアスを有効にすることを伝え、その後、図形を描画することでアンチエイリアスがかかった画像が描画されるようになります。

まとめ

今回は、円を描画する方法とglfwでアンチエイリアスを有効にする方法を説明しました。円やその他の多角形は三角形をうまく組み合わせて描画しているのですが、2Dゲームではスプライトという概念があるため、すぐすぐ必要になることはないかもしれません。ただ、3Dゲームを作るときには必要になる知識なので今回説明しました。また、glfwでアンチエイリアスをどのようにして有効にするかを説明しました。

参考図書

「ゲームプログラマになる前に覚えておきたい技術」

この本は「ゲームをどのように作るのか」といった薄っぺらい内容ではなく、ゲームを動かすための技術を1から理解できるように解説してくれています。そして、この本にはゲーム開発にとどまらず、プログラマに必要な知識がたくさーん詰まっています。C++の基礎からキャッシュの話とか浮動小数点演算の話などのちょっと難しい話、最適化手法の話までもが書かれているので、プログラマならぜったい読むべき一冊ですね。そしてページ数も872ページとボリューミィ!分厚い参考書はいい本です!内部的に使われているのはDirectXですが、基本的にそれを意識する必要は内容に解説されているので、絶対に一度は読んでおきたい一冊です。


ゲームプログラマになる前に覚えておきたい技術
平山 尚(株式会社セガ)
秀和システム
売り上げランキング: 10284
 

「OpenGLで作るiPhone SDKゲームプログラミング」

この本はiPhoneでOpenGLを使う方法を解説した本です。2Dゲームの「はえたたき」から3Dゲームの「カーレース」まで、サンプルがとても充実しているので、ゲームを作りはじめようという時に非常に良い取っ掛かりになります!また、パーティクルや衝突判定などゲームには欠かせない話もしっかりと説明されている数少ない日本語の書籍なので、ぜひぜひ読んでおきたいですねー(^^)v

OpenGLで作るiPhone SDKゲームプログラミング
横江 宗太(株式会社パンカク)
インプレスジャパン
売り上げランキング: 28,461


「OpenGLプログラミングガイド 原著第5版」

OpenGLといったらまずはコレ。通称赤本と呼ばれるバイブルです。とりあえず、ちょこちょこと参照することが多いので、手元に置いておきたい(というか重すぎてモバイルは無理)一冊です。OpenGLをやるぞ、という意気込み(もしくは自分へのプレッシャ)で買ってしまう一冊です。コレを買ったら後戻りは出来ません。。。

 

OpenGLプログラミングガイド 原著第5版
OpenGL策定委員会
ピアソンエデュケーション
売り上げランキング: 475,144