You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用glBufferSubData绘制单个三角形失败,触发GL_INVALID_OPERATION错误

OpenGL glDrawArrays 报 GL_INVALID_OPERATION 错误(单缓冲区重构后空白)

尝试将双缓冲区存储顶点数据的OpenGL程序重构为单缓冲区(通过两次glBufferSubData填充数据),但绘制后屏幕空白,调试日志报错:

GL CALLBACK: ** GL ERROR ** type = 0x824c, severity = 0x9146, message = GL_INVALID_OPERATION in glDrawArrays

查阅文档后无法理解为何提示“缓冲区数据存储当前处于映射状态”,核心代码及着色器如下。


问题根源

错误出在VAO(顶点数组对象)的状态管理上:

  • 在init函数中,绑定VAO后配置了顶点属性指针,但随后调用glDisableVertexAttribArray(0)和glDisableVertexAttribArray(1),这会把“顶点属性数组禁用”的状态保存到VAO中。
  • 在display函数中,直接绑定VBO并启用属性,但此时未绑定VAO,这些启用操作不会被记录到VAO;绘制时VAO的属性数组仍处于禁用状态,导致OpenGL无法读取顶点数据,进而触发GL_INVALID_OPERATION错误。

另外,display函数中手动绑定VBO是多余的——VAO已经记录了顶点属性对应的VBO关联信息,只需绑定VAO即可恢复所有顶点配置。


修复代码

修复后的init函数

void init(GLWrapper* glw) {
    // Generate index (name) for one vertex array object
    glGenVertexArrays(1, &vao);

    // Create the vertex array object and make it current
    glBindVertexArray(vao);

    // Generate a name for a vertex buffer object
    glGenBuffers(1, &generalBufferObject);
    glBindBuffer(GL_ARRAY_BUFFER, generalBufferObject);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions) + sizeof(vertexColours), NULL, GL_DYNAMIC_DRAW);
    // Fill the buffer with { xyzxyzxyz rgbrgbrgb }
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertexPositions),
            vertexPositions);
    glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertexPositions),
            sizeof(vertexColours), vertexColours);

    // Tell the shaders where to look for vertex coordinates and colors
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, (void*)0);

    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0,
              (void*)sizeof(vertexPositions));

    // 移除禁用操作,让VAO保存属性数组的启用状态
    // glDisableVertexAttribArray(0);
    // glDisableVertexAttribArray(1);

    // Unbind VBO and VAO
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    try {
        // call to the wrapper
        program = glw->LoadShader("vert_attrib.vert", "vert_attrib.frag");
    } catch (exception& e) {
        cout << "Caught exception: " << e.what() << endl;
        cin.ignore();
        exit(0);
    }
}

修复后的display函数

void display() {
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(program);
    // 只需绑定VAO,自动恢复所有顶点属性配置(启用状态+VBO关联)
    glBindVertexArray(vao);

    glDrawArrays(GL_TRIANGLES, 0, 3);

    // 解绑VAO和程序
    glBindVertexArray(0);
    glUseProgram(0);
}

额外说明

  • VAO会保存以下状态:顶点属性数组的启用/禁用状态、glVertexAttribPointer的配置、以及对应的VBO绑定信息(通过glVertexAttribPointer时的当前GL_ARRAY_BUFFER绑定)。
  • 绘制时只需绑定VAO,无需重复配置顶点属性或绑定VBO,这也是VAO的核心作用——复用顶点配置状态。

内容的提问来源于stack exchange,提问作者Andriy Sultanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 21:24:52