在 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 进行绘制的主要内容,如果未能解决你的问题,请参考以下文章