我在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
的假设显然是错误的。 最佳答案
为了回答您在问题标题中提出的问题,没有用于流传输顶点数据的“最有效”缓冲区对象设置。特别是在ES 2.0上,尤其是在涵盖各种不同硬件的ES 2.0上,每种特性都有其独特之处。
要回答有关代码为何停止工作的问题,可能是因为您不尊重这些功能的实际作用。
例如,glUseProgram
导致给定的程序对象成为以后所有glDraw*
调用将使用的程序对象,直到再次调用glUseProgram
。可以将大多数OpenGL函数视为戳全局状态,因为这就是它的工作方式。 glUseProgram
设置glDraw*
读取的全局变量,以找出要使用的着色器。
因此,如果要确保特定的绘图调用使用特定的着色器,则必须事先预先对该着色器进行glUseProgram
。或至少到最近才知道您没有在其他地方进行更改。通常,对象的渲染如下所示:
第一步使用
glEnableVertexAttribArray
,glBindBuffer
和glVertexAttribPointer
。这些功能就像glUseProgram
设置全局状态一样。与对象一起渲染后,应使用glDisableVertexAttribArray
,并且应取消绑定(bind)可能使用过的所有缓冲区。关于performance - OpenGL ES 2.0 : The most efficient setup for a VBO with GL_STREAM_DRAW?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7303000/