我有一个片段着色器,它基本上读取颜色alpha并将其转换为像素的抖动效果。
然而,对于所有mod和if语句来说,它是处理器密集型的。 有没有人对优化下面的代码有任何建议?
varying vec2 the_uv;
varying vec4 color;
void main()
{
// The pixel color will correspond
// to the uv coords of the texture
// for the given vertice, retrieved
// by the Vertex shader through varying vec2 the_uv
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
vec4 tex = texture2D(_MainTex, the_uv);
tex = tex * color ;
float r = tex.a;
if ( r > 0.1 ) {
if ( ( mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y, 4.0) ) > 6.00 ) {
gl_FragColor = color;
}
}
if ( r > 0.5 ) {
if ( ( mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y, 4.0) ) > 6.00 ) {
gl_FragColor = color;
}
}
if ( r > 0.7 ) {
if ( ( mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0) ) > 6.00 ) {
gl_FragColor = color;
}
}
if ( r > 0.9 ) {
if ( ( mod(gl_FragCoord.x + 1.0, 4.001) + mod(gl_FragCoord.y + 1.0, 4.0) ) > 6.00 ) {
gl_FragColor = color;
}
}
if ( r > 0.3 ) {
if ( ( mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0) ) > 6.00 ) {
gl_FragColor = color;
}
}
}
以下是基于反馈的解决方案:
varying vec2 the_uv;
varying vec4 color;
void main()
{
color = gl_Color;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
the_uv = gl_MultiTexCoord0.st;
}
#endif
#ifdef FRAGMENT
uniform sampler2D _MainTex;
uniform sampler2D _GridTex;
varying vec2 the_uv;
varying vec4 color;
void main()
{
if (texture2D(_MainTex, the_uv).a * color.a > texture2D(_GridTex, vec2(gl_FragCoord.x, gl_FragCoord.y)*.25).a) gl_FragColor = color;
else gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
答案 0 :(得分:6)
您要做的是选择是否应根据源alpha在4x4网格上点亮每个像素。最简单的方法就是做到这一点。
首先使用像素通过所需的相应alpha来初始化4x4纹理(我选择1.0作为从未在此处显示的alpha)
1.0 0.5 1.0 0.1
1.0 1.0 0.9 1.0
1.0 0.3 1.0 0.7
1.0 1.0 1.0 1.0
使用repeat设置此纹理以完全避免mod,使用最近的滤镜来避免线性过滤。
然后,使用该纹理的采样来决定是否点亮像素。
vec4 dither = texture2D(_my4x4, gl_FragCoord / 4.); // 4 is the size of the texture
if (r > dither) { gl_FragColor = color; }
这假设r从不是1.有简单的方法可以解决这个问题,例如:除了1.0之外,将4x4纹理中的值除以2,然后在if测试之前将抖动乘以2,但是在获取之后。
进一步的潜在优化:
答案 1 :(得分:-1)
首先,无论if语句的结果如何,你的片段颜色都是相同的,因为颜色是在开头设置的。
其次,只使用if else语句而不使用if,无论如何都会使你的代码贯穿每个计算。
更好的方法是:
if ( r > 0.9 ) {
if ( ( mod(gl_FragCoord.x + 1.0, 4.001) + mod(gl_FragCoord.y + 1.0, 4.0) ) > 6.00) {
gl_FragColor = color;
}
}
else if ( r > 0.7 ) {
if ( ( mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0) ) > 6.00 ) {
gl_FragColor = color;
}
}
else if ( r > 0.5 ) {
if ( ( mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y, 4.0) ) > 6.00 ) {
gl_FragColor = color;
}
}
else if ( r > 0.3 ) {
if ( ( mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0) ) > 6.00 ) {
gl_FragColor = color;
}
}
else if ( r > 0.1 ) {
if ( ( mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y, 4.0) ) > 6.00 ) {
gl_FragColor = color;
}
}
else{
gl_FragColor = color;
}
当然这不会帮助你改变输出,因为颜色永远不会改变(正如我之前提到的)。但这应该会使事情运行得更快。
要考虑的另一件事是最常执行的案例。我假设大r的情况更常见,因此if语句的顺序。如果小r更常见,则颠倒顺序并使r <1。 0.1,r&lt; 0.3,r&lt; 0.5,r&lt; 0.7,r&lt; 0.9会更有意义。
这里的重点是使代码尽可能快地退出(即if中的一个返回true)。一旦if中的一个返回true,则忽略其余部分,从而使您无需计算所有其余mod操作。