代码之家  ›  专栏  ›  技术社区  ›  Mati Bagiński

glDrawElements引发GL_INVALID_VALUE错误

  •  2
  • Mati Bagiński  · 技术社区  · 10 年前

    我试图绘制部分平铺图像,但在调用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();
    }
    
    2 回复  |  直到 5 年前
        1
  •  4
  •   Reto Koradi    10 年前

    问题在于您的 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 。因此,当您稍后将VAO绑定到 draw() 方法,您将没有绑定 GL_元素数组缓冲区 .

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

    glBindVertexArray(vao);
    {
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
        glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, ...);
    
        ...
    }
    glBindVertexArray(0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    
        2
  •  1
  •   user3747345    10 年前

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

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

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

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