glDrawElements 抛出 GL_INVALID_VALUE 错误

Posted

技术标签:

【中文标题】glDrawElements 抛出 GL_INVALID_VALUE 错误【英文标题】:glDrawElements throw GL_INVALID_VALUE error 【发布时间】:2014-07-11 16:24:23 【问题描述】:

我正在尝试绘制我的平铺图像的一部分,但是当我调用 glDrawElements 函数时出现 GL_INVALID_VALUE 错误。当我用 glDrawArrays 改变这个函数时没有问题。问题是索引计数参数不是负数。

有一个代码:

#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】:

问题在于您的 setText() 方法中的以下(缩短的)调用序列:

glBindVertexArray(vao);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, ...);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    ...

glBindVertexArray(0);

GL_ELEMENT_ARRAY_BUFFER 的绑定是 VAO 状态的一部分。因此,通过在绑定 VAO 时进行此调用:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

您将 VAO 状态设置为具有0 的元素数组缓冲区绑定。因此,当您稍后在 draw() 方法中绑定 VAO 时,您将不会绑定 GL_ELEMENT_ARRAY_BUFFER

为避免这种情况,最简单的解决方案是删除该调用。如果您因为担心绑定它可能会对其他代码产生不良副作用而想显式取消绑定,则需要在取消绑定 VAO 后移动它:

glBindVertexArray(vao);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, ...);

    ...

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

【讨论】:

【参考方案2】:

在没有看到完整代码和知道确切的GL版本的情况下,我会尝试给你一个正确的答案。

首先,如果您使用的是 ES2,则默认情况下不支持将索引类型用作 GL_UNSIGNED_INT,但我认为这不是您的问题。

您的实际问题是元素数组实际上并未存储在您的 VAO 对象中,仅存储顶点数据配置。因此 glDrawElements 会给你这个错误,因为它会认为没有元素数组被绑定并且你将 NULL 作为索引参数传递给函数。

要解决这个问题,请在调用 glDrawElements 之前绑定适当的元素数组

【讨论】:

谢谢!我在 glDrawElements 之前添加了 glBindBuffer(GL_ELEMENT..) 并且它正在工作! GL_ELEMENT_ARRAY_BUFFER 的绑定实际上是 VAO 状态的一部分。这里的问题是代码在绑定 VAO 时显式地将其与glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) 解除绑定。如果您删除该调用,它就可以正常工作,而无需在绘制之前再次显式绑定元素缓冲区。这就是使用 VAO 的全部思想,您可以通过绑定 VAO 来设置整个状态。

以上是关于glDrawElements 抛出 GL_INVALID_VALUE 错误的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL:glDrawElements 不绘制

glDrawElements 崩溃

使用 glDrawElements 很难理解索引

glDrawElements中的index参数是啥意思?

OpenGL ES - glDrawElements - 无法理解索引

我不明白的 glDrawElements 的使用