Godot 4.x Color Swap for 3D Mesh Models

This has nine built in sections for swapping colors on your 3D model’s albedo texture. Set this shader material up as the next pass on your geometry’s material override. Drag and drop the texture you’re using into the slot for it in the inspector, and make sure you’re using input colours that are very distinct from each other. You can play with the maximum difference setting on line 68 if you need more or less precision in the color matching. 

On line 71 I have it set to show a bright obnoxious blue if the shader isn’t able to find an input colour to map to. This is just for troubleshooting, you can disable it if there are colours on your texture that you don’t want altered. To do that you’d replace the line on 71 with:

ALBEDO = albedo_texture.rgb;

Because this shader exposes the output colors to the editor, this allows you to manipulate the color of a texture via code, enabling randomly generated or player controlled color swaps instead of just ones done by you in the editor. Just remember to make sub-resources unique if you use the shader across multiple models. You change the color of your model via code by accessing your_mesh_node.next_pass.shader_parameter/input_color1 and providing it with a new color. Check out Godot’s “Color” docs if you’re not sure how to do that. 

Shader code
shader_type spatial;

uniform sampler2D albedo_texture : source_color, filter_nearest;
uniform vec4 input_color1 : source_color;
uniform vec4 output_color1 : source_color;

uniform vec4 input_color2 : source_color;
uniform vec4 output_color2 : source_color;

uniform vec4 input_color3 : source_color;
uniform vec4 output_color3 : source_color;

uniform vec4 input_color4 : source_color;
uniform vec4 output_color4 : source_color;

uniform vec4 input_color5 : source_color;
uniform vec4 output_color5 : source_color;

uniform vec4 input_color6 : source_color;
uniform vec4 output_color6 : source_color;

uniform vec4 input_color7 : source_color;
uniform vec4 output_color7 : source_color;

uniform vec4 input_color8 : source_color;
uniform vec4 output_color8 : source_color;

uniform vec4 input_color9 : source_color;
uniform vec4 output_color9 : source_color;

bool colorMatch(vec4 c1, vec4 c2, float maxDiff) {
    return (
        abs(c1.r - c2.r) < maxDiff
        && abs(c1.g - c2.g) < maxDiff
        && abs(c1.b - c2.b) < maxDiff
    );
}

void fragment() {
	
	vec4[] input_colors = {
		input_color1,
		input_color2,
		input_color3,
		input_color4,
		input_color5,
		input_color6,
		input_color7,
		input_color8,
		input_color9
	};
	
	vec4[] output_colors = {
		output_color1,
		output_color2,
		output_color3,
		output_color4,
		output_color5,
		output_color6,
		output_color7,
		output_color8,
		output_color9
	};
	
	vec4 current_color = texture(albedo_texture, UV);
	
	for(int cr = 0; cr < input_colors.length(); cr++){
		if (colorMatch(current_color, input_colors[cr], 0.1)){
			ALBEDO = output_colors[cr].rgb;
			break; }
		else (ALBEDO = vec3(0,0,1));
		}
	}
Tags
3d, color swap, mask, palette swap, Spatial
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

Palette Swap: Post-Process, Image-Parametrized

2 Colour Palette Swap

Terrain Mesh Blending – Godot 4.3

Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Johnny Ryall
Johnny Ryall
2 months ago

If you want to layer this on top of an existing texture, simply add this near the top

render_mode blend_mul;