why does binding a GL_ELEMENT_ARRAY_BUFFER to 0 pr

2019-04-01 18:40发布

问题:

I had a bug that took me quite some time to fix. I kept getting EXC_BAD_ACCESS and a reference to a memmove error without any further description until I commented the following line:

[self loadShaders];

glGenVertexArraysOES(1, &_vao);
glBindVertexArrayOES(_vao);

// Vertex Buffer
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);

glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);

glEnableVertexAttribArray(ATTRIB_TEXTURE);
glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));

// Index Buffer
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER,0);  

////////// COMMENTED THIS ONE //////////////
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);//
////////////////////////////////////////////

glBindVertexArrayOES(0);

I thought binding a buffer to 0 meant unbinding it, so I really cant understand how would that made my app crash.

Thanks for the information! I just do not stay with this concern...

My structures:

const Vertex Vertices[4] = {
    {{0.75, -1, 0}, {1, 0, 0, 1},     {0.125, 0.833496}},
    {{0.75, 1, 0}, {0, 1, 0, 1},      {0.125, 1}},
    {{-0.75, 1, 0}, {0, 0, 1, 1},     {0,     1}},
    {{-0.75, -1, 0}, {0, 0, 0, 1},    {0,     0.833496}},
};

const GLushort Indices[6] =
{
    0, 1, 2,
    2, 3, 0
};

回答1:

From your code, it looks as if this function is in some initialization routine, where you initialize your attribute data, which gets stored in the bound VAO, so that when drawing you only need to bind the VAO.

A VAO in turn encapsulates all the state needed for drawing VBOs, which is the enabled flags of your attributes (set by gl(En/Dis)ableVertexAttribArray), the attribute sources and properties (set with glVertexAttribPointer), and the currently bound index buffer (set with glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...)). Note that it doesn't store the currently bound vertex buffer, as this information is stored in the attribute state.

So what happens is, that you create and bind the index buffer, set its data, then unbind it, with the VAO still active. So the VAO state will store a GL_ELEMENT_ARRAY_BUFFER binding of 0. When you now draw something with

glBindVertexArrayOES(_vao);
glDrawElements(...);

there is no buffer bound and the glDrawElements fails, as VAOs don't work with client side arrays. You either have to use a VBO for the index data or draw non-indexed primitives (with glDrawArrays).

Neither will

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBindVertexArrayOES(_vao);
glDrawElements(...);

work, because the bound index buffer is overwritten by the VAO when it gets bound (whose index buffer is 0). It would work if you first bind the VAO and then the index buffer, but that would only circumvent the problem.

Conceptually the bound GL_ELEMENT_ARRAY_BUFFER is part of the VAO state, so you should not bind it to 0 in your VAO initialization routine (only if you don't need any index data). And neither are you allowed to use client side arrays for index or vertex data when using VAOs. If you don't want to draw indexed geometry though, just use glDrawArrays instead of glDrawElements, but then the index buffer is obsolete, anyway.