GameBoy-like Old-School 2D Filter

Hi,
I’ve made an old-school gameboy-like 2D filter based on an existing dithering filter (https://github.com/hughsk/glsl-dither).

http://i.imgur.com/1L6J5G2.gif

Here’s the shader code:


float luma(vec3 color) {
  return dot(color, vec3(0.299, 0.587, 0.114));
}


float luma(vec4 color) {
  return dot(color.rgb, vec3(0.299, 0.587, 0.114));
}

// from https://github.com/hughsk/glsl-dither
float dither8x8(vec2 position, float brightness) {
  int x = int(mod(position.x, 8.0));
  int y = int(mod(position.y, 8.0));
  int index = x + y * 8;
  float limit = 0.0;


  if (x < 8) {
    if (index == 0) limit = 0.015625;
    if (index == 1) limit = 0.515625;
    if (index == 2) limit = 0.140625;
    if (index == 3) limit = 0.640625;
    if (index == 4) limit = 0.046875;
    if (index == 5) limit = 0.546875;
    if (index == 6) limit = 0.171875;
    if (index == 7) limit = 0.671875;
    if (index == 8) limit = 0.765625;
    if (index == 9) limit = 0.265625;
    if (index == 10) limit = 0.890625;
    if (index == 11) limit = 0.390625;
    if (index == 12) limit = 0.796875;
    if (index == 13) limit = 0.296875;
    if (index == 14) limit = 0.921875;
    if (index == 15) limit = 0.421875;
    if (index == 16) limit = 0.203125;
    if (index == 17) limit = 0.703125;
    if (index == 18) limit = 0.078125;
    if (index == 19) limit = 0.578125;
    if (index == 20) limit = 0.234375;
    if (index == 21) limit = 0.734375;
    if (index == 22) limit = 0.109375;
    if (index == 23) limit = 0.609375;
    if (index == 24) limit = 0.953125;
    if (index == 25) limit = 0.453125;
    if (index == 26) limit = 0.828125;
    if (index == 27) limit = 0.328125;
    if (index == 28) limit = 0.984375;
    if (index == 29) limit = 0.484375;
    if (index == 30) limit = 0.859375;
    if (index == 31) limit = 0.359375;
    if (index == 32) limit = 0.0625;
    if (index == 33) limit = 0.5625;
    if (index == 34) limit = 0.1875;
    if (index == 35) limit = 0.6875;
    if (index == 36) limit = 0.03125;
    if (index == 37) limit = 0.53125;
    if (index == 38) limit = 0.15625;
    if (index == 39) limit = 0.65625;
    if (index == 40) limit = 0.8125;
    if (index == 41) limit = 0.3125;
    if (index == 42) limit = 0.9375;
    if (index == 43) limit = 0.4375;
    if (index == 44) limit = 0.78125;
    if (index == 45) limit = 0.28125;
    if (index == 46) limit = 0.90625;
    if (index == 47) limit = 0.40625;
    if (index == 48) limit = 0.25;
    if (index == 49) limit = 0.75;
    if (index == 50) limit = 0.125;
    if (index == 51) limit = 0.625;
    if (index == 52) limit = 0.21875;
    if (index == 53) limit = 0.71875;
    if (index == 54) limit = 0.09375;
    if (index == 55) limit = 0.59375;
    if (index == 56) limit = 1.0;
    if (index == 57) limit = 0.5;
    if (index == 58) limit = 0.875;
    if (index == 59) limit = 0.375;
    if (index == 60) limit = 0.96875;
    if (index == 61) limit = 0.46875;
    if (index == 62) limit = 0.84375;
    if (index == 63) limit = 0.34375;
  }


  return brightness < limit ? 0.0 : 1.0;
}


vec3 dither8x8(vec2 position, vec3 color) {
  return color * dither8x8(position, luma(color));
}


vec4 dither8x8(vec2 position, vec4 color) {
  return vec4(color.rgb * dither8x8(position, luma(color)), 1.0);
}
//


uniform sampler2D bgl_RenderedTexture;


void main(void)
{
    vec4 color = texture2D(bgl_RenderedTexture, gl_TexCoord[0].st);
    float avg = (color.r + color.g + color.b) / 3.0;
    
    vec4 tint = vec4(avg, avg, avg, color.a) * vec4(0.716, 0.8909, 0.1675, 1.0);
    vec4 final = dither8x8(gl_FragCoord.xy, tint);
    gl_FragColor = final;
}

Color version:


float luma(vec3 color) {
  return dot(color, vec3(0.299, 0.587, 0.114));
}


float luma(vec4 color) {
  return dot(color.rgb, vec3(0.299, 0.587, 0.114));
}

// from https://github.com/hughsk/glsl-dither
float dither8x8(vec2 position, float brightness) {
  int x = int(mod(position.x, 8.0));
  int y = int(mod(position.y, 8.0));
  int index = x + y * 8;
  float limit = 0.0;


  if (x < 8) {
    if (index == 0) limit = 0.015625;
    if (index == 1) limit = 0.515625;
    if (index == 2) limit = 0.140625;
    if (index == 3) limit = 0.640625;
    if (index == 4) limit = 0.046875;
    if (index == 5) limit = 0.546875;
    if (index == 6) limit = 0.171875;
    if (index == 7) limit = 0.671875;
    if (index == 8) limit = 0.765625;
    if (index == 9) limit = 0.265625;
    if (index == 10) limit = 0.890625;
    if (index == 11) limit = 0.390625;
    if (index == 12) limit = 0.796875;
    if (index == 13) limit = 0.296875;
    if (index == 14) limit = 0.921875;
    if (index == 15) limit = 0.421875;
    if (index == 16) limit = 0.203125;
    if (index == 17) limit = 0.703125;
    if (index == 18) limit = 0.078125;
    if (index == 19) limit = 0.578125;
    if (index == 20) limit = 0.234375;
    if (index == 21) limit = 0.734375;
    if (index == 22) limit = 0.109375;
    if (index == 23) limit = 0.609375;
    if (index == 24) limit = 0.953125;
    if (index == 25) limit = 0.453125;
    if (index == 26) limit = 0.828125;
    if (index == 27) limit = 0.328125;
    if (index == 28) limit = 0.984375;
    if (index == 29) limit = 0.484375;
    if (index == 30) limit = 0.859375;
    if (index == 31) limit = 0.359375;
    if (index == 32) limit = 0.0625;
    if (index == 33) limit = 0.5625;
    if (index == 34) limit = 0.1875;
    if (index == 35) limit = 0.6875;
    if (index == 36) limit = 0.03125;
    if (index == 37) limit = 0.53125;
    if (index == 38) limit = 0.15625;
    if (index == 39) limit = 0.65625;
    if (index == 40) limit = 0.8125;
    if (index == 41) limit = 0.3125;
    if (index == 42) limit = 0.9375;
    if (index == 43) limit = 0.4375;
    if (index == 44) limit = 0.78125;
    if (index == 45) limit = 0.28125;
    if (index == 46) limit = 0.90625;
    if (index == 47) limit = 0.40625;
    if (index == 48) limit = 0.25;
    if (index == 49) limit = 0.75;
    if (index == 50) limit = 0.125;
    if (index == 51) limit = 0.625;
    if (index == 52) limit = 0.21875;
    if (index == 53) limit = 0.71875;
    if (index == 54) limit = 0.09375;
    if (index == 55) limit = 0.59375;
    if (index == 56) limit = 1.0;
    if (index == 57) limit = 0.5;
    if (index == 58) limit = 0.875;
    if (index == 59) limit = 0.375;
    if (index == 60) limit = 0.96875;
    if (index == 61) limit = 0.46875;
    if (index == 62) limit = 0.84375;
    if (index == 63) limit = 0.34375;
  }


  return brightness < limit ? 0.0 : 1.0;
}


vec3 dither8x8(vec2 position, vec3 color) {
  return color * dither8x8(position, luma(color));
}


vec4 dither8x8(vec2 position, vec4 color) {
  return vec4(color.rgb * dither8x8(position, luma(color)), 1.0);
}
//

uniform sampler2D bgl_RenderedTexture;

void main(void)
{
    vec4 color = texture2D(bgl_RenderedTexture, gl_TexCoord[0].st);
    gl_FragColor = dither8x8(gl_FragCoord.xy, color);
}

I hope you like it :smiley:

Oh my god yes!

Nice work,
I can see a nice super metroid gameboy advanced game coming out of the bge now.

Love it! Looks awesome, only problem is it brings my 60FPS game down to 2FPS…
EDIT: Had pulse mode activated, whoops. Works great

those if statements should use else if to avoid additional branch checking

Sent from my SM-G920F using Tapatalk

could you just make a list one time ‘range’ or something
[1.00005,1.03030,.5005050,.3030303]

and

range[value] = your value?

I don’t know GLSL , it just seems faster.

Maybe parsing all to string and apply. But i seen codes with python script to shaders… how to wrap 2d filter (which are pure glsl) to python? Is i t possible like it’s in shader tutorial? (like this) It might make possible to change 2d filter dynamically, but i dunno know. Just asking.

I tried changing that list of numbers in the following ways and had the following outcomes:

  1. I changed it to an array of floats. This resulted in a reduction in performance.
    I think that storing the values in an array is taxing on memory, since you have to store all of those single-precision values each frame.

float luma(vec3 color) {
  return dot(color, vec3(0.299, 0.587, 0.114));
}


float luma(vec4 color) {
  return dot(color.rgb, vec3(0.299, 0.587, 0.114));
}

// from https://github.com/hughsk/glsl-dither
float dither8x8(vec2 position, float brightness) {
  int x = int(mod(position.x, 8.0));
  int y = int(mod(position.y, 8.0));
  int index = x + y * 8;
  float limit = 0.0;
  float limits[64] = {
    0.015625,
    0.515625,
    0.140625,
    0.640625,
    0.046875,
    0.546875,
    0.171875,
    0.671875,
    0.765625,
    0.265625,
    0.890625,
    0.390625,
    0.796875,
    0.296875,
    0.921875,
    0.421875,
    0.203125,
    0.703125,
    0.078125,
    0.578125,
    0.234375,
    0.734375,
    0.109375,
    0.609375,
    0.953125,
    0.453125,
    0.828125,
    0.328125,
    0.984375,
    0.484375,
    0.859375,
    0.359375,
    0.0625,
    0.5625,
    0.1875,
    0.6875,
    0.03125,
    0.53125,
    0.15625,
    0.65625,
    0.8125,
    0.3125,
    0.9375,
    0.4375,
    0.78125,
    0.28125,
    0.90625,
    0.40625,
    0.25,
    0.75,
    0.125,
    0.625,
    0.21875,
    0.71875,
    0.09375,
    0.59375,
    1.0,
    0.5,
    0.875,
    0.375,
    0.96875,
    0.46875,
    0.84375,
    0.34375,
  };


  if (x < 8) {
    limit = limits[index];
  }

  return brightness < limit ? 0.0 : 1.0;
}


vec3 dither8x8(vec2 position, vec3 color) {
  return color * dither8x8(position, luma(color));
}


vec4 dither8x8(vec2 position, vec4 color) {
  return vec4(color.rgb * dither8x8(position, luma(color)), 1.0);
}
//


uniform sampler2D bgl_RenderedTexture;


void main(void)
{
    vec4 color = texture2D(bgl_RenderedTexture, gl_TexCoord[0].st);
    float avg = (color.r + color.g + color.b) / 3.0;
    
    vec4 tint = vec4(avg, avg, avg, color.a) * vec4(0.716, 0.8909, 0.1675, 1.0);
    vec4 final = dither8x8(gl_FragCoord.xy, tint);
    gl_FragColor = final;
}

  1. I changed it to “else if” after the first if statement and got a reduction in performance.
    I have no idea why this would be the case, since it seems logical that it would have to perform less comparisons as a result of this.

float luma(vec3 color) {
  return dot(color, vec3(0.299, 0.587, 0.114));
}


float luma(vec4 color) {
  return dot(color.rgb, vec3(0.299, 0.587, 0.114));
}

// from https://github.com/hughsk/glsl-dither
float dither8x8(vec2 position, float brightness) {
  int x = int(mod(position.x, 8.0));
  int y = int(mod(position.y, 8.0));
  int index = x + y * 8;
  float limit = 0.0;


  if (x < 8) {
    if (index == 0) limit = 0.015625;
    else if (index == 1) limit = 0.515625;
    else if (index == 2) limit = 0.140625;
    else if (index == 3) limit = 0.640625;
    else if (index == 4) limit = 0.046875;
    else if (index == 5) limit = 0.546875;
    else if (index == 6) limit = 0.171875;
    else if (index == 7) limit = 0.671875;
    else if (index == 8) limit = 0.765625;
    else if (index == 9) limit = 0.265625;
    else if (index == 10) limit = 0.890625;
    else if (index == 11) limit = 0.390625;
    else if (index == 12) limit = 0.796875;
    else if (index == 13) limit = 0.296875;
    else if (index == 14) limit = 0.921875;
    else if (index == 15) limit = 0.421875;
    else if (index == 16) limit = 0.203125;
    else if (index == 17) limit = 0.703125;
    else if (index == 18) limit = 0.078125;
    else if (index == 19) limit = 0.578125;
    else if (index == 20) limit = 0.234375;
    else if (index == 21) limit = 0.734375;
    else if (index == 22) limit = 0.109375;
    else if (index == 23) limit = 0.609375;
    else if (index == 24) limit = 0.953125;
    else if (index == 25) limit = 0.453125;
    else if (index == 26) limit = 0.828125;
    else if (index == 27) limit = 0.328125;
    else if (index == 28) limit = 0.984375;
    else if (index == 29) limit = 0.484375;
    else if (index == 30) limit = 0.859375;
    else if (index == 31) limit = 0.359375;
    else if (index == 32) limit = 0.0625;
    else if (index == 33) limit = 0.5625;
    else if (index == 34) limit = 0.1875;
    else if (index == 35) limit = 0.6875;
    else if (index == 36) limit = 0.03125;
    else if (index == 37) limit = 0.53125;
    else if (index == 38) limit = 0.15625;
    else if (index == 39) limit = 0.65625;
    else if (index == 40) limit = 0.8125;
    else if (index == 41) limit = 0.3125;
    else if (index == 42) limit = 0.9375;
    else if (index == 43) limit = 0.4375;
    else if (index == 44) limit = 0.78125;
    else if (index == 45) limit = 0.28125;
    else if (index == 46) limit = 0.90625;
    else if (index == 47) limit = 0.40625;
    else if (index == 48) limit = 0.25;
    else if (index == 49) limit = 0.75;
    else if (index == 50) limit = 0.125;
    else if (index == 51) limit = 0.625;
    else if (index == 52) limit = 0.21875;
    else if (index == 53) limit = 0.71875;
    else if (index == 54) limit = 0.09375;
    else if (index == 55) limit = 0.59375;
    else if (index == 56) limit = 1.0;
    else if (index == 57) limit = 0.5;
    else if (index == 58) limit = 0.875;
    else if (index == 59) limit = 0.375;
    else if (index == 60) limit = 0.96875;
    else if (index == 61) limit = 0.46875;
    else if (index == 62) limit = 0.84375;
    else if (index == 63) limit = 0.34375;
  }


  return brightness < limit ? 0.0 : 1.0;
}


vec3 dither8x8(vec2 position, vec3 color) {
  return color * dither8x8(position, luma(color));
}


vec4 dither8x8(vec2 position, vec4 color) {
  return vec4(color.rgb * dither8x8(position, luma(color)), 1.0);
}
//


uniform sampler2D bgl_RenderedTexture;


void main(void)
{
    vec4 color = texture2D(bgl_RenderedTexture, gl_TexCoord[0].st);
    float avg = (color.r + color.g + color.b) / 3.0;
    
    vec4 tint = vec4(avg, avg, avg, color.a) * vec4(0.716, 0.8909, 0.1675, 1.0);
    vec4 final = dither8x8(gl_FragCoord.xy, tint);
    gl_FragColor = final;
}

  1. I changed it to a switch statement and got about a 50% reduction in performance.
    I didn’t expect this to have a different effect to the if statement, yet it was slower.

Anyone here really good at glsl and can explain this to me?