我有几个具有统一变量的着色器,它们在所有着色器中具有相同的名称。一次在所有着色器中更新具有相同名称的制服的最佳方法是什么?我考虑以下方法:
1)只需为每个程序存储该制服的位置,并在程序被分配为“已使用”程序后立即更新它 ( glUseProgram
)。
缺点:所有“共享”的统一变量将在每次glUseProgram
调用后更新。此外,如果在当前帧期间不是第一次使用程序,所有glUniform*
调用都将是多余的。或者,应该有一组标志来判断程序是否是第一次使用。“未使用”标志应每帧重置。
2)使用统一的缓冲区和shared
(甚至std140
)布局。在这种方法中,我们可以立即设置统一,然后在不更新缓冲区的情况下更改着色器程序。但是如果有一堆简单的着色器,其中唯一的共享变量是变换矩阵呢?这么少的内存可以使用统一缓冲区吗?在一些论坛讨论中,我读过
glBindBuffer(GL_UNIFORM_BUFFER,buf);
glBufferSubData(/*just 16 floats*/);
glBindBuffer(GL_UNIFORM_BUFFER,0);
比glUniform*
通话慢得多。在这里我们可以注意到,第一种和第二种方法之间的选择取决于以下条件:
- 着色器每帧多久更改一次,它们多久重复一次?
- 有多少“共享”制服?
- 在每一帧中应该将多少数据传递给着色器程序?
无论这三个问题的答案如何,是否有任何折衷的设计模式会具有良好的性能?
3)使用超级着色器。在第二段中提到:GLSL multiple shaderprogram VS uniforms switch。我有两个问题:
哪个性能更好:一个glUseProgram
调用还是多个统一开关,会改变 ubershader 的功能?
提到的那个问题的作者
每帧必须多次更换制服
作为 ubershader 的缺点之一。但是为什么不好呢?它有不好的表现吗?如果是这样,是否可以将转换矩阵和其他一些小尺寸的东西作为统一变量传递并在每帧更新它们?
总结以上所有的主要问题:您能否建议任何其他技术或设计模式来更新几个不同着色器程序中的同名统一变量?
UPD:答案是可以接受的,但是如果您可以建议一种重要的高级设计技术(在 C++ 中或与语言无关),请将其留在这里。