我在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
,这显然是错误的。
答案 0 :(得分:9)
要回答您在问题标题中提出的问题,没有“最有效”的缓冲区对象设置用于流式传输顶点数据。特别是在ES 2.0上,它涵盖了宽范围的不同硬件,每个都有自己的特点。
要回答有关代码停止工作原因的问题,可能是因为您不尊重这些功能实际执行的操作。
例如,glUseProgram
会导致给定的程序对象成为任何后续glDraw*
调用将使用的程序对象,直到您再次调用glUseProgram
。 Think大多数OpenGL函数都是在全局状态下戳,因为它的工作原理。 glUseProgram
正在设置glDraw*
读取的全局变量,以找出要使用的着色器。
因此,如果您想确保特定的绘制调用使用特定着色器,那么您必须事先glUseProgram
该着色器。或者至少在最近你知道你没有在其他地方改变它。通常,对象的呈现如下所示:
第一步使用glEnableVertexAttribArray
,glBindBuffer
和glVertexAttribPointer
。这些函数就像glUseProgram
设置全局状态一样。在使用对象渲染后应该使用glDisableVertexAttribArray
,并且应该取消绑定您可能使用过的任何缓冲区。