March 9, 2011

GLSL dithering

looking at previous post (crosshatch), it inspired me to take a deeper look into dithering algorithms. http://en.wikipedia.org/wiki/Dithering
After few minutes I came up with very simple b/w Bayer Ordered dithering. I am quite sure someone has done it before me, but it was a nice exercise for me.


//Bayer Ordered dithering
uniform sampler2D bgl_RenderedTexture;

void main()
{
vec3 color = texture2D(bgl_RenderedTexture, gl_TexCoord[0].xy).rgb;
vec3 luminosity = vec3(0.30, 0.59, 0.11);
float lum = dot(luminosity, color);

float v = gl_FragCoord.s;
float h = gl_FragCoord.t;

gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);

if (lum < 0.9)
{
gl_FragColor.rgb *= round((fract(v/2))+(fract(h/2)));
}

if (lum < 0.75)
{
gl_FragColor.rgb *= round((fract(v+v/2))+(fract(h+h/2)));
}

if (lum < 0.5)
{
gl_FragColor.rgb *= round((fract(v+v+v/2))+(fract(h+h/2)));
}

if (lum < 0.25)
{
gl_FragColor.rgb *= round((fract(v+v/2))+(fract(h+h+h/2)));
}

}


and I just found a color Ordered dithering shader here (4x4 Bayer Matrix):
http://www.assembla.com/code/MUL2010_OpenGLScenePostprocessing/subversion/nodes/MUL%20FBO/Shaders/dithering.frag?rev=83


// Ordered dithering aka Bayer matrix dithering

uniform sampler2D bgl_RenderedTexture;
float scale = 1.0;

float find_closest(int x, int y, float c0)
{
vec4 dither[4];

dither[0] = vec4( 1.0, 33.0, 9.0, 41.0);
dither[1] = vec4(49.0, 17.0, 57.0, 25.0);
dither[2] = vec4(13.0, 45.0, 5.0, 37.0);
dither[3] = vec4(61.0, 29.0, 53.0, 21.0);

float limit = 0.0;
if(x < 4)
{
limit = (dither[x][y]+1.0)/64.0;
}

if(c0 < limit)
{
return 0.0;

}else{

return 1.0;
}

}


void main(void)
{
vec4 lum = vec4(0.299, 0.587, 0.114, 0.0);
float grayscale = dot(texture2D(bgl_RenderedTexture, gl_TexCoord[0].xy), lum);
vec3 rgb = texture2D(bgl_RenderedTexture, gl_TexCoord[0].xy).rgb;

vec2 xy = gl_FragCoord.xy * scale;
int x = int(mod(xy.x, 4.0));
int y = int(mod(xy.y, 4.0));

vec3 finalRGB;

finalRGB.r = find_closest(x, y, rgb.r);
finalRGB.g = find_closest(x, y, rgb.g);
finalRGB.b = find_closest(x, y, rgb.b);

float final = find_closest(x, y, grayscale);

gl_FragColor = vec4(finalRGB, 1.0);
}


Comparison screenshots (click to see full size):

Without filter


B/W dithering


Color dithering

2 comments:

  1. Hi Martinsh,
    I wanted to test this effect with ATI and had to do some changes:
    ##################
    //Bayer Ordered dithering
    uniform sampler2D bgl_RenderedTexture;

    void main()
    {
    vec3 color = texture2D(bgl_RenderedTexture, gl_TexCoord[0].xy).rgb;
    vec3 luminosity = vec3(0.30, 0.59, 0.11);
    float lum = dot(luminosity, color);

    float v = gl_FragCoord.s;
    float h = gl_FragCoord.t;
    float value;

    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);

    if (lum < 0.9)
    {
    value = float(int((fract(v/2.0))+(fract(h/2.0))));
    gl_FragColor.rgb *= vec3(value, value, value);
    }

    if (lum < 0.75)
    {
    value = float(int((fract(v+v/2.0))+(fract(h+h/2.0))));
    gl_FragColor.rgb *= vec3(value, value, value);
    }

    if (lum < 0.5)
    {
    value = float(int((fract(v+v+v/2.0))+(fract(h+h/2.0))));
    gl_FragColor.rgb *= vec3(value, value, value);
    }

    if (lum < 0.25)
    {
    value = float(int((fract(v+v/2.0))+(fract(h+h+h/2.0))));
    gl_FragColor.rgb *= vec3(value, value, value);
    }

    }
    ################
    Cheers.

    ReplyDelete
  2. ooh yeah, you are right. Mine does not work on ATI cards..
    Yours seems to be working very nicely though :)

    ReplyDelete