Shaders Simple Color Replacement Shader

A

AzureCube

Guest
Hello,

I am currently using GMS 1.4.9999 and I wish to create a simple shader that replaces every black pixel in a sprite with white and then converts the sprite to grayscale. By searching the Internet, I have found a functional grayscale shader (code included below). However, I have not figured out how to convert all black pixels to white.

Does anyone know a simple way of testing the color of a pixel and, only if it is a certain value, changing that pixel to a different color?

Grayscale shader code (/3.5 to darken from default value):

Fragment shader:
varying vec2 vTc;
void main() {
vec4 irgba=texture2D(gm_BaseTexture,vTc);
float luminance=dot(irgba.rgb,vec3(0.2125,0.7154,0.0721));
gl_FragColor=vec4(luminance/3.5,luminance/3.5,luminance/3.5,irgba.a);
}

Vertex shader:
attribute vec4 in_Position;
attribute vec2 in_TextureCoord;
varying vec2 vTc;
void main() {
gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * in_Position;
vTc = in_TextureCoord;
}
 

Xor

@XorDev
Hello.

I would use ternary to check if the gray value is below a black threshold and set it to white.
Here's an example fragment shader:
Code:
varying vec2 vTc;

void main()
{
    //Sample texture.
    vec4 tex = texture2D(gm_BaseTexture,vTc);

    //Calculate grayscale luminance value (https://en.wikipedia.org/wiki/Grayscale#Luma_coding_in_video_systems)
    float gray = dot(tex,vec4(.299,.587,.114,0));
    //Black is considered anything darker than this value:
    const float black = .01;
    //If gray is greater than black then do nothing, otherwise set gray to 1.0 (white).
    gray = (gray>black) ? gray : 1.;
    //You can divide gray by 3.5 here if you want the white result to be unaffected.
   
    //Darken the grayscale result.
    gl_FragColor = vec4(vec3(gray/3.5),tex.a);
}
I hope this helps!

-Xor
 
  • Like
Reactions: Yal
A

AzureCube

Guest
Hello,
Thank you both for your help. The color replacement effect now works properly. However, the shader does not take into account the alpha at which the sprite is being drawn ( image_alpha or draw_set_alpha() ).
How might that be implemented?

Shader Code:
Fragment Shader:
varying vec2 vTc;
void main()
{
vec4 irgba=texture2D(gm_BaseTexture,vTc);
float luminance=dot(irgba.rgb,vec3(0.2125,0.7154,0.0721));
gl_FragColor=vec4(luminance/4.5,luminance/4.5,luminance/4.5,irgba.a);
if (gl_FragColor.rgb == vec3(0.0))
{
gl_FragColor=vec4(1.0,1.0,1.0,irgba.a);
}
}

Vertex Shader:
attribute vec4 in_Position;
attribute vec2 in_TextureCoord;
varying vec2 vTc;
void main() {
gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * in_Position;
vTc = in_TextureCoord;
}
 
If you want image_alpha or draw_set_alpha to have any effect, then just getting the alpha value out of the texture alone is not enough.

You'll want to add an in_Colour vec4 attribute to the vertex shader. Then, you'll need to pass at least the alpha component of that attribute as a varying variable to the fragment shader. The final alpha should be irgba.a * that_varying_variable (if a float, or that_varying_variable.a if a vec4 rgba).
 
  • Like
Reactions: Xor
Top