openglcollision-detectionvertexvertex-buffervertex-array

OpenGL Vertex buffer object, can I access the vertex data for other uses such as collision detection?


I'm currently using the GLTools classes that come along with the Superbible 5th edition. I'm looking in the GLTriangleBatch class and it has the following code:

// Create the master vertex array object
glGenVertexArrays(1, &vertexArrayBufferObject);
glBindVertexArray(vertexArrayBufferObject);


// Create the buffer objects
glGenBuffers(4, bufferObjects);

#define VERTEX_DATA     0
#define NORMAL_DATA     1
#define TEXTURE_DATA    2
#define INDEX_DATA      3

// Copy data to video memory
// Vertex data
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[VERTEX_DATA]);
glEnableVertexAttribArray(GLT_ATTRIBUTE_VERTEX);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*nNumVerts*3, pVerts, GL_STATIC_DRAW);
glVertexAttribPointer(GLT_ATTRIBUTE_VERTEX, 3, GL_FLOAT, GL_FALSE, 0, 0);

// Normal data
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[NORMAL_DATA]);
glEnableVertexAttribArray(GLT_ATTRIBUTE_NORMAL);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*nNumVerts*3, pNorms, GL_STATIC_DRAW);
glVertexAttribPointer(GLT_ATTRIBUTE_NORMAL, 3, GL_FLOAT, GL_FALSE, 0, 0);

// Texture coordinates
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[TEXTURE_DATA]);
glEnableVertexAttribArray(GLT_ATTRIBUTE_TEXTURE0);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*nNumVerts*2, pTexCoords, GL_STATIC_DRAW);
glVertexAttribPointer(GLT_ATTRIBUTE_TEXTURE0, 2, GL_FLOAT, GL_FALSE, 0, 0);

// Indexes
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObjects[INDEX_DATA]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort)*nNumIndexes, pIndexes, GL_STATIC_DRAW);

// Done
glBindVertexArray(0);

// Free older, larger arrays
delete [] pIndexes;
delete [] pVerts;
delete [] pNorms;
delete [] pTexCoords;

// Reasign pointers so they are marked as unused
pIndexes = NULL;
pVerts = NULL;
pNorms = NULL;
pTexCoords = NULL;

From what I understand the code passes the arrays that the pointers pVerts, pNorms, pTexCoords, pIndexes and stores them in a Vertex array object, which essentially is an array of vertex buffer objects. These are stored in memory on the GPU. The original pointers are then deleted.

I'm interested in accessing the vertex positions, which were held in the array pVert pointed to.

Now my question revolves around collision detection. I want to be able to access an array of all of the vertices of my GLTriangleBatch. Can I obtain them through the vertexBufferObject at a later time using some sort of getter method? Would it be best to just keep the pVerts pointer around and use a getter method for that instead? I'm thinking in terms of performance, as I hope to implement a GJK collision detection algorithm in the future...


Solution

  • Buffer objects, when used as sources for vertex data, exist for the benefit of rendering. Going backwards (reading the data back) is generally not advisable from a performance point of view.

    The hint you give glBufferData has three access patterns: DRAW, READ, and COPY; these tell OpenGL how you intend to be getting/retrieving data from the buffer object directly. The hints do not govern how OpenGL should be reading/writing from/to it. These are just hints; the API doesn't enforce any particular behavior, but violating them may lead to poor performance.

    DRAW means that you will put data into the buffer, but you will not read from it. READ means that you will read data from the buffer, but you will not write to it (typically for transform feedback or pixel buffers). And COPY means that you will neither read from nor write to the buffer directly.

    Notice that there is no hint for "read and write." There is just "write", "read", and "neither." Consider that a hint as to how good of an idea it is to write data to a buffer directly and then start reading from that buffer.

    Again, the hints are for the user directly getting or retrieving data. glBufferData, glBufferSubData, and the various mapping functions all do writes, while glGetBufferSubData and mapping functions all do reads.

    In any case no, you should not do this. Keep a copy of the position data around in client memory if you need to use it on the client.

    Also, some drivers ignore the usage hints entirely. They instead decide where to place the buffer object based on how you actually use it, rather than how you say you intend to use it. This will be worse for you, because if you start reading from that buffer, the driver may move the buffer's data to memory that is not as fast. It may be moved out of the GPU and even into the client memory space.

    However, if you insist on doing this, there are two ways to read data from a buffer object. glGetBufferSubData is the inverse of glBufferSubData. And you can always map the buffer for reading instead of writing.