在 iOS 上使用具有多个 VBO 和 IBO(多个对象)OpenGLES 2 的 VAO 进行绘制

Posted

技术标签:

【中文标题】在 iOS 上使用具有多个 VBO 和 IBO(多个对象)OpenGLES 2 的 VAO 进行绘制【英文标题】:Draw using VAO with multiple VBOs and IBOs (multiple objects) OpenGLES 2 on iOS 【发布时间】:2012-11-14 22:49:02 【问题描述】:

对于多个对象(大约 200 个对象,其中 15 个一次可见,每个对象都有自己的顶点和索引缓冲区),我对使用 VAO(顶点数组对象)有些困惑。下面是我的渲染函数

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
 

glClearColor(0.50f, 0.50f, 0.50f, 1.0f);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

[super drawLines];


for(int i=0; i< self.numberofBars; i++) //numberofBars



    // Render the object

    [self.barShaderProg use];

    iVBarNode *temp = [theBars objectAtIndex:i];

    _modelViewProjectionMatrix = GLKMatrix4Multiply(ProjectionView, modelMatrix);
    _modelViewProjectionMatrix =  GLKMatrix4Multiply(_modelViewProjectionMatrix, temp.modelMatrix);
    GLKMatrix4 modeltotalMatrix = GLKMatrix4Multiply(modelMatrix, temp.modelMatrix);
    GLKMatrix4 modelViewMatrix = GLKMatrix4Multiply(ViewMatrix, modeltotalMatrix);

    _normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);


    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
    glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0,_normalMatrix.m);//
    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEW_MATRIX], 1, 0, modelViewMatrix.m);

    glUniform4f(uniforms[COLOR_VECTOR], temp.barColor.r, temp.barColor.g, temp.barColor.b, temp.barColor.a);

    //bind corresponding buffer before drawing
    glBindBuffer(GL_ARRAY_BUFFER, [temp getVertexID]);


    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), BUFFER_OFFSET(0));
    glEnableVertexAttribArray(GLKVertexAttribNormal);
    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), BUFFER_OFFSET(12));


    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, [temp getIndexID]);
    glDrawElements(GL_TRIANGLES, [temp.bar getIndicesSize], GL_UNSIGNED_SHORT, (void*)0); 



if(self.translation>0)

    self.paused = NO;


else
    self.paused = YES;
 

这工作得很好。 在 OpenGLES 分析器中分析了我的代码后,它显示使用 VAO 可以从中受益,因为 glVertexAttribPointer 调用是多余的(对所有人都一样)。但我只是不知道是否可以将它们与不同的顶点缓冲区对象一起使用。我在互联网上找到的大多数示例仅将它们与一个 VBO 或两个 VBO 一起使用,其中第二个 VBO 定义了不同的属性,而不是我的情况相同的属性。我尝试绑定为我的对象生成的每个顶点缓冲区索引使用单个 VAO,但它没有按如下方式工作

-(void) configureVertexArrayObject



// Create and bind the vertex array object.

glGenVertexArraysOES(1,&vertexArrayObject);

glBindVertexArrayOES(vertexArrayObject);

for(int i=0;i<self.numberofBars;i++)

    iVBarNode *myNode = [theBars objectAtIndex:i];

 glBindBuffer(GL_ARRAY_BUFFER, [myNode getVertexID]);
// Configure the attributes in the VAO
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), BUFFER_OFFSET(12));

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, [myNode getIndexID]);



// Bind back to the default state.

glBindBuffer(GL_ARRAY_BUFFER,0);

glBindVertexArrayOES(0);

这是我的渲染方式

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect


glClearColor(0.50f, 0.50f, 0.50f, 1.0f);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

[super drawLines];

glBindVertexArrayOES(vertexArrayObject);

