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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:34:51