[SOLVED] Subtract Blend Mode

S

Samus

Guest
I'm working on an improved lighting system in my game. Footage:
https://gph.is/2LcYwii

It looks good, I think, but I want a gradient circle. I used draw_circle_colour with both black and white, and I set the blend mode to subtract, thinking this would subtract a gradient circle from the black rectangle I had already drawn on the surface. I've tried this before, and I've seen it done in basically all lighting tutorials I've ever watched, but it just isn't working for me, it punches a flat gradient-less circle in the surface. Here is the code:

Code:
///In the Begin step event
surface_free(global.shadow);
global.shadow = surface_create(1024, 768);

//Draw lighting sprite
surface_set_target(global.shadow)
draw_set_color(c_black);
draw_rectangle(0, 0, room_width, room_height,false);
draw_set_color(c_white);
draw_set_blend_mode(bm_subtract);
draw_circle_colour(obj_player.x, obj_player.y, 160, c_white, c_black, false);
draw_set_blend_mode(bm_normal);
Code:
///In the End Step event
//Reset target
surface_reset_target();
Code:
///In the Draw Event
//draw_set_blend_mode(bm_one);
draw_surface(global.shadow, 0, 0);
Any help is appreciated, Thanks!
 
Hi. You can't subtract from black, because it's already zero. What I think is going on there is you are subtracting 1.0 from 1.0 alpha, leaving a circular "hole" in your surface with no opacity.

EDIT: What is needed is a gradient to the amount of alpha being subtracted along the radius of the circle.
 
Last edited:
S

Samus

Guest
Thanks for the reply! I had tried changing the color of the rectangle, but that had the same effect, so I gave up on it. I did not, however, change the alpha. Changing the color and the alpha created the circle gradient I was looking for. I was hoping to have a solid black rectangle, not a semi-transparent dark grey though. Do you think I could somehow use one of the other blend modes? Thanks!
 
S

Samus

Guest
Doesn't seem to work, which is probably because that turns off the colors needed to draw white, and I was relying on the gradient between white and black on the circle subtracted from the black rectangle. It would be awesome if there was something like draw_circle_ext that let you define the alpha near the end, but I haven't found anything like that in the documentation...
 
S

Samus

Guest
How do I create that sprite? I can do a color gradient in the editor, but can't seem to find an option for an alpha gradient.
 
S

Samus

Guest
I see the edit now, lol. Didn't know it was possible to have a negative alpha, I'll try it!
 
M

MirthCastle

Guest
I think some of his issue is that last bm_one thats in the draw event. it isn't needed i don't think.

either way:
//Draw lighting sprite
surface_set_target(global.shadow)
draw_clear_alpha( c_black, 1)
draw_set_blend_mode(bm_subtract);
draw_circle_colour(obj_player.x, obj_player.y, 160, c_white, c_black, false);
draw_set_blend_mode(bm_normal);
surface_reset_target(); < why was this somewhere else?

bm_subtract works by percentage - it doesn't subtract directly - the more WHITE the sprite you are subtracting - the higher percentage reduction you get.

You have to set the draw_clear_alpha to 1, so that there is alpha channel to subtract from. Set it lower if you want to see other areas better.

See if the below works too (after you try @flyingsaucerinvasion )

 
Hi again Samus... So I think to handle multiple lights, it would actually be better to use the subtract blend mode, and to invert the alpha of that sprite. To something like this:

upload_2018-7-13_18-44-33.png
I made that sprite using photoshop, by making the whole thing black, and then giving it an alpha mask.

EDIT: when I said invert the opacity of the mask what I mean was new alpha = 1 - old alpha. And the actual color, since this'll be using the subtract blending mode, does not matter, if you start with a black background, since you can't subtract anything from zero. Note: Like other poster said, the "subtract" blending mode is not truely subtraction. The formula for our subtraction blending mode is actually:

colour = source * zero + destination * (1 - inverse source colour ).

which is pretty different from true subtraction, which should look more like:

colour = destination - source
 
Last edited:
M

MirthCastle

Guest
<- wishes he would come off the 20 bucks/mo for photoshop - it makes such nicer gradients than GIMP.... but i cant seem to make myself lol


Yeah you need subtract like @flyingsaucerinvasion just said, the draw_clear_alpha(c_black, 1), and you need a white sprite.

actually - i think black would work cause our focus is opacity... its the alpha channel were interested in.
 
Last edited by a moderator:
S

Samus

Guest
@MirthCastle , very informative response, thank you. You can see that the bm_one part is commented out, its left over from when I was experimenting with something else, I figure I'll delete it completely once I have this done. The reason I put the reset_target part in another event was because I'm also using dynamic lighting. Other objects draw shadows onto that surface in the step event, in between the step begin and step end. Kind of complicated I guess. :/ I will try using draw_clear_alpha, that makes sense. Though it seems like the same thing as drawing a rectangle, just less complicated.

@flyingsaucerinvasion Oh yeah, I don't have photoshop, so I can't quite do that in GMS's sprite editor, lol.
 
You could just use the sprite I posted there, since all you'd need to do is scale it up or down a bit. I'm not familiar with GIMP, but I'm surprised you can't do this kind of thing easily with that program. If you really need a specific sprite of a certain size or shape or whatever, I'm not doing anything else at the moment, so I could make one for you real quick.
 
M

MirthCastle

Guest
GIMP doesn't give you an option to "set the size" you have to eyeball the whole thing. :/

It makes you weep when you spent forever getting a real nice gradient, to find out the damn thing is cut off on a side and you cant tell real easy until you've gone through and load it up onto the surface.
 
S

Samus

Guest
@flyingsaucerinvasion Thanks man, that won't be necessary, I can resize the one you provided. (I didn't think about downloading it lol). Thank you though! I'm not using Gimp, I'm using GMS1.4's sprite editor. Should probably look at Gimp some time because GMS1.4's sprite editor is kind of lackluster. GMS2's sprite editor is great for pixel art but falls short of being useful for much else.

@MirthCastle Appreciate the blog link! I will read it and work on this some more. :)

Worst case scenario I've come up with a crazy idea to use a while loop to draw a series of circles and create my own gradient alpha through code. Thanks guys!
 
Top