GLSL Gif抖动效果:优化

mik*_*ker 5 opengl glsl fragment-shader

着色器结果的图像

我有一个片段着色器,它基本上读取颜色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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是基于反馈的解决方案:

        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);   

        }
Run Code Online (Sandbox Code Playgroud)

Bah*_*bar 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
Run Code Online (Sandbox Code Playgroud)

使用repeat设置此纹理以完全避免mod,并使用最近的滤镜来避免线性过滤.

然后,使用该纹理的采样来决定是否点亮像素.

vec4 dither = texture2D(_my4x4, gl_FragCoord / 4.); // 4 is the size of the texture
if (r > dither) { gl_FragColor = color; }
Run Code Online (Sandbox Code Playgroud)

这假设r永远不是1.有一些简单的方法可以解决这个问题,例如将4x4纹理中的值除以1.0,除了1.0之外,然后在if测试之前将抖动乘以2,但是在获取之后.

一些进一步的潜在优化:

  • 你可以通过使用带比较的纹理(阴影纹理)完全避免if测试.
  • 你可以使用textureFetch指令来避免使用/ 4