1bit ordered bayer matrix

Hi guys

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

// 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 make it for a videogame so I decided 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
the point is that I’m using it inside game maker studio 2 which has some differences writing it

I was not able to write double arrays like this

//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

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

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

// 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

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

Well I found how to get Dither Size

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

uniform vec2 resolution;

uniform float pixelSize;
uniform float ditherSize;

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; 
	vec2 tuv = gl_FragCoord.xy / 8.0 / ditherSize ;
	
	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;
	
	tuv = fract(tuv);
	
	vec4 tdither = texture2D( textureImage, tuv );
	
	vec4 lum = vec4(0.299, 0.587, 0.114, 0);
	
	float center = vsize - distance(vec2(0.5),uv);
	
	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);
	}
}

simply by keeping the texture resolution but using a third parameter

vec2 tuv = gl_FragCoord.xy / 8.0 / ditherSize ;

tuv could not be multiplied by 17

tuv *= 17.0;

because the fract works also without it to repeat the texture to the whole canvas

the shader is going to be perfect, but in some points the shader is going to cut in half some “pixels” of the bigger bayer matrix texture, with the step function

I should try to leave this cut