あなたは運がいいです。プログラムの構造には、すでにすべてが整っています。煩わしい 1 から始まるインデックス作成を回避することもできます。
最初に VBO を作成します。
GLuint vbo_id;
GLuint eabo_id; /* EIB = Element Array Buffer */
size_t eabo_n_elements;
void make_vbo()
{
GLuint genbuf_ids;
glGenBuffers(2, genbuf_ids);
vbo_id = genbuf_ids[0];
eabo_id = genbuf_ids[1];
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
データにスペースを割り当て、頂点データをバッファにコピーします。頂点要素のインデックス配列が 1 つシフトされているため、頂点を 1 つ多く割り当て、データをオフセット付きでそこにコピーします (GL_ARB_draw_elements_base_vertex
拡張機能を使用することもできますが、次のように表示したいと思います:
glBufferData(
GL_ARRAY_BUFFER,
(vertexCoords.size() + 3)*sizeof(vertexCoords[0]),
NULL,
GL_STATIC_DRAW );
glBufferSubData(
GL_ARRAY_BUFFER,
sizeof(vertexCoords[0])*3, /* offset by 1 vertex */
(vertexCoords.size())*sizeof(vertexCoords[0],
&vertexCoords[0]);
glBindBuffer(GL_ARRAY_BUFFER, 0);
要素配列バッファについても同じです。2 つのベクトルを互いに「積み重ね」ましたが、これはあまり効率的ではありません。これを広げてみましょう。最初にもう一度バッファにメモリを割り当てますが、データをそこにコピーしないでください。各サブベクトルの長さは異なる場合があるため (ただし、特定のプリミティブ描画モードで使用する場合はすべて同じサイズにする必要があります)、最初に要素の総数を決定します (C++11 機能を使用してauto
入力を節約し、イテレータを使用します); また、後でそれらを描画するためにその数を知る必要があります。
eabo_n_elements = 0;
for(auto i = faces.begin(); i != faces.end(); i++) {
eabo_n_elements += i.size();
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eabo_id);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
sizeof(faces[0][0]) * eabo_n_elements,
NULL,
GL_STATIC_DRAW );
顔データをEABにアンロールコピー
size_t offset = 0;
for(auto i = faces.begin(); i != faces.end(); i++) {
size_t const len = i.size() * sizeof(i[0]);
glBufferSubData(
GL_ELEMENT_ARRAY_BUFFER,
offset,
len,
&i[0] );
offset += len;
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
これでそれを描くことができます。技術的には、VAO を使用できます (OpenGL-4 では使用する必要があります) が、安全に使用しましょう。VBO の描画は、クライアント側の頂点配列からの描画に非常に似ています。これglVertexPointer
で、固定関数パイプラインを使用していることを示します。それを使うことができます。しかしその後、VBO は OpenGL-3 でのみ OpenGL のコア機能になりました (それ以前は、拡張機能として長い間利用可能でした)。そのためglVertexAttribPointer
、代わりにそれに対応するシェーダーが追加されます。移行をできるだけ小さくするために、 の使用をリサイクルしましょうglVertexPointer
。主な違いは、glVertexPointer
呼び出しを行う前に VBO をバインドし、 integer-cast-to-a-pointer (実際には 0 以外の UB を呼び出す可能性がある)オフセットを data パラメーターに渡すことです。
void draw_vbo()
{
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
glVertexPointer(3, GL_FLOAT, 0, (void*)0);
VBO が頂点配列アクセスに「リンク」されると、バインドを解除できます。データは引き続き VBO からフェッチされます。
glBindBuffer(GL_ARRAY_BUFFER, 0);
そして最後にドローコールを行います。頂点データを VBO にコピーするときに 1 要素オフセットを適用したことを思い出してください。したがって、面の頂点要素のインデックスを通過するだけです。VBO と同じパターン: バインドし、整数オフセットをポインターにキャストし、それを glDrawElements に渡します。
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eabo_id);
glDrawElements(GL_TRIANGLE_STRIP, eabo_n_elements, GL_UNSIGNED_INT, (void*)0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}