glDrawElements throw GL_INVALID_VALUE error

2019-07-21 05:05发布

问题:

I am trying to draw part of my tile image but I am getting GL_INVALID_VALUE error when I call glDrawElements function. There is no problem when I change this function with glDrawArrays. The problem is that the indices count parameter is not negative number.

There is a code:

#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
 #define VERTEX_ATTR_PTR(loc, count, member, type) \
    glEnableVertexAttribArray(loc); \
    glVertexAttribPointer(loc, count, GL_FLOAT, GL_FALSE, sizeof(type),  BUFFER_OFFSET(offsetof(struct type, member)))
// ---------- TextRenderer
void TextRenderer::setText(const string& text) {
    vector<Vertex2f> vertex_buffer;
    vector<GLuint> index_buffer;

    GLfloat cursor = 0.f;
    FPoint2D cell_size = font->getCellSize();

    for (char c : text) {
        TILE_ITER iter = font->getCharacter(c);
        {
            // UV
            for (GLuint i = 0; i < 4; ++i) {
                TILE_ITER _v = iter + i;
                vertex_buffer.push_back( {
                        {
                                _v->pos[0]  + cursor,
                                _v->pos[1],
                                _v->pos[2]
                        },
                        { _v->uv[0], _v->uv[1] }
                });
            }
            // Index
            for (GLuint i = 0; i < 6; ++i)
                index_buffer.push_back(
                        Tile::indices[i] + vertex_buffer.size() - 4);
        }
        cursor += cell_size.X;
    }

    vertices_count = vertex_buffer.size();
    indices_count = index_buffer.size();

    glBindVertexArray(vao);
    {
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
        glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,
                0,
                indices_count * sizeof(GLuint),
                &index_buffer[0]);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferSubData(GL_ARRAY_BUFFER,
                0,
                vertices_count * sizeof(Vertex2f),
                &vertex_buffer[0]);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
    glBindVertexArray(0);
}
void TextRenderer::create() {
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    {
        indices = genGLBuffer( {
                nullptr,
                BUFFER_SIZE / 2 * sizeof(GLuint),
                GL_ELEMENT_ARRAY_BUFFER
        }, true, GL_DYNAMIC_DRAW);

        vbo = genGLBuffer( {
                nullptr,
                BUFFER_SIZE * sizeof(Vertex2f),
                GL_ARRAY_BUFFER
        }, true, GL_DYNAMIC_DRAW);

        VERTEX_ATTR_PTR(0, 3, pos, Vertex2f); // Vertex
        VERTEX_ATTR_PTR(1, 2, uv, Vertex2f); // UV
    }
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    setText("DUPA");
}
void TextRenderer::draw(MatrixStack& matrix, GLint) {
    static Shader shader(
            getFileContents("shaders/text_frag.glsl"),
            getFileContents("shaders/text_vert.glsl"),
            "");

    shader.begin();
    shader.setUniform(GL_TEXTURE_2D, "texture", 0,
            font->getHandle());
    shader.setUniform("matrix.mvp", matrix.vp_matrix * matrix.model);
    shader.setUniform("col", col);
    {
        glBindVertexArray(vao);
        //glDrawArrays(GL_LINE_STRIP, 0, vertices_count);
        glDrawElements(GL_LINES, indices_count, GL_UNSIGNED_INT,
                nullptr);
        glBindVertexArray(0);
        showGLErrors();
    }
    shader.end();
}

回答1:

The problem is with the following (shortened) call sequence in your setText() method:

glBindVertexArray(vao);
{
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, ...);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    ...
}
glBindVertexArray(0);

The binding of the GL_ELEMENT_ARRAY_BUFFER is part of the VAO state. So by making this call while the VAO is bound:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

you're setting the VAO state to have an element array buffer binding of 0. So when you later bind the VAO in your draw() method, you won't have a binding for GL_ELEMENT_ARRAY_BUFFER.

To avoid this, the simplest solution is to just remove that call. If you want to explicitly unbind it because you're worried that having it bound might have undesired side effects on other code, you need to move it after unbinding the VAO:

glBindVertexArray(vao);
{
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, ...);

    ...
}
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);


回答2:

Without seeing the whole code and knowing exact GL version, I will attempt to give you a correct answer.

First, if you're using ES2 then using index type as GL_UNSIGNED_INT is not supported by default, however I don't think that's your problem.

Your actual issue is that element arrays are actually not stored in your VAO object, only vertex data configuration. Therefore glDrawElements will give you this error as it will think no element array is bound and you passed NULL as indices argument to the function.

To solve this, bind the appropriate element array before you call glDrawElements



标签: c++ opengl vbo vao