这个问题很广泛,所以我会努力让它尽可能准确。
我编写的程序加载并渲染一个具有多个纹理的模型。由于我使用单一模型,我能够形成所有缓冲区,启用所有顶点属性数组,绑定所有顶点数组,并在负责绘制的循环之前绑定和设置活动纹理。
因此,我在绘图循环的每次迭代中的程序只执行单行glDrawArrays。在大量对象的情况下也可以这样做,或者我需要在绘制循环的每次迭代中形成所有缓冲区,启用attrib数组,绑定和设置活动纹理,设置着色器程序等(这意味着向视频发送大量数据)卡应该慢?)
答案 0 :(得分:5)
目前还不清楚你究竟在寻找什么 - 以及我们谈论的对象数量。
因此,我在绘图循环的每次迭代中的程序只执行单行glDrawArrays。在大量对象的情况下也可以这样做,或者我需要在绘制循环的每次迭代中形成所有缓冲区,启用attrib数组,绑定和设置活动纹理,设置着色器程序等(这意味着向视频发送大量数据)卡应该慢?)
是的,那会很慢。缓冲区对象允许您以GL可访问的方式存储数据。在理想情况下,GL可以决定将数据直接存储在VRAM中(尽管您从未完全控制过OpenGL)。因此,如果您有静态的,不变的网格数据,那么上传一次就是最佳选择。在单个缓冲区中合并许多小对象的数据也可能很有用。
您可以使用Vertex Array Objects (VAOs)存储顶点属性指针并启用,因此在绘制时,您可以绑定VAO并发出绘制调用。因此,渲染多个对象的基本方法是
// ... at initinialization
for each object:
create and upload VBO(s) and index buffers
create and upload textures
create and initialize VAO
// at draw time
for each object:
bind VAO
bind texture(s)
set all other object-related OpenGL state
(like switching programs, setting unforms for
the model matrix, base colors, ...)
glDraw*(...)
如果每帧只绘制几百个对象,则使用此方法可能不会遇到性能问题。 (这里不要误解我,我只是谈到每个对象的单个绘图调用的开销,而不是实际对象的渲染成本 - 如果你的对象有数百万个顶点,或者你正在生成很多片段,你仍然可以用很少或一个对象来降低性能。在这种情况下,你需要一个更聪明的策略来有效地渲染你自己的对象,例如通过应用细节层次方法)
通常,有两种主要方法可以改善这种渲染循环的性能:
减少状态更改次数。
切换不同的GL状态意味着性能损失。 标准方法是对每个对象进行分组 着色器程序,纹理等可以绘制多个 没有昂贵的状态开关的对象。
查看this answer to a related question了解不同状态变化的相对成本。
增加单次绘制调用绘制的对象数。 在某种程度上,这也意味着方法1,因为你无法切换 绘制调用期间的OpenGL状态。但是,使用现代GL,您可以使用数组纹理并将不同对象的纹理放入单个纹理对象中(您也可以通过使用纹理类来完成没有纹理数组,并且可以将它们组合在一起)。
这方面的其他非常有趣的功能是
近年来,已经提出了一些有效渲染许多对象的策略,这些对象在标题Approaching Zero Driver Overhead (AZDO)下已知。