0

次のグローバル変数があります。

vector<vector<unsigned int> > faces; 
vector<float> vertexCoords; 
unsigned int modelList;

私の初期化には、次のコードがあります。

glEnableClientState(GL_VERTEX_ARRAY);   // vertex array
glVertexPointer(3, GL_FLOAT, 0, &vertexCoords[0]);

modelList = glGenLists(1);  // generate display list
glNewList(modelList, GL_COMPILE); 
for (unsigned int i = 0; i < faces.size(); i++) {
    glBegin(GL_TRIANGLE_STRIP); 
    for (vector<unsigned int>::iterator it = faces[i].begin();
            it != faces[i].end(); it++)
        glArrayElement(*it - 1); 
    glEnd();
}
glEndList(); // End display list.

私の glutDisplayFunc では、次のように呼び出します。

glCallList(modelList); // Execute display list.

DisplayList の代わりに、VBO を使用したいと思います。このコードを変換するにはどうすればよいですか? 前もって感謝します。

4

1 に答える 1

1

あなたは運がいいです。プログラムの構造には、すでにすべてが整っています。煩わしい 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);
}
于 2014-10-04T10:09:49.373 に答える