前回はDirectXでいうところのDrawPrimitiveUP()と同じ描画方法をやりましたが、今回は頂点バッファとインデックスバッファを使用した場合の描画方法をやります。
OpenGLにはディスプレイリストが存在するのですが(2.0でもあるかどうかは知らない)、GLES2.0には存在しません。
頂点バッファもインデックスバッファも作成方法はほぼ同じです。データの種類と、一部の関数での引数が違うだけです。
では、まず頂点バッファの作成方法から見ていきます。
glGenBuffers( 1, &g_hVbo ); |
まずはバッファを作成します。複数のバッファを作成することも可能で、DirectXのストリームのように複数のバッファを設定してもかまいません。
次にこのバッファに頂点情報を書き込みます。
glBindBuffer( GL_ARRAY_BUFFER, g_hVbo );
glBufferData( GL_ARRAY_BUFFER, size, pData, GL_STATIC_DRAW ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); |
まず、作成したバッファをバインドします。これが1行目です。
2行目で情報を書き込みます。ターゲット、データサイズ、データの先頭アドレス、usage となります。
usage は通常、GL_STATIC_DRAW を選択します。これは基本的に変更しないデータを書き込む場合の設定です。
GL_DYNAMIC_DRAW を選択するのはデータを頻繁に変更する場合です。多分、速度は遅くなるけど、アクセスがしやすいような状態になっているんではないかと思います。
3行目でバッファのバインドを解除しています。OpenGLではバインドは引数に 0 を渡すとデフォルト設定に戻ります。DirectXもテクスチャやシェーダはそんな感じですね。
GL_ARRAY_BUFFER は頂点バッファのターゲットです。
このターゲットを GL_ELEMENT_ARRAY_BUFFER に変更するとインデックスバッファを指定したことになります。
実際の描画は以下のように行います。
glBindBuffer( GL_ARRAY_BUFFER, g_hVbo );
// ここで頂点とシェーダプログラム内の属性をバインド glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, g_hIbo ); |
頂点バッファを設定した後に頂点属性のバインドを行います。
頂点属性のバインドは前回やった glVertexAttribPointer() のことです。
これらの設定は必ず頂点バッファの設定後に行う必要があります。
また、全く同じ頂点属性を持つ複数の頂点バッファを入れ替える場合も、頂点バッファのバインド後に属性のバインドを行う必要があります。
DirectXではVertexDeclarationが同じなら設定し直す必要はないのですが、OpenGLではやらないと駄目っぽいです。
どうも、頂点バッファの実体に対してバインドしているようなのです。
つまり、glBindBuffer() は属性をバインドするターゲットはこのオブジェクトですよ、と教えてやるだけのものなんじゃないかと思います。
その後、ターゲットを変更してインデックスバッファも設定します。もちろん、インデックスバッファを使用しないなら設定の必要はありません。
OpenGLはDirectXのようにバッファを使用する描画関数と使用しない描画関数が分かれていません。
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL ); |
インデックスを使用する場合、glDrawElements() 関数の第4引数で指定していましたが、インデックスバッファを使用する場合は NULL を指定します。
インデックスバッファを使用しているのに NULL を使用しないと描画がおかしくなるので注意してください。
また、DirectXと異なり、頂点バッファは使うけどインデックスバッファは使わずにインデックス配列を使って描画、とかも可能です。もちろん、その逆もOKです。
この辺の設定とかは頂点バッファやインデックスバッファをクラス化しておくといろいろ楽できるでしょう。