Search code examples
androidopengl-esopengl-es-2.0vbo

Relation between buffers and glVertexAttribPointer


I'm trying to understand the relations between [glGenBuffers, glBindData, glBufferData, glBufferSubData] and glVertexAttribPointer.

I saw that you don't really have to use the buffers method (at least not in Android) but rather call glVertexAttribPointer directly, passing a pointer to the buffer object as the last parameter. (the buffers being a FloatBuffer in this case)

e.g.

GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 12, vertexBuffer);
GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false, 16, colorBuffer);
GLES20.glVertexAttribPointer(normalHandle, 3, GLES20.GL_FLOAT, false, 12, normalsBuffer);
GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 8, textureBuffer);

1) Why would I want to use the buffer methods? Only if my data is happened to be stacked together in one array?

2) How do openGL handle these direct (non buffer) functions behind the scenes? I saw that it calls glVertexAttribPointerBounds - does it actually stack it together to a single array of bytes?

3) If I do bind an array to the GL_ARRAY_BUFFER - it means I have to use the stacked array version, and I won't be able to pass anymore direct objects, correct? i.e. I cannot do this:

int[] bufferVertices = new int[1];
GLES20.glGenBuffers(1, bufferVertices, 0);
vertexBufferId = bufferVertices[0];
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, cubeCoords.length * 4 , vertexBuffer, GLES20.GL_STATIC_DRAW);

GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride,0);
GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false, 16, colorBuffer);
GLES20.glVertexAttribPointer(normalHandle, 3, GLES20.GL_FLOAT, false,12, normalsBuffer);
GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false,8, textureBuffer);

Solution

  • You can have multiple buffer objects. If a vertex array buffer is bound, when glVertexAttribPointer is called then the last parameter of glVertexAttribPointer is treated as an offset to this buffer, but if no vertex buffer object is bound, then the last parameter is treated as a pointer to the data:

    See OpenGL ES 2.0 specification; 2.8. VERTEX ARRAYS; 21:

    void VertexAttribPointer( uint index, int size, enum type, 
                              boolean normalized,  sizei stride, 
                              const void *pointer );
    

    ... For each command, pointer specifies the location in memory of the first value of the first element of the array being specified.

    See OpenGL ES 2.0 specification; 2.9. BUFFER OBJECTS; 25:

    ... When an array is sourced from a buffer object, the pointer value of that array is used to compute an offset, in basic machine units, into the data store of the buffer object. ...

    This means it is possible to do:

    int[] bufferVertices = new int[4];
    GLES20.glGenBuffers(4, bufferVertices, 0);
    
    vertexBufferId = bufferVertices[0];
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId);
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, cubeCoords.length * 4, vertexBuffer, GLES20.GL_STATIC_DRAW);
    
    colorBufferId = bufferVertices[1];
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, colorBufferId);
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, cubeCoords.length * 4, colorBuffer, GLES20.GL_STATIC_DRAW);
    
    normlBufferId = bufferVertices[2];
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, normlBufferId);
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, cubeCoords.length * 4, normalsBuffer, GLES20.GL_STATIC_DRAW);
    
    textureBufferId = bufferVertices[3];
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, textureBufferId);
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, cubeCoords.length * 4, textureBuffer, GLES20.GL_STATIC_DRAW);
    

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId);
    GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, 0);
    
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, colorBufferId);
    GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false, 0, 0);
    
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, normlBufferId);
    GLES20.glVertexAttribPointer(normalHandle, 3, GLES20.GL_FLOAT, false, 0, 0);
    
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, textureBufferId);
    GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 0, 0);