【问题标题】:Can I call `glDrawArrays` multiple times while updating the same `GL_ARRAY_BUFFER`?我可以在更新同一个“GL_ARRAY_BUFFER”时多次调用“glDrawArrays”吗?
【发布时间】: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

标签: c++ opengl rendering opengl-3


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-17
    • 1970-01-01
    • 2011-03-01
    • 2016-02-17
    • 1970-01-01
    • 2012-06-29
    相关资源
    最近更新 更多