• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Shader - replace one color.

I'm having a difficult time understanding shaders. I've seen numerous video tutorials online and example code, but still feel lost. Here's what I know thus far:

My_Shader.vsh is untouched. The following is written under My_Shader.fsh:

Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
   
   vec4 Base_Color = texture2D( gm_BaseTexture, v_vTexcoord );
   
   float Red = 0.0;
   float Green = 0.0;
   float Blue = Base_Color.b;
   float Alpha = 1.0;
   
   vec4 New_Color = vec4(Red, Green, Blue, Alpha);
    gl_FragColor = New_Color;
}
In the "Draw" event of my object I have:

Code:
shader_set(shader_test);
draw_self();
shader_reset();
I ran it successfully and it changes the entire sprite a shade of blue. However, I would only like to change yellow hex color FFF200 (which I obtained from my sprite) to the original blue found within the sprite.

I believe I do not have to modify My_Shader.vsh and all code to change yellow to blue needs to be within the My_Shader.fsh code above in main(). I am confused as to how to loop through each pixel to find the yellow value to replace. My understanding is limited at this point and any info would be greatly appreciated.

Thank you!
 
You've got to check if the texture color is equal to your test_color.

Now, under some circumstances you might not get correct results making a direct check for equality between two vec3 colors. So, what I've got here is a measure of the diffference between the two colors. And then, I couldn't think of a more straightforward way, so I check if the dot product of that difference with itself is less than a small value. If it is, then I consider the colors equal, and in that case, the mix function will replace color.rgb with whatever the value of replace_color is.

vec4 color = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
vec3 diff = color.rgb - test_color;
float equality = float(dot(diff,diff) < 0.00001);
color.rgb = mix( color.rgb, replace_color, equality );
 
I tried your suggestion a few different ways with no luck. I'm not quite sure how to implement it, but I think I have to set a shader uniform in the object.
 
There are two colors you need to define. The test_color, which is the color to be replaced. And then the replace_color, which is the color that replaces it. They can be uniforms or constants, but they should be vec3's. If you are using colors with components that come in the range 0-255, be sure to divide by 255.
 
Yes, that is what I am having trouble with. I am unable to correctly define the colors. I tried to define them in main() unsuccessfully. Is that where they need to be defined? I'm not clear on how or where. May you please provide an example code?
 
put your constants or uniforms above main.

example of constant:

const vec3 replace_color = vec3( 0.532, 0.12, 0.644 );

example of uniform variable:

uniform vec3 test_color;

setting uniform in gml:

shader_set( shader_name );
shader_set_uniform_f( shader_get_uniform( shader_name, "test_color" ), 0.135, 0.762, 0.123 ); //can put shader_get_uniform in create event if you'd like.
//draw stuff here
 
I appreciate the quick responses. No errors! But not the expected results. This is what I have in the shader:

Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

const vec3 replace_color = vec3( 0.0, 0.0, 0.0 ); //all zero's, which should be black.
uniform vec3 original_color;

void main()
{
   vec4 color = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
   vec3 diff = color.rgb - original_color;
   float equality = float(dot(diff,diff) < 0.00001);
   color.rgb = mix( color.rgb, replace_color, 0.25 );
    gl_FragColor = color;
}
This is what I have in the draw event of the object:
Code:
shader_set_uniform_f( shader_get_uniform( shader_test, "original_color" ), 255.0, 255.0, 255.0 ); //all 255, which should be white.
shader_set(shader_test);
draw_self();
shader_reset();
I've changed the numbers a bit, and it is affecting every color of the sprite. Just to test and learn about shaders, I'm attempting to replace white with black. Finally, I'm starting to understand a bit more now. Any further guidance would be much appreciated.
 
Two problems, but easy to fix.

-----------------

Problem #1 is in the fragment shader.

color.rgb = mix( color.rgb, replace_color, 0.25 );

The purpose of the mix function here was to replace color.rgb with replace_color in the event that equality == 1.0.

Because you've changed the third argument to a constant, it will always move color.rgb 25% of the way toward replace_color, regardless of what the original value of color.rgb was.

I gather that you wanted to move 25% toward replace_color when color == original_color. Is that correct? In that case, replace the faulty mix function arguments with this:

color.rgb = mix( color.rgb, replace_color, equality * 0.25 );

-------------------

Problem #2 is with the values you are using to set the color of "original_color".

There, you are using a range of 0-255 for each of your color components (r,g,b). However, inside of a shader, a colors sampled from a texture have components in a range from 0 to 1. So to convert your color into the same range, divide each color component by 255. White would thus have a value of (1,1,1).

------------

A possible complication could come from your use of the v_vColour multiplication with the texture color. If image_blend is anything other than white, it will change the value of "color", and therefore your tests for equality with "color" wont work as you probably expect them to.
 
Last edited:
I've been very busy as of late; sorry for the late response. However, things are finally starting to click. Thanks much for the info.
 
Top