When I update my vertex array on iOS in OpenGL 2.0, the original vertex data is staying on the screen -- ie the 1st flush is persistent (the initial set of points I sent down to the GPU gets rendered every frame), but the 2nd, 3rd, 4th, .. nth flushes all seem to overwrite the same memory.
So I'm doing:
vector<VertexType> rawDynamicData ;
glGenVertexArraysOES( 1, &va ) ; CHECK_GL ;
glBindVertexArrayOES( va ) ; CHECK_GL ;
glGenBuffers( 1, &vb ) ; CHECK_GL ;
glBindBuffer( GL_ARRAY_BUFFER, vb ) ; CHECK_GL ;
glBufferData( glBufferData(
GL_ARRAY_BUFFER, //Specifies the target buffer object.
rawDynamicData.size() * sizeof( VertexType ),
&rawDynamicData[0],
GL_DYNAMIC_DRAW // I plan to update the data every frame
) ; CHECK_GL ;
On subsequent frames, I'm just calling again:
// update the data
glBufferData( glBufferData(
GL_ARRAY_BUFFER, //Specifies the target buffer object.
rawDynamicData.size() * sizeof( VertexType ),
&rawDynamicData[0],
GL_DYNAMIC_DRAW // I plan to update the data every frame
) ; CHECK_GL ;
I also tried
//update the data
GLvoid* vbo_buffer = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
memcpy(vbo_buffer, &rawDynamicData[0], rawDynamicData.size()*sizeof(VertexType) );
glUnmapBufferOES(GL_ARRAY_BUFFER);
But with both ways, I get this:
The white points were the initial data, and the red points are the result of subsequent calls to glBufferData
So this question has a couple of parts regarding dynamic vbos in OpenGL ES 2.0:
What is the correct command order for creating a dynamic vertex buffer whose elements will be completely updated on every frame?
Can the vertex buffer grow between frames? Or do I have to flush exactly the same size?
I know about using "client memory" pointers, can you do this in OpenGL ES 2.0 (to avoid the memcpy) or is that deprecated, should use vertex buffers exclusively?
Misfire #1
I found an answer here which pointed me to using glSubBufferData
for parking data in the array, and to use glBufferData
only for the initial allocation. Ultimately this did not work (if the vb was too big, only the first 3 elements would be updated),
So,
glBufferData( glBufferData(
GL_ARRAY_BUFFER, //Specifies the target buffer object.
rawDynamicData.size() * sizeof( VertexType ),
0, // NO INITIAL DATA
GL_DYNAMIC_DRAW // I plan to update the data every frame
) ; CHECK_GL ;
Then for the first and subsequent updates:
// Update the whole buffer
glBufferSubData(GL_ARRAY_BUFFER, 0,
rawDynamicData.size()*sizeof(VertexType), &rawDynamicData[0]) ;
That seemed to work.
Seemed. But it didn't.
The only thing I could do to make it work was quit using vertex buffers and use client memory vertex arrays.
This looks as follows:
// do all your vertex attrib/glVertexAttrib enable commands:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexPC), &debugPoints->data[0].pos.x) ;
CHECK_GL ;
glEnableVertexAttribArray(0); CHECK_GL ;
// ..do glVertexAttrib* for all attributes you have..
// then just flush your draw command
glDrawArrays(GL_POINTS, 0, debugPoints->data.size());
So in short, I have found that using vertex buffers for dynamic data is either challenging or not supported.
For Android users out there, I just confirmed that it's possible to have deformable geometry using vertex attribute arrays in OpenGL ES 2.0 on Android, in a little test. The annoying thing is you don't get to pass a pointer to your own array, instead you have to use a FloatBuffer (or similar type). Sample code:
Initialization:
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (number of coordinate values * 4 bytes per float)
coords.length * 4);
// use the device hardware's native byte order
bb.order(ByteOrder.nativeOrder());
// create a floating point buffer from the ByteBuffer
vertexBuffer = bb.asFloatBuffer();
// add the coordinates to the FloatBuffer
vertexBuffer.put(coords);
// set the buffer to read the first coordinate
vertexBuffer.position(0);
Drawing Code:
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
checkGlError("glGetAttribLocation");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
checkGlError("glEnableVertexAttribArray");
float newValue = (float) Math.sin((float) (frame++) / 1000) + 1;
System.out.println(newValue);
vertexBuffer.put(0, newValue);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, VERTEX_STRIDE, vertexBuffer);