3

我使用顶点数组非常快地绘制了很多三角形:

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

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

vbufferid 被 glGenBuffers 调用赋值为 1,所以我不认为问题出在我的显卡上。

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

那么在使用 VBO 作为顶点时如何将颜色传输到 GPU 上呢?

没有 GL_COLOR_BUFFER 类型!?

4

1 回答 1

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(…
于 2012-12-21T14:33:46.930 回答