• 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!

Shaders Recoloring sprites

Andymakeer

Member
Hi guys!

I'm using a shader to recolor my sprites but its not turning out the way i want.

This is what happening:
I have "bullet" sprites that i want them to change their color if they are "frozen".

These are them at normal state:


These is what I want them to become:

I got this using the Colorize tool from the sprite editor

Now the coding:

This is my shader:
Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform vec3 u_color;

void main()
{
    vec4 texColor = texture2D(gm_BaseTexture, v_vTexcoord);
    gl_FragColor = v_vColour * vec4(u_color.rgb, texColor.a);
}
and this is my code on draw event:
Code:
if freeze_amp < 1
{
    shader_set(shader_Recolor);
    shader_set_uniform_f(_uniColor, 66 / 255, 236 / 255, 225 / 255);
    
}
draw_self();
shader_reset();
Those numbers on uniform are the RGB color divided by 255 (parsing to shader color).

But ingame the result is this:


The black borders around the bullets are being recolored too, which is NOT what I want.
Basically, I want THE SAME EFFECT that happens when you use the Colorize tool from the sprite editor.

Help me please ;-;
 

Cat

Member
You need to multiply gl_FragColor by texColor, e.g.
Code:
gl_FragColor = texColor * v_vColour * vec4(u_color.rgb, texColor.a);
 

Joe Ellis

Member
Colorizing is a different thing than simply multiplying one color with another. It essentially gets the hue, sat and lum of each pixel, then sets the hue to the chosen value.
I've got code for that if you wanna see, and you can also look it up online, that's what I did
 

Andymakeer

Member
Colorizing is a different thing than simply multiplying one color with another. It essentially gets the hue, sat and lum of each pixel, then sets the hue to the chosen value.
I've got code for that if you wanna see, and you can also look it up online, that's what I did
i want to see the code, plssss
 

Joe Ellis

Member
I use these scripts in my project for the color picker:

Code:
///color_get_hsl(color)

//Takes standard gamemaker color and returns an array of [hue, sat, lum]

var _color = argument0;

var
r = colour_get_red(_color) / 255,
g = colour_get_green(_color) / 255,
b = colour_get_blue(_color) / 255,
_min, _max, _range, hue, sat, lum, hsl;

_min = min(r, g, b)
_max = max(r, g, b)
_range = _max - _min

lum = (_max + _min) / 2

if _range = 0
{
hue = 0
sat = 0
}
else
{

if lum < 0.5
{sat = _range / (_max + _min)}
else
{sat = _range / (2 - _max - _min)}

if r = _max
{
if g > b
{hue = (g - b) / _range}
else
{hue = 6 - ((b - g) / _range)}
}
else
{
if g = _max
{hue = 2 + (b - r) / _range}
else
{hue = 4 + (r - g) / _range}
}
if hue < 0
{hue++}
if hue > 6
{hue--}
}

hsl[0] = round(hue * 255) //the multiplication here isn't that important if you're just using this in a shader
hsl[1] = round(sat * 255) //it's just to make more sense in a color picker
hsl[2] = round(lum * 510)

return hsl
Code:
///make_color_hsl(hue, sat, lum)

//again, here the input values can range from 0-1 instead
var hue = argument0 / 1530, sat = argument1 / 255, lum = argument2 / 510, r, g, b, tr, tg, tb, t1, t2;

if lum < 0.5
{t1 = lum * (1.0 + sat)}
else
{t1 = lum + sat - lum * sat}

t2 = 2 * lum - t1

tr = hue + 0.333
tg = hue
tb = hue - 0.333

if tr > 1
{--tr}
if tg > 1
{--tg}
if tb > 1
{--tb}

if tr < 0
{++tr}
if tg < 0
{++tg}
if tb < 0
{++tb}


//Red
if 6 * tr < 1
{r = t2 + (t1 - t2) * 6 * tr}
else
{
if 2 * tr < 1
{r = t1}
else
{
if 3 * tr < 2
{r = t2 + (t1 - t2) * (0.666 - tr) * 6}
else
{r = t2}
}
}

