Palette shader (lospec compatible)

This palette shader uses 1x palette textures to do it’s work. It does so by sampling from the 1x textures you can find on websites like lospec.

To make this shader work, use a Sprite (or other CanvasItem with pixels) or cover the area you want to change the colors of with a ColorRect. Then use this shader, set up the amount of colors in the palette texture and drag in the palette texture itself.

Why not try the world famous PICO-8 palette for your next jam game! Confuse everyone haha.

Shader code
shader_type canvas_item;

uniform sampler2D palette : hint_black; // Insert a palette from lospec for instance
uniform int palette_size = 16;

void fragment(){ 
	vec4 color = texture(SCREEN_TEXTURE, SCREEN_UV);
	vec4 new_color = vec4(.0);
	
	for (int i = 0; i < palette_size; i++) {
		vec4 palette_color = texture(palette, vec2(1.0 / float(palette_size) * float(i), .0));
		if (distance(palette_color, color) < distance(new_color, color)) {
			new_color = palette_color;
		}
	}
	
	COLOR = new_color;
}
Tags
Color, lospec, palette, pixel
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

Extensible Color Palette (Gradient Maps) Now with Palette Blending!

Palette Shader

Palette Limiter Shader

Subscribe
Notify of
guest

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Ferajo
Ferajo
2 years ago

I did one exactly like yours Palette Filter For 3D and 2D – Godot Shaders

silentbat
silentbat
2 years ago

i think you missed a small offset (its not often visible but it can be):
when iterating over the points, you should use

vec4 palette_color = texture(palette, vec2(1.0 / float(palette_size) * (float(i) + 0.5), .0));

the “+0.5” takes care of “centering” in each pixel of the palette – otherwise you can hit edges between pixels.
Happened to me: i took a plalette with 36 colors but had to increase the palette_size to 37 for the sampling to work.
Reason: 35/36 = 0.97222… which is exactly where the pixel should start, but through floating point error, you get the 35th instead of the 36th color, therefor the last color never gets used.

Bombardlos
1 year ago

Had to change SCREEN_TEXTURE to TEXTURE, and SCREEN_UV to UV:

vec4 color = texture(TEXTURE, UV);

(Now mind you I have no idea what I’m doing, it just worked for me)

JohnnyNeverWalked
JohnnyNeverWalked
10 months ago

If you are having problems with transparent pixels try adding this at the end:

COLOR.a = color.a;

This should apply the alpha channel of the original pixel thus preserving any transparency 🙂