OpenGL - 从DisplayList转换为使用VBO

时间:2014-10-04 04:31:49

标签: c++ opengl vbo displaylist

我有以下全局变量:

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.

我想使用VBO而不是DisplayList。我该如何转换此代码?提前谢谢。

1 个答案:

答案 0 :(得分: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);

为数据分配空间,将顶点数据复制到缓冲区中。由于您的顶点元素索引数组移动了一个,我们更多地分配一个顶点并使用偏移量将数据复制到其中(我们也可以使用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);

元素数组缓冲区相同;你&#34;堆积&#34;相互之间的两个向量......顺便说一句,效率不高。让我们展开这个。首先再为缓冲区分配内存,但不要将数据复制到其中。由于每个子向量可能具有不同的长度(尽管如果用于特定的基本绘制模式,它们应该具有相同的大小)首先确定元素的总数(使用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 (which actually may invoke UB for anything other than 0)偏移量传递给数据参数:

void draw_vbo()
{
    glEnableClientState(GL_VERTEX_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
    glVertexPointer(3, GL_FLOAT, 0, (void*)0);

一旦VBO被联系起来&#34;进入顶点数组访问,我们可以解除绑定。数据仍将从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);
}