一个大的OpenGL顶点缓冲区,或者多个小的

One big OpenGL vertex buffer, or many small ones?

本文关键字:缓冲区 或者 顶点 OpenGL 一个      更新时间:2023-10-16

假设我有5个实体(对象),方法为Render()。每个实体都需要在缓冲区中设置自己的顶点以进行渲染。

以下两个选项中哪一个更好?

  1. 使用一个用glGenBuffer创建的大的预分配缓冲区,每个实体都将通过用glBufferSubData将其顶点写入缓冲区来使用该缓冲区(作为参数传递给Render方法的缓冲区的id)
  2. 每个实体都创建并使用自己的缓冲区

如果一个大缓冲区更好,我如何使用适当的着色器和所有东西正确渲染该缓冲区中的所有顶点(来自所有实体)?

拥有多个VBO是可以的,只要它们有一定的大小。您希望避免的是有很多小的绘制调用,并且必须非常频繁地绑定不同的缓冲区。

为了避免过多的开销,缓冲区必须有多大取决于很多因素,甚至几乎不可能给出经验法则。起作用的因素包括:

  • 硬件性能特征
  • 驾驶员效率
  • 相对于碎片数量的顶点数量(三角形大小)
  • 着色器的复杂性

通常,将通常同时绘制的相似/相关对象保留在单个顶点缓冲区中是有意义的。

把所有东西放在一个缓冲区似乎很极端,事实上可能会产生不利影响。假设你有一个大的"世界",在那里你只渲染任何给定帧中的一个子集。如果你走到极致,将所有顶点都放在一个巨大的缓冲区中,GPU需要在每次绘制调用时都可以访问该缓冲区。根据体系结构和缓冲区的分配方式,这可能意味着:

  • 试图将缓冲区保留在专用GPU内存(例如VRAM)中,如果缓冲区太大,可能会出现问题
  • 将内存映射到GPU地址空间
  • 固定/连接存储器

如果以上任何一项都需要应用于一个非常大的缓冲区,但最终只使用其中的一小部分来渲染帧,那么这些操作会造成很大的浪费。在具有VRAM的系统中,它还可以阻止其他分配,如纹理,以适应VRAM。

如果使用只能访问参数(如glDrawArrays()glDrawRangeElements())给定的缓冲区子集的调用来完成渲染,则驱动程序可能会避免使整个缓冲区GPU可访问。但我不一定指望会发生这种事。

为每个实体使用一个带有glGenBuffer的VBO(顶点缓冲区对象)更容易,但这并不总是最好的做法,这取决于使用情况。但是,在大多数情况下,每个实体有一个VBO并不是问题,而且渲染很少受到影响。

好的信息位于:OpenGL顶点规范最佳实践