OpenGL:多次调用glDrawArrays()仅显示首次调用结果?
解决多网格循环渲染仅显示第一个的问题
嘿,这个问题我之前也碰到过——用相同顶点属性配置渲染多个VBO时,只有第一个网格显示,大概率是OpenGL的状态管理没做好。结合你的代码结构,我给你梳理几个最可能的原因和解决办法:
1. 核心问题:未正确绑定每个网格的VBO或使用VAO管理状态
OpenGL的glVertexAttribPointer会把当前绑定的GL_ARRAY_BUFFER和顶点属性关联起来,但很多人误以为设置一次就可以通用所有VBO。实际上,如果你在循环中没有为每个网格重新绑定对应的VBO,所有绘制调用都会复用第一个绑定的VBO的数据,自然只会看到第一个网格。
最优解:用VAO管理每个网格的状态
VAO(Vertex Array Object)是专门用来保存顶点属性配置和对应VBO绑定状态的,每个网格只需要创建一次VAO,渲染时直接绑定就行,不用重复设置顶点属性,既高效又不容易出错。
给你改一下代码示例:
// 初始化阶段(程序启动时执行一次) std::vector<GLuint> mesh_vaos; std::vector<GLuint> mesh_vbos; std::vector<int> mesh_vertex_counts; // 假设你已经有了每个网格的顶点数据和顶点数 const int mesh_count = sConfig.mRendering.isRenderTypeActive(RENDER_TYPE_TWO_MESH)? 2 : 1; mesh_vaos.resize(mesh_count); mesh_vbos.resize(mesh_count); mesh_vertex_counts.resize(mesh_count); for (int i = 0; i < mesh_count; i++) { // 创建VAO和VBO glGenVertexArrays(1, &mesh_vaos[i]); glGenBuffers(1, &mesh_vbos[i]); // 绑定VAO(后续的顶点属性设置都会存在这个VAO里) glBindVertexArray(mesh_vaos[i]); // 绑定当前网格的VBO并上传数据 glBindBuffer(GL_ARRAY_BUFFER, mesh_vbos[i]); // 这里替换成你自己的顶点数据和顶点数 glBufferData(GL_ARRAY_BUFFER, mesh_vertex_counts[i] * sizeof(YourVertexType), your_vertex_data[i], GL_STATIC_DRAW); // 设置顶点属性(和你原来的glVertexAttribPointer完全一致) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(YourVertexType), (void*)offsetof(YourVertexType, position)); glEnableVertexAttribArray(0); // 如果有其他属性(比如颜色、UV),同样在这里设置 // 解绑VAO和VBO(好习惯,避免后续操作污染状态) glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); } // 渲染阶段的循环 if (sConfig.mRendering.isRenderTypeActive(RENDER_TYPE_SINGLE_MESH) || sConfig.mRendering.isRenderTypeActive(RENDER_TYPE_TWO_MESH)) { const int mesh_count = sConfig.mRendering.isRenderTypeActive(RENDER_TYPE_TWO_MESH)? 2 : 1; for (int i = 0; i < mesh_count; i++) { std::lock_guard<std::mutex> lock(...); // 你的锁逻辑 // 只需要绑定当前网格的VAO,所有状态都会自动恢复 glBindVertexArray(mesh_vaos[i]); // 调用glDrawArrays时传入当前网格的顶点数 glDrawArrays(GL_TRIANGLES, 0, mesh_vertex_counts[i]); glBindVertexArray(0); } }
2. 检查绘制时的顶点数量是否正确
如果你的所有网格都用了同一个顶点数调用glDrawArrays,而后面的网格顶点数为0或者和第一个网格不匹配,就会导致后面的网格无法渲染。一定要确保每个网格都有对应的顶点数变量,并且在绘制时传入正确的值。
3. 验证VBO数据是否正确上传
别忽略这个基础问题——检查每个网格的VBO是否都正确执行了glBufferData:
- 确认你的顶点数据数组不为空,数据格式正确(比如float数组没有越界)
- 确认
glBufferData的大小参数计算正确(比如顶点数 * 单个顶点字节数) - 可以用
glGetBufferSubData读取VBO中的数据,和原始顶点数据对比,验证是否上传成功
4. 排查渲染状态问题
有时候不是VBO的问题,是渲染状态导致的:
- 深度测试:如果后面的网格被第一个完全遮挡,且没开启深度测试,就会看不到。在渲染初始化时加一句
glEnable(GL_DEPTH_TEST);试试。 - 着色器Uniform:如果你的着色器用了模型矩阵、颜色等Uniform,要确保每个网格绘制前都更新了对应的Uniform值——不然后面的网格可能和第一个完全重合,看起来没渲染。
- 绘制顺序:如果关闭了深度测试,绘制顺序会影响结果,后绘制的网格会覆盖先绘制的。如果场景需要,调整顺序或者开启深度测试。
内容的提问来源于stack exchange,提问作者Scott Mudge
相关产品推荐
相关产品推荐

