Limit game's color palette

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By 9BitStrider

How would be the best way to go about limiting my game’s color palette to the NES one? I did this with an earlier build, but was curious to see if there was another way.

Palette Being Used

Shader Code

Completely unrelated this is the only thing i hate about Godot.
No uniform arrays in shaders

Wakatta | 2022-12-05 15:30

@Wakatta - I don’t have much shader experience, but doesn’t this provide the support you mention?

jgodfrey | 2022-12-05 15:38

I’ll give that a try to clean up the code a bit. I’m just curious if there’s a way to limit the overall color palette of my game to the colors in the image above. Is there a way to check color range compared to X color?

9BitStrider | 2022-12-05 15:57

:bust_in_silhouette: Reply From: aXu_AP

It sounded like a fun challenge, so I made a post processing shader for this. I haven’t done one earlier, so it was good exercise.

Step 1: make a viewportcontainer with viewport as it’s child (and everything you need to render as a child of viewport). Follow this if unsure.

Step 2: Add shader material and put this in your shader:

shader_type canvas_item;
render_mode blend_mix;

uniform sampler2D palette;

void fragment()
{
	vec3 source_col = texture(TEXTURE, UV).rgb;
	vec3 closest_col = vec3(0.0);
	float smallest_error = 10.0;
	
	int palette_size = textureSize(palette, 0).x;
	float palette_pixel_size = 1.0 / float(palette_size);
	for (int x = 0; x < palette_size; x++)
	{
		vec3 palette_col = texture(palette, vec2(float(x) * palette_pixel_size, 0.0)).rgb;
		float error = distance(source_col, palette_col);
		if (error < smallest_error)
		{
			closest_col = palette_col;
			smallest_error = error;
		}
	}
	
	COLOR.rgb = closest_col;
}

Step 3: In shader params, add your palette texture. It should have all the colors in one row. I tried downloading palettes from lospec in 1x png format, works well. Set filtering off from import settings!

That’s amazing! Thank you so much!

9BitStrider | 2022-12-08 22:43

If it helps don’t forget to mark answer as accepted - it helps others to find relevant answers when they’re having similiar issue :slight_smile:

aXu_AP | 2022-12-08 23:12

Like 9BitStrider said…
This is amazing!!!

Wakatta | 2022-12-09 01:53

In Godot 4 I was only able to get this to work by using hint_screen_texture like this:

shader_type canvas_item;
render_mode blend_mix;
// filter_nearest so you don't get weird ghost palette colors!!
uniform sampler2D palette: filter_nearest;
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;

void fragment()
{
   vec3 source_col = texture(screen_texture, SCREEN_UV).rgb;
   //...everything else is the same

dannflor | 2023-03-19 05:49