我正在研究用于2D冲击波的后处理GLSL(ES)片段着色器。很容易扭曲一个圆圈中的纹理,它已经适用于单个冲击波。现在我需要同时支持多个波浪,我的想法是:
第一个想法:为每个wave进行后处理(绑定FBO - >绑定上一个纹理 - >绘制调用)。简单的实现,但很多状态改变和绘制调用。
第二个想法:添加数据纹理,包含所有波的所有信息和带有数字波的单个制服,所以我可以这样做:
uniform int count;
uniform sampler2D dataTex;
const float dataTexSize = 32;
[...]
vec4 pixel;
for(int i = 0; i < count; i++)
{
vec2 dataTexPos = vec2(i / dataTexSize, 0);
pixel += shockwave(texture2D(dataTex, dataTexPos));
}
pixel /= float(count);
[...]
但显然GPU不喜欢具有非常量表达式的循环,并且驱动程序无法展开。
是否有最佳做法为着色器提供“动态的工作量”?我的OpenGL版本是2.0 ES。
答案 0 :(得分:1)
只有少数ES2.0 GPU(任何合理数量都可用)不支持片段着色器中的动态循环。我特别知道的两个是Tegra 2(Android GLSL fragment shader on NVIDIA tegra2 - 但它已经老了)和Broadcom VC4(Raspberry Pi和Amazon FireTV Stick)。 ES 2.0规范不需要支持,但正如@Nicol Bolas所提到的,绝大多数移动GPU确实支持它。因此,如果您没有针对任何这些芯片,那么您很可能只使用着色器。
遗憾的是,没有GLES扩展来宣传对动态循环的支持。您基本上只需要使用动态循环编译着色器,并查看它是否成功。如果您的目标不支持它,您可以通过使用常量循环表达式编译多个着色器而不是使用统一来“伪造”动态循环。例如:
int count = %d;
uniform sampler2D dataTex;
const float dataTexSize = 32;
[...]
vec4 pixel;
for(int i = 0; i < count; i++)
{
vec2 dataTexPos = vec2(i / dataTexSize, 0);
pixel += shockwave(texture2D(dataTex, dataTexPos));
}
pixel /= float(count);
[...]
每当遇到需要不同循环计数的情况时,请将%d
替换为所需的循环计数并编译新的着色器。只要count
具有相当少的可能值,您就不会得到这么多着色器。