I'm using a Vertex Buffer Object (VBO) in OpenGL ES 2.0.
I have a set of vertex data which is permanently stored in normal RAM. The reason is that calculating the vertex positions from scratch is costly, but a delta can be added to the last position to cheaply update it.
The actual number of vertices to be drawn changes rapidly over time. In one frame I may have 1000 and in the next 2500. Following advice received here earlier, I now specify integer UPPER
as an upper bound on the number of vertices which will ever be drawn. I malloc
my vertex and index data arrays only once at startup based on this value.
I pass the GL_STREAM_DRAW
usage hint to each glBindBuffer
call to indicate the data changes each frame.
Attempting to be as efficient as possible, I created the following setup:
// 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.
However this breaks with an EXC_BAD_ACCESS
on glDrawElements
, and I know it's due to my ordering of gl
commands.
I had a similar setup earlier which worked:
// 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, ...);
However, this setup requires much more work per frame, and as you can see involves changing the VBO sizes (since it uses actual size, not UPPER
), which I've been told is a big performance drain.
Could someone please explain to me any obvious problems with my new setup, and most importantly which commands I have to call every frame before glDrawElements
? My assumption that I can prepare all possible indices in advance and then pass the actual vertex count to glDrawElements
is clearly wrong.
To answer the question you asked in your question title, there is no "most efficient" buffer object setup for streaming vertex data. Especially not on ES 2.0, which covers a wide range of different hardware, each with its own peculiarities.
To answer your question about why your code stopped working, it's likely because you're not respecting what these functions actually do.
For example, glUseProgram
causes the given program object to become the program object that any subsequent glDraw*
calls will use until you call glUseProgram
again. Think of most OpenGL functions as poking at global state, because that's how it works. glUseProgram
is setting a global variable that glDraw*
reads to find out what shader to use.
Therefore, if you want to ensure that a particular draw call uses a particular shader, then you must glUseProgram
that shader immediately beforehand. Or at least recently enough that you know that you didn't change it somewhere else. Generally, rendering for an object looks like this:
The first step uses glEnableVertexAttribArray
, glBindBuffer
, and glVertexAttribPointer
. These functions, just like glUseProgram
set global state. You should use glDisableVertexAttribArray
after having rendered with the object, and you should unbind any buffers you may have used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With