如何在OpenGL中使用顶点数组的顶点缓冲区对象?

时间:2012-12-21 13:07:27

标签: qt opengl

我使用Vertex Array快速绘制了很多三角形:

void initializeGL() { 
   ...
   glEnableClientState(GL_VERTEX_ARRAY);
   glEnableClientState(GL_COLOR_ARRAY);
   glVertexPointer(3, GL_FLOAT, 0, vertices);
   glColorPointer(3,  GL_FLOAT, 0,   colors);
}

void paintGL() {
   ...  
   glDrawElements(GL_TRIANGLES, 3*numTriangles, GL_UNSIGNED_INT, indices);
 }

但是我想通过使用顶点缓冲对象(VBO)来使渲染速度更快。

我是否理解glVertexPointer()告诉GPU它在CPU中哪里可以获取顶点数据然后GPU从每个paintGL()的CPU中的这个位置复制它?

使用VBO可以通过将顶点数据仅写入GPU一次来改善这一点吗?

我正在使用Qt我尝试使用QGLBuffer类:

void GLWidget::initializeGL() {
   ... 
   vertexBuffer = new QGLBuffer(QGLBuffer::VertexBuffer);
   vertexBuffer->create();
   vertexBuffer->bind();
   vertexBuffer->setUsagePattern(QGLBuffer::StaticDraw);
   vertexBuffer->allocate(vertices, 3*numVertices*sizeof(float)); // copies vertices to GPU? 
   vertexBuffer->release();

   #define BUFFER_OFFSET(bytes) ((GLubyte*) NULL + (bytes)) 
   glEnableClientState(GL_VERTEX_ARRAY);
   glEnableClientState(GL_COLOR_ARRAY);
   glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
   glColorPointer(3, GL_FLOAT, 0,  colors);
}  

当我运行它时,它会在崩溃之前挂起很长时间:-(。 如果我注释掉vertexBuffer-> release();它根本不显示任何内容,但不会崩溃。

我在这里做错了什么?

另外:我怎么能同样只将我的颜色发送到GPU一次? 没有QGLBuffer :: ColorBuffer类型!?

编辑: 我在我的项目中包含了GLee。[h / c]并通过以下方式替换了QGLBuffer调用:

unsigned int vbufferid;
glGenBuffers(1, &vbufferid);  
glBindBuffer(GL_ARRAY_BUFFER, vbufferid); 
int size = 3*numVertices*sizeof(float);
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);

但代码仍然没有绘制任何东西!?

通过glGenBuffers调用为vbufferid分配值1,所以我不认为问题是我的显卡。

编辑2: 我发现如果我注释掉glEnableClientState(GL_COLOR_ARRAY);用VBO(但没有颜色)显示三角形的线!

那么在将VBO用于顶点时,如何将颜色传输到GPU?

没有GL_COLOR_BUFFER类型!?

1 个答案:

答案 0 :(得分:1)

  

我是否正确地理解glVertexPointer()告诉GPU它在CPU中哪里可以获取顶点数据然后GPU从每个paintGL()的CPU中的这个位置复制它?

     

使用VBO可以通过将顶点数据仅写入GPU一次来改善这一点吗?

这是关于一般的想法,虽然实际的执行(你不必关心)有点琐碎。

一个常见的误解是:OpenGL没有“初始化”。当然,您可以在初始阶段将某些资源上传到OpenGL,但是作为状态机,OpenGL需要在您需要之前进入所需状态。

然后就是你真正的问题:你的顶点位置在缓冲对象中。但是你的颜色不是。但是你给OpenGL一个指针,它误解为顶点缓冲区的偏移量。

所以我建议你在glDrawElements电话之前移动以下几行:

#define BUFFER_OFFSET(bytes) ((GLubyte*) NULL + (bytes)) 
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER, vbufferid);
glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));

glBindBuffer(GL_ARRAY_BUFFER, 0); // or put the colors into a VBO as well
glColorPointer(3, GL_FLOAT, 0,  colors);

glDrawElements(…

请注意,缓冲区在执行glVertexPointer调用之前显式绑定,并在颜色指针之前解除绑定。

但是,拥有VBO中的一些属性,而有些属性并未达到目的。因此我建议你将所有的顶点属性移动到VBO中,最好是一个VBO,一个接着一个数组(步长0和它们之间的偏移)或交错(stride =整个属性向量的大小,偏移量是偏移量)第一个属性向量)。

更新代码示例:

上传到VBO

unsigned int vbufferid;
glGenBuffers(1, &vbufferid);  
glBindBuffer(GL_ARRAY_BUFFER, vbufferid); 

int vertexbufsize = (3)*numVertices*sizeof(float);
int colorbufsize = (3)*numVertices*sizeof(float);
glBufferData(GL_ARRAY_BUFFER, vertexbufsize + colorbufsize, NULL, GL_STATIC_DRAW); // data=NULL : initialize, but don't copy

glBufferSubData(GL_ARRAY_BUFFER, 0, vertexbufsize, vertices);
glBufferSubData(GL_ARRAY_BUFFER, vertexbufsize, colorbufsize, vertices);

使用VBO组合绘图

#define BUFFER_OFFSET(bytes) ((GLubyte*) NULL + (bytes)) 
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER, vbufferid);
glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
glColorPointer(3, GL_FLOAT, 0,  BUFFER_OFFSET(vertexbufsize));

glDrawElements(…