如何在带有 Qt 的 OpenGL 中使用顶点缓冲区对象绘制矩形?

Posted

技术标签:

【中文标题】如何在带有 Qt 的 OpenGL 中使用顶点缓冲区对象绘制矩形?【英文标题】:How do I draw a rectangle using a Vertex Buffer Object in OpenGL with Qt? 【发布时间】:2012-12-15 14:49:13 【问题描述】:

我正在尝试使用带有 Qt 的 OpenGL 中的顶点缓冲区对象绘制一个样方。 这是我的几何图形:

numVertices = 4;
vertices = new float[3*numVertices];
int i = 0;
vertices[i++] = 0.0f; vertices[i++] = 0.0f; vertices[i++] = 0.0f; // (0,0,0)
vertices[i++] = 1.0f; vertices[i++] = 0.0f; vertices[i++] = 0.0f; // (1,0,0)
vertices[i++] = 1.0f; vertices[i++] = 1.0f; vertices[i++] = 0.0f; // (1,1,0)
vertices[i++] = 0.0f; vertices[i++] = 1.0f; vertices[i++] = 0.0f; // (0,1,0)
i = 0;
// spilt quad into two triangles:
numTriangles = 2;
indices = new unsigned int[numTriangles*3];
indices[i++] = 0; indices[i++] = 1; indices[i++] = 2; 
indices[i++] = 0; indices[i++] = 2; indices[i++] = 3;

initializeGL 方法中的下一步:

QGLBuffer vertexBuffer;
vertexBuffer.create();
vertexBuffer.bind();
vertexBuffer.allocate(vertices, numVertices*sizeof(float));

QGLShaderProgram* shaderProgram_ = new QGLShaderProgram;
shaderProgram_->addShaderFromSourceFile(QGLShader::Vertex,"C:/src/light.vert.glsl") ) 
shaderProgram_->addShaderFromSourceFile(QGLShader::Fragment, "C:/src/light.frag.glsl");
bool ok = shaderProgram_->link();
ok = shaderProgram_->bind();

我认为 VBO 部分所做的只是将顶点复制到 GPU? (为什么这么多行?)

着色器部分在旧式 glBegin(GL_QUADS); 下工作得很好;

接下来我的paintGL方法:

shaderProgram_->setAttributeBuffer("vertex", GL_FLOAT, 0, 3, 0);
shaderProgram_->enableAttributeArray("vertex");
glDrawElements(GL_TRIANGLES, numTriangles, GL_UNSIGNED_INT, indices);

前两行在做什么?也许告诉着色器有一个名为“顶点”的顶点缓冲区,类型为 GL_FLOAT? 但是我在创建 VBO 时没有指定任何名称!? OpenGL怎么知道这是“顶点”?

反正我什么都没看到!? 有没有我遗漏的步骤? 我的着色器很简单:

# version 120  
varying vec4 color;
void main() 
    vec4 vertex = gl_Vertex;
    // pass trough:
    gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vertex; 
    color = gl_Color; 


# version 120 
varying vec4 color;
void main (void) 
   
    // pass-trough:    
 gl_FragColor = color;
 

【问题讨论】:

我知道这是一个老问题,但作为一个 opengl 初学者,我发现 this QT 使用 VBO 和 OpenGL ES 绘制立方体的示例非常有用。我基本上注释掉了在顶点和索引数组中生成其他 5 个面的代码行,并在相应的 glBufferData 调用中更正了顶点和索引的数量,仅此而已。 QT 有很多有据可查的示例,请随时查看 【参考方案1】:

我猜你在这里输了 3 个:

vertexBuffer.allocate(vertices, numVertices*sizeof(float));

->

vertexBuffer.allocate(vertices, numVertices*sizeof(float)*3);

我认为 VBO 部分所做的只是将顶点复制到 GPU? (为什么这么多 行?)

是的。这就是 OpenGL 的工作原理。要在 VBO 中存储某些内容,您必须创建它、绑定它并复制数据。

前两行在做什么?也许告诉着色器 有一个名为“顶点”的 GL_FLOAT 类型的顶点缓冲区?但是,我 创建 VBO 时没有指定任何名称!? OpenGL是怎么知道的 这是“顶点”吗?

第一行:

QGLShaderProgram::setAttributeBuffer() "在此着色器程序中设置名为 name 的属性的顶点值数组,从当前绑定的顶点缓冲区中的特定偏移量开始。" - 从手册。同样,这就是 OpenGL 的工作原理。这是一个状态机。您将特定缓冲区绑定到 GL_ARRAY_BUFFER 绑定点,然后告诉 OpenGL 这是存储“顶点”属性数据的缓冲区。 “顶点”是您在着色器程序中的属性名称。 (也许你应该把它改成“gl_Vertex”)猜猜,Qt 调用glVertexAttribLocation() 来查找你的属性的位置,然后调用glVertexAttribPointer()

第二行:

OpenGL 必须知道它应该将数据从某个缓冲区复制到着色器程序可以找到它的某个特殊位置。这是通过启用特定位置的属性数组来完成的。猜猜,Qt 在这里调用glVertexAttribLocation()glEnableAttribArray()

顺便说一句: 您是否在代码中指定了任何模型视图和投影矩阵?我不确定它们是否是默认设置的。尝试从着色器中删除这些值以进行测试。

添加:

glDrawElements(GL_TRIANGLES, numTriangles, GL_UNSIGNED_INT, indices);

第二个参数不是三角形的数量,而是索引的数量,将从索引数组中读取。这里应该是numTriangles*3

【讨论】:

谢谢奥列格!但我仍然没有看到任何矩形。我认为我的模型视图和投影很好。如果我添加一个 glutSolidTeapot(2.0f);调用我的paintGL方法,这显示得很好。 @Andy 我在glDrawElements() 调用中发现了另一个错误。在主帖中查看。

以上是关于如何在带有 Qt 的 OpenGL 中使用顶点缓冲区对象绘制矩形?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Qt 中使用顶点缓冲区对象渲染地形?

有没有办法在带有 Java 的 Android 的 OpenGL ES 2.0 中使用顶点缓冲区中的对象?

带有附加数据的 OpenGL 索引缓冲区对象

使用 VBO 在 OpenGL 中渲染人群

OpenGL/C++:使用顶点缓冲区进行从后到前渲染

带有 OpenGL 的 Qt MDI 应用程序:如何获取有效的屏幕截图?