Sprite3D Color Swap & Rainbow Shader
This is a shader I made for myself and wanted to share in case anyone was looking for something similar, wasn’t able to find any good Sprite3D color swap shaders so I took a bunch of snippets from different shaders and sort of frankensteined them together
How to use:
1. Create a ShaderMaterial as a material override onto a Sprite3D or AnimatedSprite3D and apply this shader onto it
2. Set Sprite Texture as the sprite of the Sprite3D texture, or the sprite sheet if it’s an AnimatedSprite3D
The shader will only color swap the hue values between min and max values (.5 is cyan-ish and 1.0 is red), this is great if you want to change the colors of specific portions of a sprite
Shader code
//amalgamation of these shaders:
//https://godotshaders.com/shader/billboard-sprite3d-hitflash-godot-4-x/
//https://godotshaders.com/shader/color-range-swap/
//https://godotshaders.com/shader/rainbow-outline/
shader_type spatial;
render_mode unshaded;
uniform bool y_billboard = false;
uniform bool rainbow = false;
uniform float rainbow_frequency : hint_range(0.1, 2.0) = 0.5;
uniform float rainbow_blend : hint_range(0.1, 2.0) = 0.5;
//billboard
void vertex() {
if (y_billboard == true) {
MODELVIEW_MATRIX = VIEW_MATRIX * mat4(vec4(normalize(cross(vec3(0.0, 1.0, 0.0), INV_VIEW_MATRIX[2].xyz)), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(normalize(cross(INV_VIEW_MATRIX[0].xyz, vec3(0.0, 1.0, 0.0))), 0.0), MODEL_MATRIX[3]);
}
else {
MODELVIEW_MATRIX = VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0], INV_VIEW_MATRIX[1], INV_VIEW_MATRIX[2], MODEL_MATRIX[3]);
}
MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);
}
uniform float _min;
uniform float _max;
uniform sampler2D spriteTexture: source_color, filter_nearest;
uniform vec4 color : source_color;
//color swap
vec3 rgb2hsv(vec3 c)
{
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 hsv2rgb(vec3 c)
{
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
vec4 to_gray(vec4 tex)
{
float avg = (tex.r + tex.g + tex.b) / 3.0;
return vec4(vec3(avg),tex.a);
}
vec4 to_color(vec4 gray, vec4 col)
{
return gray * col;
}
void fragment()
{
vec4 tex = texture(spriteTexture, UV);
vec3 hsv = rgb2hsv(tex.rgb);
vec4 color_set = vec4(1,1,1,1);
if (rainbow == true) {
vec4 rainbow_color = vec4(sin(2.0*3.14*rainbow_frequency*TIME),
sin(2.0*3.14*rainbow_frequency*TIME + radians(120.0)),
sin(2.0*3.14*rainbow_frequency*TIME + radians(240.0)),
1.0);
color_set.rgb = mix(color.rgb,rainbow_color.rgb,rainbow_blend);
}
if (hsv.r >= _min && hsv.r <= _max)
{
tex = to_gray(tex);
tex = to_color(tex, color * color_set);
}
//changed COLOR = tex; to the two lines below to convert it from canvas to spatial
ALBEDO = tex.rgb;
ALPHA = tex.a;
}


