Vertex Buffer Object(VBO)について VBOとは†OpenGL - Vertex arrayはOpenGLのAPIの呼び出しを減らすことで, パフォーマンスを大きく改善することができるものの, 頂点データは描画呼び出し毎にクライアント側のメモリからサーバ(GPU)側のメモリ(ビデオカードのメモリ)に転送されるという問題もあります. 一方,GPU側で完全に格納されたデータで呼び出しのたびに実行されるものとしてディスプレイリストがあります. ディスプレイリストではAPI呼び出しのオーバーヘッドをなくすことで高速な描画を可能としています. しかし,ディスプレイリストは一度コンパイルされれば,ディスプレイリスト内のデータを変更することはできません. これらの問題を解決するのが Vertex Buffer Object(VBO) です. VBOは頂点データを格納するGPU側のメモリに置かれたバッファです. クライアント側のメモリ上の配列と同じように扱え, glVertexPointerなどに直接渡すことができます. また,ディスプレイリストと違い,クライアント側のメモリスペースにバッファをマッピングすれば, クライアントからの読込みや変更が可能となります. VBO作成手順†VBOの作成にはGL拡張をいくつか使います. GLEWなどをインクルード,リンクするようにしてください(参照:GLEWについて). VBOの作成はテクスチャを作成するのと同じような手順です.
他に範囲データ転送やVBO破棄命令などがある.
VBOを使った描画例†まず,VBOを作成します. // VBO作成 vector<Vec3> vertices;// = { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0 }; vertices.push_back(Vec3(0, 0, 0)); vertices.push_back(Vec3(1, 0, 0)); vertices.push_back(Vec3(1, 1, 0)); vertices.push_back(Vec3(0, 1, 0)); vector<int> indices;// = { 0, 1, 2, 0, 2, 3 }; indices.push_back(0); indices.push_back(1); indices.push_back(2); indices.push_back(0); indices.push_back(2); indices.push_back(3); glGenBuffers(1, &vrtVBO); glBindBuffer(GL_ARRAY_BUFFER, vrtVBO); glBufferData(GL_ARRAY_BUFFER, vertices.size()*3*sizeof(double), (GLdouble*)&vertices[0], GL_STATIC_DRAW); glGenBuffers(1, &idxVBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxVBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(int), &indices[0], GL_STATIC_DRAW); この処理は頂点,インデックスデータが変わらなければ1回だけでいいです. 次に描画時には, glBindBuffer(GL_ARRAY_BUFFER, vrtVBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxVBO); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_DOUBLE, 0, 0); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glDisableClientState(GL_VERTEX_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBufferでVBOをバインドして,あとはVertex arrayと同じですが, データの場所のポインタには0を指定します(オフセット値0ということ). 使い終わったら削除します. glDeleteBuffers(1, &vrtVBO); glDeleteBuffers(1, &idxVBO); VBOデータの変更†VBOはクライアント側のメモリスペースにバッファをマッピングすれば,データの修正が可能となります. データの修正は以下の手順で行います.
データの修正の例は以下. void ModifyVBO(void) { glBindBuffer(GL_ARRAY_BUFFER, vrtVBO); double *ptr = (double*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); static double ang = 0.0; if(ptr){ for(int i = 1; i <= 2; ++i){ ptr[3*i] = cos(RX_TO_RADIANS(ang)); ptr[3*i+2] = sin(RX_TO_RADIANS(ang)); } glUnmapBuffer(GL_ARRAY_BUFFER); ang = (ang < 360) ? ang+1 : 0.0; } glBindBuffer(GL_ARRAY_BUFFER, 0); } † |