我可以在更新同一个“GL_ARRAY_BUFFER”时多次调用“glDrawArrays”吗?

Posted

技术标签:

【中文标题】我可以在更新同一个“GL_ARRAY_BUFFER”时多次调用“glDrawArrays”吗?【英文标题】:Can I call `glDrawArrays` multiple times while updating the same `GL_ARRAY_BUFFER`? 【发布时间】:2015-10-19 18:12:13 【问题描述】:

在单个帧中,是否“允许”连续更新相同的GL_ARRAY_BUFFER 并在每次更新后继续调用glDrawArrays

我知道这可能不是最好的,也不是最推荐的方法,但我的问题是:我可以这样做并期望在每次调用 glDrawArrays 之前更新 GL_ARRAY_BUFFER 吗?

代码示例如下所示:

// setup a single buffer and bind it
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);

while (!renderStack.empty())

    SomeObjectClass * my_object = renderStack.back();
    renderStack.pop_back();

    // calculate the current buffer size for data to be drawn in this iteration
    SomeDataArrays * subArrays = my_object->arrayData();
    unsigned int totalBufferSize = subArrays->bufferSize();
    unsigned int vertCount = my_object->vertexCount();

    // initialise the buffer to the desired size and content
    glBufferData(GL_ARRAY_BUFFER, totalBufferSize, NULL, GL_STREAM_DRAW);

    // actually transfer some data to the GPU through glBufferSubData
    for (int j = 0; j < subArrays->size(); ++j)
    
        unsigned int subBufferOffset = subArrays->get(j)->bufferOffset();
        unsigned int subBufferSize = subArrays->get(j)->bufferSize();
        void * subBufferData = subArrays->get(j)->bufferData();

        glBufferSubData(GL_ARRAY_BUFFER, subBufferOffset, subBufferSize, subBufferData);

        unsigned int subAttributeLocation = subArrays->get(j)->attributeLocation();

        // set some vertex attribute pointers
        glVertexAttribPointer(subAttributeLocation, ...);
        glEnableVertexAttribArray(subAttributeLocation, ...);
    

    glDrawArrays(GL_POINTS, 0, (GLsizei)vertCount);

您可能会问 - 我为什么要这样做,而不是一次将所有内容预加载到 GPU 上……嗯,很明显的答案,因为当有太多数据无法容纳时,我不能这样做到单个缓冲区中。

我的问题是,我只能看到glDrawArrays 调用之一的结果(我相信第一个),或者换句话说,看起来好像GL_ARRAY_BUFFER 是在每次glDrawArrays 调用之前没有更新,这让我回到了我的问题,如果这可能的话。

我正在使用 OpenGL 3.2 CoreProfile(在 OS X 下)并与 GLEW 链接以进行 OpenGL 设置以及 Qt 5 以设置窗口创建。

【问题讨论】:

你试过glBufferSubData 是的,我实际上是在使用glBufferSubData 复制缓冲区的不同部分,但我仍然需要调用glBufferData 来调整它的大小......无论哪种方式 - 哪个有区别我打电话问我的问题? @Chris:你的方法是有效的。 GL 将完成所有必要的隐式同步,以便为您工作。实际上,由于调用 glBufferData() 为缓冲区对象分配了一个新的存储空间,因此无需任何进一步的同步就可以实现合理的实现,因此该方法甚至不应该像您想象的那么糟糕(但您也不能依赖它)。我不知道你的情况出了什么问题,但我可以明确确认缓冲区更新本身不是问题。 @derhass 感谢您的确认,您可以想象使用包含数百万个点的数据集进行调试有点痛苦……我扩展了我的示例以表明我也在使用 @987654332 @ 转移部分缓冲区,但我认为这也不会产生任何影响,对吧? @Chris:BufferSubData 部分没问题(假设您的尺寸和偏移量正确)。但是,代码没有意义,因为您在内部循环中设置了VertexAttribPointer。只有最后一个有效,当你最后调用DrawArrays 【参考方案1】:

是的,这是合法的 OpenGL 代码。这绝不是任何人真正应该做的事情。但这是合法的。实际上,在您的情况下,它甚至更没有意义,因为您正在为每个对象调用 glVertexAttribPointer

如果您无法将所有顶点数据放入内存,或者需要在 GPU 上生成,那么您应该使用正确的buffer streaming techniques 流式传输数据。

【讨论】:

以上是关于我可以在更新同一个“GL_ARRAY_BUFFER”时多次调用“glDrawArrays”吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 OpenGL ES 2 中更新 VBO 的顶点

在模拟中使用 GL_ARRAY_BUFFER 时屏幕锁定

glUnmapBuffer(GL_ARRAY_BUFFER) 与 glBindBuffer(GL_ARRAY_BUFFER,0)

OpenGL 如何知道它应该根据 GL_ARRAY_BUFFER 将顶点绘制到啥位置?

慢跑。 OpenGL。如何更新 VBO?

每帧多次调用 glBufferSubData