使用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
相关产品推荐
相关产品推荐

