Shaders 1Bit Ordered Bayer Matrix Dithering

Heavybrush

Member
Hi guys

I’m having a problem trying to fix my 1bit ordered dithering shader

C++:
// Ordered dithering aka Bayer matrix dithering
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform vec2 resolution;
uniform float pixelSize;
uniform float gamma;
uniform float contrast;
uniform int invert;
uniform sampler2D textureImage;

void main()
{
    vec2 uv = gl_FragCoord.xy / resolution.xy;
    
    vec2 pseudoPixel = floor( gl_FragCoord.xy / pixelSize );
    vec2 pseudoResolution = floor( resolution.xy / pixelSize );
    vec2 pseudoUv = pseudoPixel / pseudoResolution;
    
    vec4 color = v_vColour * texture2D( gm_BaseTexture, pseudoUv );
    float alpha = 1.0;
    
    vec2 tuv = gl_FragCoord.xy / 8.0;
    tuv *= 17.0;
    tuv = fract(tuv);
    
    vec4 tdither = texture2D( textureImage, tuv );
    
    vec4 lum = vec4(0.299, 0.587, 0.114, 0);
    
    float dither = dot(tdither, lum);
    float grayscale = dot(color, lum) * gamma;
    grayscale = (grayscale - 0.5) * contrast + 0.5;
    
    vec3 col = vec3(step(dither,grayscale));
    
    if(invert == 0) {
        gl_FragColor = vec4(col, alpha);
    } else {
        gl_FragColor = vec4(1.0 - col, alpha);
    }
}

I’m trying to put some uniform to handle some things like gamma, contrast, invert colors, pixel size

I studied a lot of bayer matrix shaders to understand this that I wrote
I was not able to write double arrays like this

C++:
//1Bit ordered dithering patterns
vec3 dither_8(vec2 pos, float val) {

    const int mat[] = int[](
    0, 48, 12, 60, 3, 51, 15, 63,
    32, 16, 44, 28, 35, 19, 47, 31,
    8, 56, 4, 52, 11, 59, 7, 55,
    40, 24, 36, 20, 43, 27, 39, 23,
    2, 50, 14, 62, 1, 49, 13, 61,
    34, 18, 46, 30, 33, 17, 45, 29,
    10, 58, 6, 54, 9, 57, 5, 53,
    42, 26, 38, 22, 41, 25, 37, 21
    );
or like this

C++:
int dither[8][8] = {
        { 0, 32, 8, 40, 2, 34, 10, 42    },
        {48, 16, 56, 24, 50, 18, 58, 26    },
        {12, 44, 4, 36, 14, 46, 6, 38    },
        {60, 28, 52, 20, 62, 30, 54, 22    },
        { 3, 35, 11, 43, 1, 33, 9, 41    },
        {51, 19, 59, 27, 49, 17, 57, 25    },
        {15, 47, 7, 39, 13, 45, 5, 37    },
        {63, 31, 55, 23, 61, 29, 53, 21    }
    };

so I decided to try sample a texture of a bayer matrix 8x8 px
try to put on top of my source image (game canvas)
multiply the texture to cover the whole canvas
and render a step function to have only black or white

in this moment I have a problem with the size of the dithering, because is static and change the quality of my final result in base of the canvas size

for example if I have a little canvas but I make it fullscreen it changes the detail of the textures, because the dither remain of a certain size

I really would like to be able to handle the dither size with a uniform, to do some debug tests and understand what is the size that I should use
also to be able to change the value in game to give some transition effect

I guess the dither size could be
or linked to the pixel size
or unlinked, maybe better so I can achieve more effects having two different values and in case link it to the pixel size outside the shader

I tried a lot of ways, I’m a little bit stuck

hope you guys can help me with this, because I’m doing very good stuff for it and I would like to fix it very soon to keep going with my project

thank you so much
 
D

Deleted member 13992

Guest
I've done this, except that instead of passing the dither matrix into the shader, I would overlay it to the view with something like draw_sprite_tiled and a blend mode. Then my shader would do the normal color banding/down-res of the bit depth. Or using a LUT with the banding built-in.

This worked well for me, giving me ordered dithering, granted it was still color (not 1-bit). Maybe it can give you ideas.
 

Heavybrush

Member
I've done this, except that instead of passing the dither matrix into the shader, I would overlay it to the view with something like draw_sprite_tiled and a blend mode. Then my shader would do the normal color banding/down-res of the bit depth. Or using a LUT with the banding built-in.

This worked well for me, giving me ordered dithering, granted it was still color (not 1-bit). Maybe it can give you ideas.
this is very nice, congratulations :)
 

Heavybrush

Member
I got a better shader now, adding a vignette effect with lots of uniforms to change all parameters dynamically

C++:
// Ordered dithering aka Bayer matrix dithering
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform vec2 resolution;

uniform float pixelSize;

uniform float gamma;
uniform float contrast;

uniform int invert;

uniform int vignette;

uniform float vsize;
uniform float vouter;
uniform float vfalloff;
uniform float valpha;

uniform sampler2D textureImage;

void main()
{
    vec2 uv = gl_FragCoord.xy / resolution.xy;
    float center = vsize - distance(vec2(0.5),uv);
    
    vec2 pseudoPixel = floor( gl_FragCoord.xy / pixelSize );
    vec2 pseudoResolution = floor( resolution.xy / pixelSize );
    vec2 pseudoUv = pseudoPixel / pseudoResolution;
    
    vec4 color = v_vColour * texture2D( gm_BaseTexture, pseudoUv );
    float alpha = 1.0;
    
    vec2 tuv = gl_FragCoord.xy / 8.0;
    tuv *= 17.0;
    tuv = fract(tuv);
    
    vec4 tdither = texture2D( textureImage, tuv );
    
    vec4 lum = vec4(0.299, 0.587, 0.114, 0);
    
    if(vignette == 1) {
        vec3 vcol = vec3(smoothstep(vouter, vouter + vfalloff, center));
        color.rgb = mix(color.rgb, color.rgb * vcol, valpha);
    }
    
    float dither = dot(tdither, lum);
    float grayscale = dot(color, lum) * gamma;
    grayscale = (grayscale - 0.5) * contrast + 0.5;
    
    vec3 col = vec3(step(dither,grayscale));
    
    if(invert == 0) {
        gl_FragColor = vec4(col, alpha);
    } else {
        gl_FragColor = vec4(1.0 - col, alpha);
    }
}
I still have the problem on the dithering size

I guess I got something wrong here

C++:
vec2 tuv = gl_FragCoord.xy / 8.0;
    tuv *= 17.0;
    tuv = fract(tuv);
dithering size should be linked to the game window size
(currently if I switch to fullscreen it changes the detail of the picture)

and should be able to change the parameter with a uniform to have more control
 
Top