Ok, step by step:
glGenVertexArraysOES(1, &_vertexArray); glBindVertexArrayOES(_vertexArray);
This binds and generates a vertex array object (VAO). VAO now contains no data. It just contains all the state associated with the arrays / vertex attributes, such as activated attributes or settings made with glVertexAttribPointer
.
glGenBuffers(1, &_vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(gCubeVertexData), gCubeVertexData, GL_STATIC_DRAW);
A vertex buffer object (VBO) is now created and linked, which is essentially a simple data buffer managed by OpenGL and copies vertex data into it.
Look at this data:
GLfloat gCubeVertexData[216] = { // Data layout for each line below is: // positionX, positionY, positionZ, normalX, normalY, normalZ, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
Your data is laid out as a bunch of floats (32 bits / 4 bytes each), and every six values represent a vertex, which, in turn, consists of a position (3 floats) and normal (3 floats).
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
This indicates the first attribute (position) containing 3 float values for each vertex, in increments of 24 bytes between each vertex. This means that it is 24 bytes from the beginning of the attribute values (position in this case) of one vertex to the beginning of the attribute data of the next vertex. Indeed, 24 bytes is the size of 6 floats and therefore the data of one vertex in our vertex data, so this exactly matches. The last parameter says that the position data starts at the beginning of the current associated VBO (which contains our vertex data), since it is the first attribute in our vertex data.
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
Indicates a second attribute (normal) containing 3 float values for each vertex, again in increments of 24 bytes, since they were obtained from the same data. Thus, from one normal to another it is also 24 bytes (6 floats). Now the last parameter says that normal data starts 12 bytes (3 floats) after the start of the current associated VBO (which contains our vertex data). This is necessary because normal is the second attribute in our vertex data, so we need to “jump over” the first three values (which are the position) to get to the normal data. If we used 0 again, we would have taken the same data as for the positions.
glEnableVertexAttribArray(GLKVertexAttribPosition); glEnableVertexAttribArray(GLKVertexAttribNormal);
Finally, they activate the attributes for rendering.
glBindVertexArrayOES(0);
So now it binds the default value (no) of VAO, since we are done with specifying it. I assume that all this piece of code is part of some initialization procedure. So now, when we later want to display our vertex data, perhaps using glDrawArrays
, we only need to bind VAO with glBindVertexArray
before calling the draw method and each vertex array state made by glEnableVertexAttribArray
or glVertexAttribPointer
to get the values set when VAO was bound by the latter, as in our initialization procedure. If you will not use VAO, you will have to call glBindBuffer
, and two glEnableVetrexAttribArray
and glVertexAttribPointer
each time you want to draw this vertex data.
But all of these explanations suggest that you are more or less familiar with these concepts. If all these words do not tell you anything, you should start by exploring some real learning resource before trying to decrypt the code of other people.