おもちゃラボ

Unityで遊びを作ってます

【OpenGLでゲームを作る】三角形のポリゴンを表示する

ポリゴンを画面上に表示するためには、OpenGLのプログラムでポリゴンの各頂点座標(ローカル座標)を定義し、それをバーテックスシェーダに渡す必要がありました(前回の記事を参照)。

nn-hokuson.hatenablog.com

今回はOpenGLからシェーダに頂点情報を渡すして画面に三角形のポリゴンを表示するプログラムを見ていきましょう。

三角形を表示するプログラムを書く

次のプログラムは画面上に3角形を描画するプログラムです。必要な部分の解説はコメントに書いているので、あわせて読んでみてください。

#include <GLFW/glfw3.h>
#include <iostream>
#include <fstream>

using namespace std;

const int g_width  = 640;
const int g_height = 480;

GLuint crateShader()
{
    //バーテックスシェーダのコンパイル
    GLuint vShaderId = glCreateShader(GL_VERTEX_SHADER);
    string vertexShader = R"#(
                            attribute vec3 position;
                            void main(void){
                                gl_Position = vec4(position, 1.0);
                            }
                            )#";
    const char* vs = vertexShader.c_str();
    glShaderSource(vShaderId, 1, &vs, NULL);
    glCompileShader(vShaderId);
    
    //フラグメントシェーダのコンパイル
    GLuint fShaderId = glCreateShader(GL_FRAGMENT_SHADER);
    string fragmentShader = R"#(
                            void main(void){
                                gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
                            }
                            )#";
    const char* fs = fragmentShader.c_str();
    glShaderSource(fShaderId, 1, &fs, NULL);
    glCompileShader(fShaderId);
    
    //プログラムオブジェクトの作成
    GLuint programId = glCreateProgram();
    glAttachShader(programId,vShaderId);
    glAttachShader(programId,fShaderId);
    
    // リンク
    glLinkProgram(programId);
   
    glUseProgram(programId);
    
    return programId;
}

int main()
{
    if( !glfwInit() ){
        return -1;
    }
    
    GLFWwindow* window = glfwCreateWindow(g_width, g_height, "Simple", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }
    
    // モニタとの同期
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);
    
    GLuint programId = crateShader();
    
    // ゲームループ
    while (!glfwWindowShouldClose(window)) {
        
        // 画面の初期化
        glClearColor(0.2f, 0.2f, 0.2f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glClearDepth(1.0);
       
        // 頂点データ
        float vertex_position[] = {
           0.0, 0.5,
           0.4, -0.25,
           -0.4,-0.25,
        };
     
        // 何番目のattribute変数か
        int attLocation = glGetAttribLocation(programId, "position");
        
        // attribute属性を有効にする
        glEnableVertexAttribArray(attLocation);
        
        // OpenGLからシェーダに頂点情報を渡す
        glVertexAttribPointer(attLocation, 2, GL_FLOAT, false, 0, vertex_position);
        
        // モデルの描画
        glDrawArrays(GL_TRIANGLES, 0, 3);

        // バッファの入れ替え
        glfwSwapBuffers(window);
        
        glfwPollEvents();
    }
    
    glfwTerminate();
    
    return 0;
}


上のプログラムを実行すると次のように三角形が描画されます。
f:id:nn_hokuson:20170203234041p:plain
ようやく画面上にポリゴンを描くことができました・・・!ここまで長い道のりでしたね〜。次は、このプログラムの説明します。今回は(そして、これからもしばらく)crateShader関数の中身とシェーダの内容は変更しませんので、main関数の中身を説明していきます。

OpenGLで三角形を表示する方法

今回のプログラムでは、OpenGL側で三角形の頂点情報を定義して、それをバーテックスシェーダに渡しています。追加したプログラムを詳しくみていきましょう。

まずは、次のように頂点情報をfloat型の配列として定義しています。

// 頂点データ
float vertex_position[] = {
           0.0, 0.5, 0.0,
           0.4, -0.25, 0.0,
           -0.4,-0.25, 0.0
};

ここでは3つの頂点を定義していて、一つ目の頂点が(0.0, 0.5, 0.0)、二つ目が(0.4, -0.25, 0.0)、三つ目が(-0.4, -0.25, 0.0)です。OpenGLではウインドウの中央が(0, 0)上下左右は±1の大きさであることに注意しましょう。
f:id:nn_hokuson:20170204001444p:plain

頂点データを渡すattribute変数を決める

頂点座標の定義に続けて、バーテックスシェーダに頂点情報を渡すのですが、頂点データ渡す前にバーテックスシェーダで定義されている変数のうち、上から何番めのattribute変数に値を渡すのかを指定する必要があります。

// 何番目のattribute変数か
int attLocation = glGetAttribLocation(programId, "position");    

「 指定したattribute変数がバーテックスシェーダで上から何番目に定義されているか」はglGetAttribLocationを使って調べます。第二引数に調べたいattribute変数名を渡すと、上から何番目のattribute変数かを返してくれます。

OpenGLからのデータを受け取れる設定にする

シェーダに頂点情報を渡す前に、受け取り側のattribute変数をデータを受け取れる状態にしておく必要があります。そのために、glEnableVertexAttribArray関数を使っています。引数には、何番目のattribute変数を「受け取れる状態にするか」を指定します。

// attribute属性を有効にする
glEnableVertexAttribArray(attLocation);

 

ポリゴンを描画する

これで、頂点情報の受け渡し可能な状態になったので、glVertexAttribPointer関数を使って頂点情報をシェーダに渡しています。第一引数にはattribute変数の位置番号、第二引数にはattribute変数の要素数(今回は2Dなので2)を渡しています。

// OpenGLからシェーダに頂点情報を渡す
glVertexAttribPointer(attLocation, 2, GL_FLOAT, false, 0, vertex_position);

まとめ

今回はようやくポリゴンが表示できました。ただ、プログラムも複雑になってきましたね。でも、やっていることは「OpenGLで定義した頂点データをシェーダに渡して描画している」だけです。これからもこのプログラムがベースになるのでしっかりと理解しておきましょう。