Game Boy Palette Overlay
Simple screen texture shader that maps the current screen image to a 4-color output, with an optional palette-constrained brightness slider.
Usage:
- Add a ColorRect to your scene.
- Ensure it draws in front of whatever you want to be affected by the palette.
- For instance, if you want it to cover the whole screen, move it to the end of the hierarchy or make it a “Top Level” CanvasItem, and make its anchor presets “Full Rect”.
- Add a material with the shader below to it.
- Set the
source_palette
andtarget_palette
shader parameters as desired.- For a Game Boy look, both should be 4 x 1 pixel .png textures.
- For ease of use, I recommend the
source_palette
be an evenly-spaced grayscale:#000000
#555555
#aaaaaa
#ffffff
- Adjust the
brightness
value as desired. It can also be quickly tweened to create screen transition effects.
Tip: if you’re stacking screen-reading shaders, you might need to place BackBufferCopy nodes in-between them. Check this article for more information.
Shader code
shader_type canvas_item;
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
uniform float brightness : hint_range(-1, 1) = 0;
uniform sampler2D source_palette;
uniform sampler2D target_palette;
void fragment() {
vec4 screen_color = texture(screen_texture, SCREEN_UV);
ivec2 pal_size = textureSize(source_palette, 0);
float color_diff = 1.0;
int nearest_swatch = 0;
for (int swatch=0; swatch < pal_size.x; swatch++) {
vec4 sampled_color = texelFetch(source_palette, ivec2(swatch,0), 0);
float new_color_diff = distance(sampled_color, screen_color);
if (new_color_diff < color_diff) {
color_diff = new_color_diff;
nearest_swatch = swatch;
}
}
int swatch_offset = int(brightness * float(pal_size.x));
int target_swatch = clamp(nearest_swatch + swatch_offset, 0, pal_size.x -1);
COLOR = texelFetch(target_palette, ivec2(target_swatch, 0), 0);
}