一个大的OpenGL顶点缓冲区,或者多个小的
One big OpenGL vertex buffer, or many small ones?
假设我有5个实体(对象),方法为Render()
。每个实体都需要在缓冲区中设置自己的顶点以进行渲染。
以下两个选项中哪一个更好?
- 使用一个用
glGenBuffer
创建的大的预分配缓冲区,每个实体都将通过用glBufferSubData
将其顶点写入缓冲区来使用该缓冲区(作为参数传递给Render
方法的缓冲区的id) - 每个实体都创建并使用自己的缓冲区
如果一个大缓冲区更好,我如何使用适当的着色器和所有东西正确渲染该缓冲区中的所有顶点(来自所有实体)?
拥有多个VBO是可以的,只要它们有一定的大小。您希望避免的是有很多小的绘制调用,并且必须非常频繁地绑定不同的缓冲区。
为了避免过多的开销,缓冲区必须有多大取决于很多因素,甚至几乎不可能给出经验法则。起作用的因素包括:
- 硬件性能特征
- 驾驶员效率
- 相对于碎片数量的顶点数量(三角形大小)
- 着色器的复杂性
通常,将通常同时绘制的相似/相关对象保留在单个顶点缓冲区中是有意义的。
把所有东西放在一个缓冲区似乎很极端,事实上可能会产生不利影响。假设你有一个大的"世界",在那里你只渲染任何给定帧中的一个子集。如果你走到极致,将所有顶点都放在一个巨大的缓冲区中,GPU需要在每次绘制调用时都可以访问该缓冲区。根据体系结构和缓冲区的分配方式,这可能意味着:
- 试图将缓冲区保留在专用GPU内存(例如VRAM)中,如果缓冲区太大,可能会出现问题
- 将内存映射到GPU地址空间
- 固定/连接存储器
如果以上任何一项都需要应用于一个非常大的缓冲区,但最终只使用其中的一小部分来渲染帧,那么这些操作会造成很大的浪费。在具有VRAM的系统中,它还可以阻止其他分配,如纹理,以适应VRAM。
如果使用只能访问参数(如glDrawArrays()
或glDrawRangeElements()
)给定的缓冲区子集的调用来完成渲染,则驱动程序可能会避免使整个缓冲区GPU可访问。但我不一定指望会发生这种事。
为每个实体使用一个带有glGenBuffer
的VBO(顶点缓冲区对象)更容易,但这并不总是最好的做法,这取决于使用情况。但是,在大多数情况下,每个实体有一个VBO并不是问题,而且渲染很少受到影响。
好的信息位于:OpenGL顶点规范最佳实践
- C++字符*缓冲区的大小
- 为什么msgrcv()将垃圾字符馈送到缓冲区
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- ostream过载时的缓冲区冲洗
- C++中的高效循环缓冲区,它将被传递给C样式数组函数参数
- Xaudio2在更改缓冲区或循环时弹出声音
- 为什么我在leetcode上收到AddressSanitizer:地址0x602000000058上的堆缓冲区溢出错误
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- 如何在cpp.中使用协议缓冲区存储大缓冲区/数组(char/int)
- 多线程双缓冲区
- Android P-9.0.0_r53 Logcat主缓冲区超出定义大小
- 套接字读取后,我在缓冲区中看到意外输入
- std::带有自定义缓冲区的 iostream 不允许我写入
- 地图计数确实很重要,或者只是检查是否存在
- 从返回的顶点缓冲区查询顶点结构
- Vulkan 中的动态顶点缓冲区格式设置
- OpenGL 16 位模板缓冲区?
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 在 openGL 中多次绑定缓冲区
- 一个大的OpenGL顶点缓冲区,或者多个小的