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

hye, im new to godot. could you link your demo project for me to dissect? ive been trying to do this, and the vague instructions in pllaces make it hard to follow for me
thanks!