Qt 如何在OpenGL中将顶点缓冲区对象与顶点数组一起使用?

Qt 如何在OpenGL中将顶点缓冲区对象与顶点数组一起使用?,qt,opengl,Qt,Opengl,我使用顶点数组快速绘制了很多三角形: void initializeGL() { ... glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(3, GL_FLOAT, 0, vertices); glColorPointer(3, GL_FLOAT, 0, colors); } void paintGL() { ...

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

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_数组),三角形将用VBO显示(但没有颜色)

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

没有GL_颜色_缓冲区类型

glVertexPointer()告诉GPU在CPU的哪个位置可以获取顶点数据,然后GPU从CPU的这个位置为每个paintGL()复制这些数据,我的理解对吗

使用VBO只需将顶点数据写入GPU一次,就能改善这一点吗

这是一般的想法,尽管实际执行(你不必关心)有点棘手

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

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

因此,我建议您将以下几行移到
gldrawerelements
调用之前:

#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(…

如果您认为在处理VBO时需要使用glBufferData函数,则不会使用glXYZPointer方法。但我可能弄错了。我仍然非常确定您需要。片段和顶点着色器是什么样子的?您确定问题不存在吗?@dowhilefor:您仍然必须告诉OpenGL在缓冲区中的何处查找顶点数据,一个d每个元素的大小。因此,是的,您仍然需要使用
gl…Pointer
函数。@dowhilefor:谢谢您的帮助,但我认为您是错的。如果我注释掉glvertexinter,则会调用程序崩溃。此外,我的代码与OpenGL编程指南第104页上的示例非常类似(它也使用glVertexPointer)。哦,好吧,别介意我:)我使用opengl已经很久了。看我的答案。颜色只是另一个顶点属性。它们也会进入GL_数组_缓冲区。谢谢你的帮助datenwolf!成功了:-)。我不必将所有的enable/bind/xyzPointer代码移到我的paintGL()中尽管如此。对我来说,即使我在initializeGL()中只做一次,它也能工作。但每次重新绘制时运行这些行的成本可能并没有那么大?它们只是告诉OpenGL在哪里查找数据,而不是将任何数据从CPU复制到GPU?我的8M三角形现在以很好的FPS旋转:-)。您认为下一个优化可能是什么?也许使用VOB作为索引?也许是在顶点着色器中计算颜色?@Andy:是的,下一步是索引数组。缓冲区类型GL\U索引\U缓冲区。然后我还建议交错顶点位置和颜色属性。现在的布局是PPP…PCCC…C。通过交错它们,您可以获得更好的内存位置,即,
pcpc…PC