我正在设计渲染引擎的排序部分。我知道更改渲染目标,着色器程序,纹理绑定等等都很昂贵,因此应该根据它们对绘制顺序进行排序以减少状态更改。但是,基于绑定了什么索引缓冲区进行排序,以及哪些顶点缓冲区用于属性呢?
我对这些感到困惑,因为VAO是强制性的,它们封装了所有这些状态。那么我应该窥视顶点数组对象(VAO)的场景,看看它们根据它设置和排序的状态?或者我应该不关心VAO的调用顺序?
这让我对顶点数组对象感到困惑。我有意义的是不要反复使用哪些缓冲区,而VAO似乎只是迫使人们不关心它。
对渲染/游戏引擎的内容进行排序是否存在一般性模糊或未达成一致意见?
我知道绑定一个缓冲区只是改变了一些全局状态,但是必须多次从同一个缓冲区中抽取硬件,可能是一些小的缓存一致性?
答案 0 :(得分:1)
虽然在没有GL_ARB_compatibility
或核心3.2+的GL 3.1中强制要求VAO,但您不必按照预期的方式使用它们......也就是说,您可以在一段时间内绑定单个VAO你的应用程序的生命周期,并继续绑定和取消绑定VBO等传统的方式,如果这以某种方式让你的生活更轻松。 Valve因提倡在 their presentation on porting the Source engine from D3D to GL 中这样做而闻名...但我倾向于在某些方面不同意他们。他们在演示文稿中提到的很多内容让我感到畏缩,因为他有多年的经验 D3D和OpenGL;他们正在就如何将某些东西移植到API上提出建议,他们对这些API的工作知识很少。
回到您的性能问题,可能会有频繁更改绑定资源的验证开销,因此它实际上不仅仅是"只是更改全局状态。" 所有GL命令都必须进行验证,以确定是否需要设置错误状态。它们将验证您的输入参数(这非常简单),以及命令需要使用的任何资源的状态(这可能很复杂)。
其他类型的GL对象(如FBO,纹理和GLSL程序)具有比缓冲对象和顶点数组更严格的验证和更复杂的内存依赖性。交换顶点指针在宏观方案中应该比大多数其他类型的对象绑定更便宜,特别是因为在实际发出glDrawElements (...)
命令之前,实现可以推迟很多东西。
然而,解决此问题的最佳方法是增加顶点缓冲区的重用。对于顶点缓冲区来说,对象重用是相当高的,如果在场景中有200个相同的不透明模型实例,则可以背对背地绘制所有200个实例,而不必更改顶点指针。材料往往比实际顶点缓冲区更频繁地更改,因此您通常首先按照材质对图形进行排序(按照关联状态(如不透明/半透明,纹理,着色器等)进行子排序) 。您可以向批次排序添加另一个级别,以便在按材料排序后绘制共享相同顶点数据的所有批次。最终目标通常是尽量减少完成框架所需的绘图命令数量,并且使用优先级/基于层次结构的排序,重点放在材料上通常可以提供最佳结果。
此外,如果您可以将模型的多个LOD拟合到单个顶点缓冲区中,而不是在不同的顶点缓冲区之间交换,有时您可以只绘制不同的索引集,甚至只是绘制不同的范围来自单个索引缓冲区的索引。以非常类似的方式,通过使用填充纹理图集/精灵图片而不是每个纹理的单个纹理对象,可以减轻纹理交换压力。
你绝对可以通过减少对顶点数组状态的更改次数来挤出一些性能,但这里的外卖消息是顶点数组状态与许多频繁更改的其他状态相比相当便宜。如果你可以快速实现二级排序来减少顶点状态的变化,那就去吧,但除非你知道它是一个瓶颈,否则我不会在更复杂的东西上投入大量的时间。首先优先考虑纹理,着色器和帧缓冲状态。