2014-10-04 25 views
0

我有以下全局变量:OpenGL的 - 从显示列表转换为使用VBO

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。我怎样才能转换此代码?提前致谢。

回答

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); 

对于元素数组缓冲区也是一样的;你将两个向量“堆栈”在一起......这种方法效率不高,让我们展开这个,首先为缓冲区分配内存,但不要复制数据,因为每个子向量可能具有不同的长度(尽管如果用于特定的原始绘制模式,它们应该都是相同的大小)首先确定元素的总数(使用C++ 11功能auto来保存一些输入并且我们可以使用迭代器);稍后我们需要知道这个num BER吸引他们:

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,我们必须拥有一个),但我们要保证这一点。绘制VBOs与从客户端顶点数组绘制非常相似。现在您使用了glVertexPointer这表明您正在使用固定功能流水线。我们可以使用它。但是,然后,维也纳组织成为OpenGL核心功能,只有OpenGL-3(在此之前它已经作为一个扩展可用很长时间)。所以它是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已经“链接”到一个顶点数组访问,我们可以解除绑定。数据仍将从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); 
}