for(int i=0; i< self.numberofBars; i++) //numberofBars



    // Render the object

    [self.barShaderProg use];

    iVBarNode *temp = [theBars objectAtIndex:i];

    _modelViewProjectionMatrix = GLKMatrix4Multiply(ProjectionView, modelMatrix);
    _modelViewProjectionMatrix =  GLKMatrix4Multiply(_modelViewProjectionMatrix, temp.modelMatrix);
    GLKMatrix4 modeltotalMatrix = GLKMatrix4Multiply(modelMatrix, temp.modelMatrix);
    GLKMatrix4 modelViewMatrix = GLKMatrix4Multiply(ViewMatrix, modeltotalMatrix);

    _normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);


    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
    glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0,_normalMatrix.m);//
    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEW_MATRIX], 1, 0, modelViewMatrix.m);

    glUniform4f(uniforms[COLOR_VECTOR], temp.barColor.r, temp.barColor.g, temp.barColor.b, temp.barColor.a);

    //all buffer associated with VAO now

    glDrawElements(GL_TRIANGLES, [temp.bar getIndicesSize], GL_UNSIGNED_SHORT, (void*)0); 


  glBindVertexArrayOES(0);

 if(self.translation>0)
 
     self.paused = NO;


 
  else
    self.paused = YES;

 



在我的第二次尝试中,我尝试仅指定 VAO 的布局,使用 glVertexAttribPointer() 表示顶点和法线(而不指定 VBO 和 IBO id),并像我在没有 VAO 的情况下所做的那样进行渲染(上面的第一次渲染代码),但现在我没有使用指定顶点布局 glVertexAttribPointer() 正如我已经向 VAO 提到的那样(实际上这是使用 VAO 的全部意义)。 这两种方法都给了我相同大小的对象,这让我觉得 VAO 以某种方式为我的所有对象复制了几何图形。我的所有对象都具有相同的几何形状但高度不同。现在我有一个选择是拥有一个顶点和索引缓冲区对象,我可以沿高度缩放并根据需要定位对象。我仍然想知道 VAO 到底有什么,没有什么,是否有办法让它发挥作用。

【问题讨论】:

【参考方案1】:

在 OpenGLES 分析器中分析了我的代码后,它显示使用 VAO 可以从中受益,因为 glVertexAttribPointer 调用是多余的(对所有人都一样)。

除非您的 glBindBuffer 调用每次都绑定相同的缓冲区,否则我认为这种推理是可疑的。

您可以通过将所有对象打包到 same 缓冲区中,从而在绘制时执行一次 bind+glVertexAttribPointer 调用,从而获得更多收益。由于您所有的对象都具有相同的顶点格式,因此您似乎没有理由不能这样做。您必须调整顶点索引以在现在更大的缓冲区中选择正确的位置,但这并不太难。

【讨论】:

我很确定 glBindBuffer 不会每次都绑定同一个缓冲区,因为我检查了缓冲区句柄(索引和顶点缓冲区)。它们从 1 开始并随着我绑定新的顶点或索引缓冲区而增加,直到我的所有对象都完成。对于您回复的第二部分,我猜不是您提到的方法而是对每个对象使用相同的 VBO 和 IBO 更好,我可以使用 modelMatrix 将它们放置在我想要的不同大小的任何位置。 实际上,glBindBuffer(GL_ARRAY_BUFFER... 没有绑定任何东西,它只是将全局变量 open GL 设置为“当前”,实际加载发生在您调用 glVertexAttribPointer(GLKVertexAttribNormal 时。每个 for 循环调用都会覆盖先前的顶点属性。要么使用一个 VBO,要么使用多个 VAO——每个对象一个(参见***.com/questions/8862578/…)

以上是关于在 iOS 上使用具有多个 VBO 和 IBO(多个对象)OpenGLES 2 的 VAO 进行绘制的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 VBO 和/或 IBO 而不是简单的顶点数据?

使用 VBO/IBO 的 OpenGL 纹理三角形

OpenGL 基本 IBO/VBO 不工作

如何优化 VBO/IBO 以最大化 GPU 缓存使用率

VAO 与 VBO 和 IBO 的手动绑定

VAO 是不是同时记住 EBO/IBO(元素或索引)和 VBO?