了解 OpenGL 中的绑定/激活纹理性能损失

Wat*_*ter 1 c++ opengl

我不确定我所做的是否是最佳的。

我有三个纹理(其中两个是堆叠有大量信息的数组纹理)并且我执行了三个渲染通道:

  • 具有纹理 1 的关卡几何体

  • 具有纹理 2 的世界实体

  • 带有纹理 3 的 HUD 东西

因此,我的代码通常会执行类似以下伪代码的操作:

bindTexture(tex1);
drawLevel();
unbindTexture(tex1);  // Is this necessary if I just bind after anyways?

bindTexture(tex2);
drawEntities();
unbindTexture(tex2);

bindTexture(tex3);
drawHUD();
unbindTexture(tex3);
Run Code Online (Sandbox Code Playgroud)

因为我记得在 GL_TEXTURE0、GL_TEXTURE1 等上看到最多允许 16 个(或更多)单独的纹理,这是否意味着我可以将我的世界纹理写入 GL_TEXTURE0,将实体写入 GL_TEXTURE1,将 HUD 写入 GL_TEXTURE2 并且没有性能罚款,还是很少?或者甚至改变活动纹理是否会带来明显的惩罚?

我问是因为我记得看到纹理交换是一项繁重的操作。这是否意味着即使我改变了我的活动纹理,它仍然很费力?或者,如果您有超过 16 个左右的纹理并不断将它们推送到 GPU,它是否只是繁重?

这是错误的还是缓慢的?

我只需要 3 个纹理,所以如果有最优化的方法来做这件事,我会很高兴学习它。

假设我使用的是核心 3.3 而不是 4.5(但如果在 4.2 或更高版本中有更好的方法,我也很乐意听到这些)。它也应该适用于 nvidia 和 AMD 或过去 4-5 年发布的任何 GPU。

编辑:如果你注意到我说的任何奇怪的概念是错误的,请纠正我,因为我是新手。由于这个原因,我更希望有人在他们的回答中冗长。

Xir*_*ema 5

我认为关于 OpenGL 中的活动纹理存在少量混淆。什么OpenGL的让你做的是有多达16个主动纹理的同时编辑:每个着色器级)。因此,您可以同时拥有多达 16 个纹理的单个绘制调用引用(并且某些实现将允许超过 16 个)。

您可以在程序中创建和激活的纹理数量没有限制(物理 VRAM 限制除外)。更重要的是,大多数 OpenGL 驱动程序都围绕这样一个假设进行了优化:您将为每个单独的绘制调用绑定一个新纹理(或可能多个)。

更改活动纹理是一个相对昂贵的过程,但不是在您使用它的上下文中。例如,如果每个实体都有多个纹理要引用,并且每个实体都是一个很小的对象,否则不会花费太多精力来渲染,这将很重要。当您实际上将所有纹理捆绑到 3 个“巨型纹理”中并且仅在从一组对象移动到下一组时才切换时,它就不那么重要了。在这种情况下,切换纹理的成本微不足道,不值得关注。

我会说这看起来有点像过早优化的情况,因为将所有内容捆绑在一起可能代表工作负载足迹可能超过您从最终结果中获得的好处,但这是您的决心必须自己做。

但是,TL;DR:您的代码在功能或性能方面没有任何问题。