【问题标题】:The best way to use VBOs [closed]使用 VBO 的最佳方式 [关闭]
【发布时间】:2013-04-10 10:17:37
【问题描述】:

最快、最灵活(适用于大多数情况)的 VBO 使用方法是什么?

我正在开发一个 openGL 应用程序,我希望它能够达到最佳性能,所以我需要有人来回答这些问题。我阅读了很多问题和答案,但我想有太多我不需要的信息会弄乱我的大脑......

  • 我应该使用多少个 vbo?
  • 我应该如何创建 vbos?
  • 如果数据大小不固定,我应该如何更新 vbos 数据?
  • 我应该如何渲染 vbos?
  • 我应该如何处理 vbo 中不想再渲染的数据?

【问题讨论】:

  • 您的许多问题都没有有效的答案。任何此类答案都将是特定于硬件的。

标签: opengl vbo


【解决方案1】:
  • 我应该使用多少个 vbo?

尽可能少。切换 VBO 的成本虽小,但可衡量。通常,您会尝试将相似的数据分组到 VBO 中。例如在 FPS 游戏中,所有不同种类的街头垃圾、小道具等,通常会位于相同或仅少数几个 VBO 中。

这也归结为绘制批量大小。 glDraw… 渲染少于大约 100 个基元的调用是次优的(即使在 15 年前也是如此)。因此,您希望尽可能批处理至少 100 个基元。但是,如果单个网格只有 20 个三角形(用于实例化的低多边形道具等),每个都在其自己的 VBO 中,您不能再批量处理更多。

  • 我应该如何创建 vbos?

glGenBuffers → glBindBuffer → glBufferData

更新你可以传递一个空指针给glBufferData的data参数来初始化缓冲区对象而不需要设置数据。

  • 如果数据大小不固定,我应该如何更新 vbos 数据?

创建比您的数据大小更粗的 VBO。无论如何,您的操作系统都会为您的主机端数据执行此操作,这称为分页。此外,如果您想使用 glMapBuffer 将缓冲区对象设置为主机页面大小的倍数,这对整个系统来说非常好。

当前系统上通常的页面大小是 4kiB。这就是我选择的 VBO 大小粒度。 更新:您可以顺便问一下您的操作系统它正在使用哪个页面大小。不过,这取决于操作系统,我会问另一个问题。

使用 glBufferSubData 更新数据或使用 glMapBuffer 在主机端映射内存中修改映射,然后使用 glUnmapBuffer。

如果数据超出缓冲区对象,则创建一个新的更大的对象并使用 glCopyBufferSubData 进行复制。见最后一段。

  • 我应该如何渲染 vbos?

glBindBuffer → glDraw…

  • 我应该如何处理 vbo 中不想再渲染的数据?

如果数据仅消耗 VBO 的一部分并与其他数据共享,并且您没有耗尽内存,那么,请不要访问它。理想情况下,您保留一些索引,您可以在其中跟踪哪个 VBO 的哪些部分可用于哪种任务。这很像内存管理,特别是一种称为对象堆栈(obstacks)的方案。

然而,最终压缩现有的缓冲区对象可能是有意义的。为此,您将创建一个新的缓冲区对象,将其绑定为写入目标,并选择旧的缓冲区对象作为读取目标。然后使用 glCopyBufferSubData 将内容复制到一个新的、紧缩的缓冲区对象中。当然,您必须更新所有对缓冲区对象名称(=OpenGL ID)和偏移量的引用。

因此,在 OpenGL 缓冲区对象之上编写一个薄抽象层是有意义的,它跟踪 OpenGL 缓冲区对象所在的无结构 blob 中的实际类型数据。

【讨论】:

  • 你确定使用 4kiB 的大小不会导致我的程序有太多的 vbos 吗?
  • @visDEVion:我并不是说您的 VBO 的大小应该正好是 4kiB,而是 4kiB 的倍数(即四舍五入到 4096 的下一个更高倍数)。假设您需要 10kiB 的内存,那么您将分配一个 14kiB 大小的 VBO。
  • 啊...看,我为静态和动态对象创建了 4mb 大小的 vbo。如果 vbo 已满,我会创建一个相同大小的新文件,然后将所有新数据添加到其中。你怎么看?
  • “假设您需要 10kiB 的内存,那么您将分配一个 14kiB 大小的 VBO。”它不应该是 12kiB 大小吗?
  • @visDEVion:啊,我有一个瞬间失灵。是的,它应该是 12kiB 大小,是的。 (对于 2kiB 的页面大小来说,10kiB 是有意义的)。
【解决方案2】:

我应该使用多少个 vbo?

只要你需要,听起来很傻,但很好,就是这样

如果数据大小不固定,我应该如何更新 vbos 数据?

用不同的数据和长度覆盖并渲染相同的 VBO。

我应该如何创建 vbos?

我应该如何渲染 vbos?

见VBO tutorial

我应该如何处理 vbo 中不想再渲染的数据?

创建一个新的 vbo 并将数据复制到其中或仅渲染该 vbo 在内存中的部分内容。

要仅渲染部分,请参阅glVertexBufferglTexCoordPointer(只需根据偏移量计算新指针和新大小)

编辑 1:

对所有事情都使用单个 VBO 感觉不对,因为您必须自己管理新顶点位置/纹理坐标的分配,这很快就会变得非常混乱。

最好将小道具分组到VBO中并批量绘制命令。

我可以使用 glBufferSubData 向缓冲区添加数据(向大小为 x 的缓冲区添加 100 个元素)吗?

不,这是不可能的,因为描述说 updates a subset of a buffer object's data store 并且子集是集合中的一个较小的集合。

编辑 2

Learning Modern 3D Graphics Programming 也是一个很好的教程,但它不是 VBO 特定的。

【讨论】:

  • 你能给我一些关于创建 vbo 的信息吗?我正在考虑对所有内容使用单个 vbo。据我所知,你不能在不打电话给glBufferData 之前打电话给glBufferSubData。如果以后要添加所有数据,我应该将哪些数据添加到 vbo?如果在示例中存储到 vbo 的数据大小为 100,我可以使用 glBufferSubData 添加大小为 200 的数据吗?
  • 哦,还有每帧上一些网格变化的数量。我还应该创建一个新的 vbo 来处理它吗?
  • -1:推荐NeHe过时的教程。
  • @Quonux:arcsynthesis.org/gltut 怎么样——由 Nicol Bolas 撰写。
  • @Quonux:顺便说一句,您的回答充满了不好的建议。你不应该为每一件小事都创建一个 VBO。切换 VBO 会影响性能。不是很大,但如果你在一个大场景中为每个单独的道具分配一个 VBO,那会很受伤。
猜你喜欢
  • 1970-01-01
  • 2021-12-27
  • 1970-01-01
  • 1970-01-01
  • 2020-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多