10

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:

enter image description here

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:

  1. What is the correct command order for creating a dynamic vertex buffer whose elements will be completely updated on every frame?

  2. Can the vertex buffer grow between frames? Or do I have to flush exactly the same size?

  3. 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?

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
bobobobo
  • 64,917
  • 62
  • 258
  • 363

2 Answers2

6

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.

bobobobo
  • 64,917
  • 62
  • 258
  • 363
  • 2
    Did you ever figure this out? I ran into the same issue of it seemed to work, but it didn't. – John Riselvato May 23 '13 at 13:58
  • No. But vertex arrays work _really well_, they're very fast (probably because on iOS ram is actually _shared_ between the GPU and CPU). I'd like to see a test of VB's vs VA's performance wise. – bobobobo May 23 '13 at 14:41
  • Well, unfortunately, I keep coming back to this question. Been looking at it for over a month. Did you ever run into any issues were if you manipulate (Transform) your object it gets all disfigured. I am guessing this is because the array has changed so, the transform you tried to apply doesn't have all the correct data. Do you have suggestions on how the fix that? – John Riselvato May 23 '13 at 15:26
  • 2
    The only place I use VB's now is for models __that load once__ and never change after that. They do fine under transformations, you just can't change the _actual vertex data_ without something going weird. For deformable geometry I use vertex arrays _only_. Before drawing a vertex array, __be sure to disable the vertex buffer with a line like:__ `glBindBuffer( GL_ARRAY_BUFFER, 0 ) ; // DISABLE THE STUPID VERTEX BUFFER RAT POISON`. I got tripped up by that earlier too. – bobobobo May 23 '13 at 15:47
  • Can this not be done in Android? I'm starting to become worried that deformable geometry isn't possible in Android without native code... – Andy Jul 24 '13 at 03:13
  • 1
    Oh look, 3 months later unfortunately found this same answer on google. Ugh. I really don't think there is a clean possible way of updating a vertex array dynamically. – John Riselvato Aug 14 '13 at 14:59
  • @bobobobo _"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."_ This is false and misleading. If you will be updating a small section, use glBufferSubData. If you will update the entire VBO, use glBufferData. Another method for updating the entire VBO is to call glBufferData with a NULL pointer (which tells driver you don't care about old contents,) then use glBufferSubData to update buffer with new contents. – arkon Sep 23 '14 at 19:42
  • @bobobobo I'm experiencing a similar problem on Android and I noticed that updating vertex data with glBufferSubData() works just fine if used with a VAO. Actually, I'm having the same problem (weird glitches when updating data) also on desktop if I disable the VAO. However, this leads to another problem: the VAO extension is not present on all GLES devices. So maybe it's best to use your vertex array approach for now :) – juzzlin Sep 04 '15 at 19:11
  • hey @bobobobo and other blokes - if you're still with this - now that it is years later, I put in an answer which may be utterly useless or may lead to more information! Cheers – Fattie Nov 30 '18 at 13:30
1

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);
juzzlin
  • 45,029
  • 5
  • 38
  • 50
Andy
  • 7,885
  • 5
  • 55
  • 61
  • @juzzlin Are you saying `GLES20` is available on that device but not all of its methods are supported? – Andy Sep 09 '15 at 19:42