【问题标题】:How do I use a Vertex Buffer Object with a Vertex Array in OpenGL?如何在 OpenGL 中使用带有顶点数组的顶点缓冲区对象?
【发布时间】:2012-12-21 13:07:26
【问题描述】:

我正在使用顶点数组快速绘制很多三角形:

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 从 CPU 中的这个位置为每个paintGL() 复制它?

使用 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 类型!?

【问题讨论】:

  • 如果认为在处理VBO时需要使用glBufferData函数,则不使用glXYZPointer方法。但我可能在这里弄错了。不过我很确定你需要glBufferData。您的片段和顶点着色器看起来如何?你确定问题不存在吗?
  • @dowhilefor:您仍然必须告诉 OpenGL 在缓冲区中的什么位置可以找到顶点数据,以及每个元素的大小。所以是的,你仍然需要使用 gl…Pointer 函数。
  • @dowhilefor:感谢您的帮助,但我认为您错了。如果我注释掉 glVertexPointer 调用程序崩溃。此外,我的代码与 The Open GL Programming guide(也使用 glVertexPointer)第 104 页上的示例非常相似。
  • 哦,好吧,不要介意我 :) 自从我使用 opengl 以来,它已经很久了。
  • 看我的回答。颜色只是另一个顶点属性。它们也进入 GL_ARRAY_BUFFER。

标签: qt opengl


【解决方案1】:

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

使用 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,它们之间有偏移)或交错的(步幅 = 整个属性向量的大小,偏移量是到第一个属性向量)。

更新代码示例:

上传到 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(…

【讨论】:

  • 感谢您的帮助 datenwolf!那行得通:-)。不过,我不必将所有启用/绑定/xyzPointer 代码移动到我的paintGL() 中。对我来说,即使我只在我的 initializeGL() 中这样做一次,它也可以工作。但是每次重绘运行这些行的成本可能没有那么大?他们只是告诉 OpenGL 在哪里寻找数据,而不是将任何数据从 CPU 复制到 GPU?
  • 我的 8M 三角形现在以不错的 FPS 旋转 :-)。你会建议下一个优化是什么?也许使用VOB作为索引?也许在顶点着色器中计算颜色?
  • @Andy:是的,索引数组将是下一步。缓冲区类型 GL_INDEX_BUFFER。然后我还建议交错顶点位置和颜色属性。现在布局是PPP…PCCC…C。通过交错它们可以获得更好的内存局部性,即PCPCPC…PC
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多