OpenGL ES 2.0:使用GL_STREAM_DRAW进行VBO最有效的设置?

时间:2011-09-05 00:34:03

标签: performance opengl-es opengl-es-2.0 vbo

我在OpenGL ES 2.0中使用顶点缓冲对象(VBO)。

我有一组顶点数据,它们永久存储在普通RAM中。原因是从头开始计算顶点位置的成本很高,但可以在最后一个位置添加一个增量来便宜地更新它。

要绘制的实际顶点数随时间变化很快。在一个帧中,我可能有1000个,在下一个2500个。根据前面收到的建议,我现在指定整数UPPER作为将绘制的​​顶点数的上限。基于此值,我只在启动时malloc我的顶点和索引数据数组。

我将GL_STREAM_DRAW使用提示传递给每个glBindBuffer调用,以指示每个帧都会更改数据。

为了尽可能高效,我创建了以下设置:

// SETUP: Called only once.
glBindBuffer(GL_ARRAY_BUFFER,...);
glBufferData(GL_ARRAY_BUFFER,...); // Pass vertex data for UPPER vertices.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,...);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,...); // Pass index values 0 - (UPPER-1).
glEnableVertexAttribArray(...); // Setup vertex attributes.
glVertexAttribPointer(...);
glUseProgram(...); // Use program with custom shaders.
glUniformMatrix4fv(...); // Identify shader uniforms.

// UPDATE: Called when vertex data changes (on each frame).
glBindBuffer(GL_ARRAY_BUFFER,...);
glBufferSubData(GL_ARRAY_BUFFER,...); // Update VBO data.

// RENDER: Called on each frame.
glDrawElements(GL_TRIANGLES, numberOfVerticesThisFrame, ...); // Number of vertices and indices to be used is inherently specified in here.

但是,这会因EXC_BAD_ACCESS上的glDrawElements而中断,我知道这是因为我订购了gl命令。

我之前有类似的设置有效:

// UPDATE: Called when vertex data changes (on each frame).
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,...);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,...); // Pass index values 0 - (actual number of vertices to draw - 1)

// RENDER: Called on each frame.
glBindBuffer(GL_ARRAY_BUFFER,...);
glBufferData(GL_ARRAY_BUFFER,...); // Pass vertex data for actual number of vertices (not UPPER).
glEnableVertexAttribArray(...); // Setup vertex attributes.
glVertexAttribPointer(...);
glUseProgram(...); // Use program with custom shaders.
glUniformMatrix4fv(...); // Identify shader uniforms.
glDrawElements(GL_TRIANGLES, numberOfVerticesThisFrame, ...);

但是,这种设置每帧需要更多的工作,正如您所看到的那样,涉及更改VBO大小(因为它使用实际大小,而不是UPPER),我被告知这是一个很大的性能消耗

有人可以向我解释我的新设置中的任何明显问题,最重要的是我必须>在glDrawElements之前的每一帧调用哪些命令?我假设我可以提前准备所有可能的索引,然后将实际的顶点数传递给glDrawElements,这显然是错误的。

1 个答案:

答案 0 :(得分:9)

要回答您在问题标题中提出的问题,没有“最有效”的缓冲区对象设置用于流式传输顶点数据。特别是在ES 2.0上,它涵盖了范围的不同硬件,每个都有自己的特点。

要回答有关代码停止工作原因的问题,可能是因为您不尊重这些功能实际执行的操作。

例如,glUseProgram会导致给定的程序对象成为任何后续glDraw*调用将使用的程序对象,直到您再次调用glUseProgram Think大多数OpenGL函数都是在全局状态下戳,因为它的工作原理。 glUseProgram正在设置glDraw*读取的全局变量,以找出要使用的着色器。

因此,如果您想确保特定的绘制调用使用特定着色器,那么您必须事先glUseProgram该着色器。或者至少在最近你知道你没有在其他地方改变它。通常,对象的呈现如下所示:

  • 建立用于渲染对象的顶点属性。
  • 设置当前程序,并更改任何每个对象的制服(矩阵等)。
  • 为程序绑定纹理(如果有)。
  • 为该计划绑定其他州,如果有的话。
  • 渲染。
  • 停用属性

第一步使用glEnableVertexAttribArrayglBindBufferglVertexAttribPointer。这些函数就像glUseProgram设置全局状态一样。在使用对象渲染后应该使用glDisableVertexAttribArray,并且应该取消绑定您可能使用过的任何缓冲区。