Shaders [solved] Shader to replace a specific colour for a specific colour?

hdarren

Member
So something I would like to do is for my character I would like to be able to add the option of changing the hair colour amongst other things. I would like it to be specific colours though which due to the different colours having different brightnesses I can't use image_blend. Does anybody know how to do such a thing with a shader? I am very lost. Thank you for any assistance!
 

rIKmAN

Member
So something I would like to do is for my character I would like to be able to add the option of changing the hair colour amongst other things. I would like it to be specific colours though which due to the different colours having different brightnesses I can't use image_blend. Does anybody know how to do such a thing with a shader? I am very lost. Thank you for any assistance!
Not sure if you only want to write it yourself, but I would recommend grabbing Pope's Retro Palette Swapper.
It's not free but is only $3.99 and is a great tool whether you want to use it as-is or learn from it.
 

hdarren

Member
That seems rather heavy duty. I was hoping I can just do a shader where I add an input/output colour and it would do that for me. Probably 2/3 colours max. Having to create a bunch of palette sprites isn't ideal for what I am hoping for. But thank you for letting me know about that.
 

rIKmAN

Member
That seems rather heavy duty. I was hoping I can just do a shader where I add an input/output colour and it would do that for me. Probably 2/3 colours max. Having to create a bunch of palette sprites isn't ideal for what I am hoping for. But thank you for letting me know about that.
No problem.

Just a Google search for "Gamemaker palette swap shader" or "Gamemaker colour swap shader" and following your nose (even to threads on here) should give you some tutorials and loads of info and code on how to go about it.
 

Xor

@XorDev
Hi!
I made a quick shader example (untested) which should fulfill your needs!
Here's the fragment shader code with comments to explain it:
Code:
/*
    Simple color replace shader by Xor (@XorDev)
*/

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform vec4 color_old1;//r,g,b of color1 to replace, tolerance between 0 and 1.
uniform vec3 color_new1;//r,g,b of the new color1.

uniform vec4 color_old2;//r,g,b of color2 to replace, tolerance between 0 and 1.
uniform vec3 color_new2;//r,g,b of the new color2.

void main()
{
    //Sample the texture.
    vec4 sample = texture2D(gm_BaseTexture,v_vTexcoord);
   
    //Find the color difference between the sample and the color_old1.
    float diff = dot(abs(sample-color_old1).rgb,vec3(1./3.));
    //Set the color_new1 when the the difference is greater than the tolerence.
    vec3 color = mix(sample.rgb,color_new1,step(diff,color_old1.w));
   
    //Find the color difference between the sample and the color_old2.
    diff = dot(abs(sample-color_old2).rgb,vec3(1./3.));
    //Set the color_new2 when the the difference is greater than the tolerence.
    color = mix(color,color_new2,step(diff,color_old2.w));
   
    //This can be repeated as necessary.
   
    //Use the new color with the sample alpha and the vertex color (v_vColour).
    gl_FragColor = v_vColour * vec4(color,sample.a);
}
And incase you don't know, step is a function that return 0.0 when argument0>argument1 and 1.0 otherwise.
dot multiplies vector1 with vector2 and adds all the components like: a.x*b.x+a.y*b.y+a.z*b.z.
I hope this helps!
 

hdarren

Member
Hi Xor. Thank you for taking time to write this! I am not understanding how to implement it though.

I am writing this in the Create event
Code:
color_old1 = shader_get_uniform(shd_ColourSwap,"color_old1");
color_new1 = shader_get_uniform(shd_ColourSwap,"color_new1");
And in the Draw event this
Code:
shader_set(shd_ColourSwap);
shader_set_uniform_f(color_old1,make_color_rgb(173,92,92));
shader_set_uniform_f(color_new1,make_color_rgb(200,200,200));
draw_self();
shader_reset();
But it doesn't seem to do anything. Am I not implementing it correctly? Thank you for any assistance.
 

Xor

@XorDev
The shader uses an RGB format rather than the hexadecimal color format GM uses. This shader uses 3 separate numbers between 0 and 1 for the red, green and blue values. Also, don't forget to set the old color tolerance value! Something like this will do (Draw Event):
Code:
shader_set(shd_ColourSwap);
shader_set_uniform_f(color_old1,173/255,92/255,92/255,10/255);
shader_set_uniform_f(color_new1,200/255,200/255,200/255);
draw_self();
shader_reset();
So I divide each channel by 255 to make sure it's between 0 and 1. I also added a tolerance of 10, but you can do any value of course!
 

Joe Ellis

Member
You could make 2 uniforms: 2 palettes, make a for loop in the pixel shader, check the pixel is each color, if so change to the color in the other palette at that same index
 
I have a problem that is similar like this, I want to be able to change specific RGB index colors of my .gif using GML, so that I dont have to use multiple images for my game that are the same but use different colors. But I have no idea if GML has an invention for this. For instance, an example of some old artwork that I did for a game , that I am going to have to redo ... looks like this :

Mil_r7.GIF Pmi_r7.GIF Pop_r7.GIF

Its the same picture, but with different colors. These are background pics. I did this long ago using Electronic Arts , Deluxe Paint . But thats what I want to do.

So can I just use one picture and then use GML to control the RGB colors of specific index palette range? I keep my gray scale the same, but I change the dithering spread of one color to another one, using Deluxe Paint. Notice the difference in green tones in my 2nd and 3rd pics, where as my 1st pic is a red toned dithering between a dark shade of red to a light shade of red.
 

hdarren

Member
The shader uses an RGB format rather than the hexadecimal color format GM uses. This shader uses 3 separate numbers between 0 and 1 for the red, green and blue values. Also, don't forget to set the old color tolerance value! Something like this will do (Draw Event):
Code:
shader_set(shd_ColourSwap);
shader_set_uniform_f(color_old1,173/255,92/255,92/255,10/255);
shader_set_uniform_f(color_new1,200/255,200/255,200/255);
draw_self();
shader_reset();
So I divide each channel by 255 to make sure it's between 0 and 1. I also added a tolerance of 10, but you can do any value of course!
Incredible it works perfectly thank you so much!!! :D
 
  • Like
Reactions: Xor
Top