GLSL 片段着色器中的动态工作量
Dynamic amount of work in GLSL fragment shader
我正在研究一个 post-processing GLSL (ES) fragment shader for 2D shock waves。很容易将纹理稍微扭曲成一个圆圈,并且它已经适用于单个冲击波。现在需要同时支持多个wave,我的想法:
第一个想法: 对每个波进行 post 处理(绑定 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 不喜欢带有非常量表达式的循环,因此驱动程序无法展开。
是否有给着色器一个 "dynamic amount of work" 的最佳实践?我的 OpenGL 版本是 2.0 ES.
只有少数 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 扩展。你基本上只需要编译一个带有动态循环的着色器,然后看看它是否成功。如果您的目标不支持它,您可以 'fake' 动态循环,方法是使用常量循环表达式编译多个着色器,而不是使用 uniform。例如:
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
的可能值数量相当少,您就不会得到这么多着色器。
我正在研究一个 post-processing GLSL (ES) fragment shader for 2D shock waves。很容易将纹理稍微扭曲成一个圆圈,并且它已经适用于单个冲击波。现在需要同时支持多个wave,我的想法:
第一个想法: 对每个波进行 post 处理(绑定 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 不喜欢带有非常量表达式的循环,因此驱动程序无法展开。
是否有给着色器一个 "dynamic amount of work" 的最佳实践?我的 OpenGL 版本是 2.0 ES.
只有少数 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 扩展。你基本上只需要编译一个带有动态循环的着色器,然后看看它是否成功。如果您的目标不支持它,您可以 'fake' 动态循环,方法是使用常量循环表达式编译多个着色器,而不是使用 uniform。例如:
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
的可能值数量相当少,您就不会得到这么多着色器。