【问题标题】:OpenGL - Convert from DisplayList to use VBOOpenGL - 从 DisplayList 转换为使用 VBO
【发布时间】:2014-10-04 04:31:48
【问题描述】:

我有以下全局变量:

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。我该如何转换此代码?提前致谢。

【问题讨论】:

    标签: c++ opengl vbo displaylist


    【解决方案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);
    

    元素数组缓冲区也一样;您将两个向量“堆叠”在一起……顺便说一句,这不是很有效。让我们展开这个。首先再次为 tha 缓冲区分配内存,但不要将数据复制到其中。由于每个子向量可能有不同的长度(尽管如果用于特定的图元绘制模式,它们应该都是相同的大小)首先确定元素的总数(使用 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 的核心功能,只有 OpenGL-3 (在此之前它作为扩展可用很长时间)。所以它是glVertexAttribPointer 加上一个匹配的着色器。为了使过渡尽可能小,让我们回收您对glVertexPointer 的使用。主要区别在于,我们在调用 glVertexPointer 之前绑定了 VBO,并将 integer-cast-to-a-pointer (which actually may invoke UB for anything other than 0) 偏移量传递给 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);
    

    最后进行draw call。请记住,我们在将顶点数据复制到 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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多