//Green
if 6 * tg < 1
{g = t2 + (t1 - t2) * 6 * tg}
else
{
if 2 * tg < 1
{g = t1}
else
{
if 3 * tg < 2
{g = t2 + (t1 - t2) * (0.666 - tg) * 6}
else
{g = t2}
}
}

//Blue
if 6 * tb < 1
{b = t2 + (t1 - t2) * 6 * tb}
else
{
if 2 * tb < 1
{b = t1}
else
{
if 3 * tb < 2
{b = t2 + (t1 - t2) * (0.666 - tb) * 6}
else
{b = t2}
}
}

r *= 255
g *= 255
b *= 255

return make_color_rgb(r, g, b)
I basically copied this code from easyrgb.com. So I can't really explain very well what they're doing and why.
But for colorizing, you might not need the math for calculating the hue, which takes up most of that code. If you want the whole image to be the one hue, you can just use the code for getting the sat & lum, then apply those to a new hue:

Code:
///color_get_sat(color)

var _color = argument0;

var
r = colour_get_red(_color) / 255,
g = colour_get_green(_color) / 255,
b = colour_get_blue(_color) / 255,
_min, _max, _range, lum, sat;

_min = min(r, g, b)
_max = max(r, g, b)
_range = _max - _min

lum = (_max + _min) / 2

if _range = 0
{sat = 0}
else
{
if lum < 0.5
{sat = _range / (_max + _min)}
else
{sat = _range / (2 - _max - _min)}
}

return sat
Code:
///color_get_lum(color)

var _color = argument0;

var
r = colour_get_red(_color) / 255,
g = colour_get_green(_color) / 255,
b = colour_get_blue(_color) / 255,
_min, _max, _range, lum;

_min = min(r, g, b)
_max = max(r, g, b)
_range = _max - _min

lum = (_max + _min) / 2

return lum
So here's those things put into a shader, and code for applying sat & lum to an rgb color(or hue):

Code:
varying vec2 v_vTexcoord;

uniform vec3 hue;

void main()
{

vec3 color = texture2D(gm_BaseTexture, v_vTexcoord).rgb;

//First get the sat & lum of the color
float _min = min(color.r, color.g, color.b);
float _max = max(color.r, color.g, color.b);
float _range = _max - _min;
float lum = (_max + _min) * 0.5;
if (_range == 0.0)
{
sat = 0.0;
}
else
{
if (lum < 0.5)
{sat = _range / (_max + _min)}
else
{sat = _range / (2 - _max - _min)}
}

//Then create a new color using the uniform hue with the found sat & lum

//First apply the lum (blend towards black or white)
if (lum > 0.5)
{
color = mix(hue, vec3(1.0), (lum * 2.0) - 1.0);
}
else
{
color = hue * lum * 2.0;
}

//Then apply the sat (blend towards grey)
color = mix(vec3(lum), color, sat)

gl_FragColor = vec4(color, 1.0);
}
This shader will be fine for basic colorizing where you just want to set a sprite to one certain hue.
If you want to adjust the sat & lum, you can add 2 extra uniforms which affect the sat & lum(adding or multiplying).
But if you want to shift the hue, you'd need to put the hue detecting code from "color_get_hsl" into the shader, then shift the hue, recalculate the rgb values for it, then apply the sat & lum. I didn't want to send code for that straightaway in case you don't need to do that, but if you do just let me know.

I hope that code I sent helps
 

2DKnights

Member
You may be able to do this using the blendmode functions to subtract out the right amount of red and green to make your objects appear the correct color just remember to reset after drawing so nothing else is affected. Might not be as efficient as shaders though, not sure.
 
R

robproctor83

Guest
The easiest thing would be to just change image_blend = c_aqua and it will shift the hue of the sprite, however it most likely won't get you the results you want. If you only need to shift the hue and retain the lightness I would use a shader like Joe posted. However, if you think you might need to swap color palettes at some point it might be worth looking into the link below. If you had a red and blue sprite and you wanted to shift the red to blue and the blue to yellow you would need to use something like this, otherwise you would only be able to get a blue and green sprite, or all blue or all yellow, but not blue and yellow.

https://marketplace.yoyogames.com/assets/1661/retro-palette-swapper
 
Top