@datenwolf already covered the key aspect in a comment above. To elaborate some more:
You do not have to bind
GL_ARRAY_BUFFER again before the
glDrawElements() call. What matters is that the buffer you want to source a given attribute from is bound when you make the
glVertexAttribPointer() call for that attribute.
The best way to picture this is that when you make this call:
glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
you’re specifying all the state needed to tell OpenGL where to get the data for attribute 0 (first argument) from, and how to read it. Most of that state is given directly by the arguments:
- it has 3 components
- the components are float values
- vertices are read with a stride of 20 bytes…
- … and starting at byte 0 of the buffer
But there’s an additional implied piece of state that is also stored away for attribute 0 when you make the call:
- the data is read from the buffer currently bound to
In other words, the state associated with each attribute includes the id of the buffer the attribute data is sourced from. This can be the same buffer for multiple/all attributes, or it can be a different buffer for each attribute.
Note that the same is not true for
GL_ELEMENT_ARRAY_BUFFER. That one needs to be bound at the time of the
glDrawElements() call. While it seems somewhat inconsistent, this is necessary because there’s no equivalent to
glVertexAttribPointer() for the index array. The API could have been defined to have this kind of call, but… it was not. The reason is most likely that it was simply not necessary, since only one index array can be used for a draw call, while multiple vertex buffers can be used.