GMS 2 blend modes

zendraw

Member
so we have a regular sprite with color, but we draw it with blend modes to be all white.
can blend modes do that or do i need to make a shader?
 

SoapSud39

Member
You can actually do it with blendmodes, using something like this:
GML:
var x2, y2;
x2 = x + sprite_get_width(spr_sprite);
y2 = y + sprite_get_height(spr_sprite);

//you can do this on a surface to manage it
draw_clear_alpha(c_black, 0);
draw_sprite(spr_sprite, 0, x, y);
gpu_set_blendmode_ext(bm_dest_alpha, bm_one);
draw_set_color(c_white);
draw_rectangle(x, y, x2, y2, false);
gpu_set_blendmode(bm_normal);
You can play around with the different blendmodes in the gpu_set_blendmode_ext() function, but I think this one works for what you want.
 

zendraw

Member
You can actually do it with blendmodes, using something like this:
GML:
var x2, y2;
x2 = x + sprite_get_width(spr_sprite);
y2 = y + sprite_get_height(spr_sprite);

//you can do this on a surface to manage it
draw_clear_alpha(c_black, 0);
draw_sprite(spr_sprite, 0, x, y);
gpu_set_blendmode_ext(bm_dest_alpha, bm_one);
draw_set_color(c_white);
draw_rectangle(x, y, x2, y2, false);
gpu_set_blendmode(bm_normal);
You can play around with the different blendmodes in the gpu_set_blendmode_ext() function, but I think this one works for what you want.
that turns the whole screen black for some reason.
 

SoapSud39

Member
I tried the code as-is with one of my sprites, and it makes it into a white silhouette, so it should work.

Are you maybe doing it with a surface? If you've messed up somewhere with x and y positions (object position, white rectangle position, draw position on surface, draw position of surface, etc.), you might just be misaligning something or drawing outside of the surface or even outside of the view. (if you'd like to post your code, in context, I or someone can take a look)
 

mikix

Member
Premultiply the alpha with shaders and then blend it with bm_one, bm_src_alpha. Something like that. If SoapSud39's code doesn't work. You can search on the forum, there is a guy that explains how to premultiply alpha.
 

zendraw

Member
this is the code
GML:
draw_clear_alpha(c_black, 0);
draw_sprite_ext(costume, -1, x, y, image_xscale, image_yscale, 0, -1, 1);

gpu_set_blendmode_ext(bm_dest_alpha, bm_one);

draw_set_color(c_white);
draw_rectangle(bbox_left, bbox_top, bbox_right, bbox_bottom, false);

gpu_set_blendmode(bm_normal);
the character is white, but the whole background is black. if i remove the draw clear alpha code it just puts a white rectangle on the screen which is understandable. so the draw clear alpha for some reason turns my screen on that specific layer black.

maybe your testing the code on a black background so you haven t noticed.
 
Last edited:

SoapSud39

Member
yeah I was testing it on a new project so that's my bad.

If you're set on using blendmodes, doing it on a different surface should fix the problem, so that the code doesn't clear the default application surface.
create surface --> set surface --> draw sprite --> set blendmode + draw rectangle + reset blendmode --> reset surface --> draw surface
The reason I thought you might have already been using surfaces is because of the offset coordinates that have to be considered when drawing on the surface and drawing the surface.

I'm not too experienced with blendmodes either, so I couldn't really figure out how to do it without draw_clear_alpha().
 
In case you want the shader solution, it's extremely simple. All you need to do is create a new shader asset, go to the fragment shader (the .fsh window), and replace the one line of code in the main function with this:
Code:
gl_FragColor = vec4(vec3(1.0), texture2D(gm_BaseTexture, v_vTexcoord).a);
 

zendraw

Member
In case you want the shader solution, it's extremely simple. All you need to do is create a new shader asset, go to the fragment shader (the .fsh window), and replace the one line of code in the main function with this:
Code:
gl_FragColor = vec4(vec3(1.0), texture2D(gm_BaseTexture, v_vTexcoord).a);
so i want to controll the amount of whiteness. im not sure if i just add a value 0 to 1 will that break the color, like if red ends up 1.4 or are they clamped betwean 0-1 by default.
 
so i want to controll the amount of whiteness. im not sure if i just add a value 0 to 1 will that break the color, like if red ends up 1.4 or are they clamped betwean 0-1 by default.
Colors in shaders are clamped 0.0-1.0. 0.0 = 0 (obviously) and 1.0 = 255. You'd have to modify the shader a bit if you want to get that effect, but the easier solution would be:
  • Draw normally the sprite you want to blend white
  • Draw a duplicate of the sprite you want to blend white with the shader I posted
  • Start with duplicate's alpha at 0 and increase it the more you want it white
EDIT: Fragment shader solution:
Code:
// In fragment shader
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform float WhiteBlend;

void main()
{
    vec4 Base = texture2D(gm_BaseTexture, v_vTexcoord);
    vec3 White = vec3(WhiteBlend);
    vec4 BlendedColor = vec4(Base.rgb + White.rgb, Base.a);
    gl_FragColor = BlendedColor;
}
GML:
// Create event of object drawing sprite
uWhiteBlend = shader_get_uniform(shd, "WhiteBlend");

// Draw event
var blendFactor = 0.5; // Just here for testing, you can modify this from elsewhere
shader_set(shd_white);
shader_set_uniform_f(uWhiteBlend, blendFactor);
  draw_sprite(sprSprite, 0, x, y);
shader_reset();
 
Last edited:

zendraw

Member
Colors in shaders are clamped 0.0-1.0. 0.0 = 0 (obviously) and 1.0 = 255. You'd have to modify the shader a bit if you want to get that effect, but the easier solution would be:
  • Draw normally the sprite you want to blend white
  • Draw a duplicate of the sprite you want to blend white with the shader I posted
  • Start with duplicate's alpha at 0 and increase it the more you want it white
EDIT: Fragment shader solution:
Code:
// In fragment shader
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform float WhiteBlend;

void main()
{
    vec4 Base = texture2D(gm_BaseTexture, v_vTexcoord);
    vec3 White = vec3(WhiteBlend);
    vec4 BlendedColor = vec4(Base.rgb + White.rgb, Base.a);
    gl_FragColor = BlendedColor;
}
GML:
// Create event of object drawing sprite
uWhiteBlend = shader_get_uniform(shd, "WhiteBlend");

// Draw event
var blendFactor = 0.5; // Just here for testing, you can modify this from elsewhere
shader_set(shd_white);
shader_set_uniform_f(uWhiteBlend, blendFactor);
  draw_sprite(sprSprite, 0, x, y);
shader_reset();
the shader replaces the alpha aswell.

Edit: that works perfect.
 
Last edited:
Top