Shaders Shader: passing only one color SOLVED

T

Toxicosis

Guest
Hello,

I'm trying to do a shader that passes exactly one color, comparing the color to a list before drawing every pixel. If the color matches a parameter, it should draw a listed color, and if the color does not, it will draw a pixel with zero alpha. How could I go about this?

I tried using the Shaderific list of shader functions, available at http://www.shaderific.com/glsl-functions/ and picked the Equal function for this.

I tried it like this...

Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform vec3 color_read;
uniform vec3 color_draw;
const vec4 color_blank = vec4(0, 0, 0, 0);

void main()
{
    vec4 v_pointer = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
    vec3 mix_control = bvec3 equal(v_pointer.rgb, color_read); //WHEN I COMMENT OUT THIS LINE IT WORKS
    vec4 color_end = vec4 (color_draw.rgb, v_pointer.a);
    gl_FragColor = mix(color_blank, color_end, mix_control);
}
I get an unspecified error in line 16. The line highlighted is line 15, but commenting it out allows the compilation to proceed (given we comment out the gl_FragColor line too and use a different output).

The following variations on the bolded line also fail to compile.
Code:
vec3 mix_control = bvec3 equal(v_pointer.rgb, color_read);
vec3 mix_control = vec3 equal(v_pointer.rgb, color_read);
float mix_control = float equal(v_pointer.rgb, color_read);
float mix_control = float equal(v_pointer.r, color_read.r);
float mix_control = equal(v_pointer.r, color_read.r);
 (The last one throws up a different error message. Error : [F]Shader_shd_one_color(16) : 'equal' : no matching overloaded function found)
How do I use the equal function?
 
T

Toxicosis

Guest
Figured out the solution by looking at an existing shader. I was trying to do something completely unnecessary.

Though the editor won't highlight "if", it still recognizes that, and ==, and &&.

Code:
//
//Draw color_pass as color_in and ignore all other colors.
//

varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform vec3 color_pass;
uniform vec3 color_in;

void main()
{
  vec4 output = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
  if (color_pass.r == output.r && color_pass.g == output.g && color_pass.b == output.b)
  {
    output.r = color_in.r;
    output.g = color_in.g;
    output.b = color_in.b;
  }
  else
  {
    output.a = 0.0;
  }
  gl_FragColor = output;
}
 

Slyddar

Member
Thanks for posting your solution, as this is something I'm trying to do. What I can't work out though is how to pass the correct colour to the shader? I've tried dividing my the passing colour rgb values by 255 and passing that, but it still won't work. Could you advise the gml code for how you passed your color_pass and color_in variables please?
 

Slyddar

Member
Well I got there in the end. The equal sign when comparing the values was the problem, so I went with a range and it worked. Seemed like there must be a floating variance problem. Passing was done with the x/255 method. I'll post the code in case it helps someone else in the future :)

I've applied it to tiles by creating 2 shader objects, one called o_shader_start on a layer above the tile layer. This calls the shader. The other is o_shader_end and sits under the tiles layer. It turns the shader off.

SHADER
Code:
//
// Changes colour_pass to colour_in
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform vec3 colour_pass;    //colour to test for
uniform vec3 colour_in;    //colour to change a into
float range = 0.001;

void main ()
{
    vec4 base_colour = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
    if (abs(colour_pass.r - base_colour.r) < range && abs(colour_pass.g - base_colour.g) < range && abs(colour_pass.b - base_colour.b) < range)  {
        base_colour.r = colour_in.r;
        base_colour.g = colour_in.g;
        base_colour.b = colour_in.b; 
    }
    gl_FragColor = base_colour;
}
o_shader_start
CREATE
Code:
colour_pass_uni = shader_get_uniform(shader, "colour_pass"); // control shader
colour_in_uni = shader_get_uniform(shader, "colour_in"); // control shader
DRAW
Code:
shader_set(shader);
//Process the first colour change
shader_set_uniform_f(colour_pass_uni, 98/255,98/255,98/255);
//pass the new colour info
shader_set_uniform_f(colour_in_uni, 167/255,143/255,52/255);
o_shader_end
DRAW
Code:
shader_reset();
 
Last edited:
@TheSly :

This should be easier (although I haven't tested this thouroughly. Sorry if I made a mistake):

Create Event:
Code:
shader = shd_swap_colours;
old_col = [242/255, 101/255, 34/255];
new_col = [1, 1, 1];

u_old_col = shader_get_uniform(shader, "old_col");
u_new_col = shader_get_uniform(shader, "new_col");
Draw Event:
Code:
shader_set(shader);
shader_set_uniform_f_array(u_old_col, old_col);
shader_set_uniform_f_array(u_new_col, new_col);
draw_self();
shader_reset();
Fragment Shader:
Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform vec3 old_col;
uniform vec3 new_col;

void main() {
   vec4 base_col = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
 
   float is_equal = step(length(base_col.rgb - old_col), 0.001);
   // or this:
   //float is_equal = step(abs(base_col.r + base_col.g + base_col.b - old_col.r - old_col.g - old_col.b), 0.001);
 
   base_col.rgb = mix(base_col.rgb, new_col, is_equal);
 
   gl_FragColor = base_col;
}
In version 1 we subtract the vectors, get the length of the result and compare that to a tolerance of 0.001. If the length is less than the tolerance, then the colours are pretty much the same.

In version 2 we just add up and subtract all components and then compare that result with the tolerance. If the result is less than the tolerance, then the colours are pretty much the same again.

@Toxicosis : This method could be something for your shader as well.

All these functions and how to deal with floats and vectors are already covered in my weekly growing shader tutorial "Shaders for Hobby Programmers" by the way:
https://www.youtube.com/playlist?list=PL0kTSdIvQNCNE-BDKOlYu628AalMmXy_P
 
Top