[Solved] alpha blending and surfaces(?)

B

basement ape

Guest
I'm having trouble drawing sprites with semi-transparent pixels over opaque background sprites. What happens is, any pixel with an alpha value > 0 and < 1 will punch a hole through anything behind it on that surface, leaving those areas fully transparent.

Like this (see the outlines around the light shades on the wall):
alphabug.png

From looking around the forum, it seems this issue is caused by the way surface alpha blending get processed on the gpu or some such. I've tried to turn all blending off while drawing application_surface...

Code:
gpu_set_blendenable(false);
draw_surface(application_surface, 0, 0);
gpu_set_blendenable(true);
... and also while drawing the offending sprites...
Code:
gpu_set_blendenable(false);
draw_sprite_ext(spr_wc_floor5_lights, 0, m_x, m_y, 1, 1, 0, c_white, 1);
gpu_set_blendenable(true);
... but so far no luck. The sprite outline still carves it's way through whatever's behind it. Anyone know what to do about this?
 
D

Deleted member 13992

Guest
what does it look like with pixel interpolation turned off?
 

Tsa05

Member
On your surface:
Code:
draw_clear_alpha(c_black,0);
gpu_set_blendmode(bm_add);
// Draw each image, in order, onto your surface

gpu_set_blendmode(bm_normal);
gpu_set_colorwriteenable(1,1,1,0);
// Draw each image, again, in order, onto your surface

// Return to normal drawing behaviour
gpu_set_blendenable(true);
gpu_set_colorwriteenable(1,1,1,1);
//Draw surface to screen as needed
 
B

basement ape

Guest
Thanks for your suggestions. I tried them both but unfortunately I couldn't get either to work, tho Tsa05's solution did give me a nice rainbow effect in the areas I'm not drawing to.

Yep, just did...

So if I understand things correctly alpha blending works like this; "(alpha_1 + alpha_2) / 2 = blended". And that means a pixel of alpha value 0.5 that gets blended with a completely opaque one will end up as a pixel of alpha value 0.75. I guess that explains why otherwise opaque background pixels suddenly go transparent in my case. Except not really, because fully transparent pixels in a sprite overlaid on fully opaque ones don't result in 0.5 transparency. And sprites drawn with for instance 50% transparency like so...
Code:
draw_sprite_ext(spr_player, 0, 100, 200, 1, 1, 0, c_white, 0.5);
... will also blend correctly with things behind them.

I'm confused. Maybe this is all too much for my brain to handle :p But if it's this involved just to draw a few poor semi-transparent pixels to screen correctly then how on earth do other people pull it off in their games?
 

Tsa05

Member
It's not hard to draw semi-transparent pixels to the screen, but I think that something is not quite being described precisely here in the nature of the problem.

The Application surface has no alpha channel (you can't see through the whole game). So when you draw a graphic with transparency onto the application surface, the transparency is lost. More precisely, it gets blended with any colors already drawn below it and the blended result is drawn fully opaque.

Other surfaces do have transparency. So, when you write data to them, you change their alpha as well as other values. I think that you slready have gotten all of this. Drawing a 0.5 alpha pixel onto a 0.5 alpha pixel will *not* get you a 0.5 alpha pixel.

I'm making the assumption that you want to combine several sprites, each containing transparency, onto a single surface, and then draw that surface to the screen. To that end, I recommended my method:

1) Each graphic is drawn to the surface using additive blending. This makes a mess of the colors, but sets up the alpha values of the surface to be the additive result of all transparent graphics you wanted to draw.

2) Once the surface's alpha is set correctly, change blending back to the normal mode, but this would overwrite color *and* alpha, sooooo

3) Disable writing alpha data. Then re-draw all of the graphics that should be combined on the surface. So, basically, write all their color info to the surface and leave the alpha set just the way it was.

At this point, you have a surface with multiple images (each containing various alpha info) drawn together.

To use this in your game, you'd have to get everything back to normal--reset your drawing target, re-enable blending, make sure you're in bm_normal...and then draw the surface to the screen. The method I've posted is taken directly from my own engine, which composites character sprites together from multiple parts that have partial transparency. Definitely works, but might not be the same kind of thing you are actually trying to do.

If you are continuing to have difficulty, we will likely need to see the images that you are trying to blend, and the code that you are trying to use. Hard to troubleshoot a report of non-working code without seeing what the code was that you tried, and what you tried using it on.
 
B

basement ape

Guest
Thanks a lot man for the comprehensive write-up! I really appreciate that.

I just had another, proper crack at it and now it's working :)
 
S

silverfrost

Guest
I'd tried many solutions posted here on forum and from google search to solve this problem with semi-transparent objects overlapping on surface (explosion ground textures). After hours of tries I'd come to this solution:
Code:
surface_set_target(your_surface);
draw_set_alpha_test(true); //enable alpha testing
draw_set_alpha_test_ref_value(0); //draw all transparent pixels
draw_set_blend_mode_ext(bm_src_alpha, bm_one); //this combination works on mobile devices
draw_sprite_ext(your_sprite, 0, x, y, 1, 1, 0, c_white,1); //draw your semi-transparent sprites here
//return drawing mode to normal
draw_set_blend_mode(bm_normal);
draw_set_alpha_test(false);
surface_reset_target();
This thread is indexed in google search, so I hope this helps someone.
 

Bapsilon

Member
Thank you So Much guys...
I've been struggling with this for DAYS in a script I made to create sprites from a surface for use in menus and stuff...

My Score Table Sprite making script now looks like this and works properly...

Code:
/// @function scr_Make_Table_Sprite("Rank","Name","Score","Font",Colour,Sprite_width,Sprite_height,Shadow(bool))
/// @description Make a sprite from surface and return index(The Text,The Sprite Name);
/// @param {string} "The Player Rank";
/// @param {string} "The Players Initials";
/// @param {string} "The Players Score";
/// @param {variable} "The Font";
/// @param {variable} "The Colour of the Text";
/// @param {real} "The Sprite and Suface Width";    //540 should be enough
/// @param {real} "The Sprite and Suface Height";   //32 is Definitely enough
/// @param {boolean}  "Draw a Shadow";

//Get Vars and Make Surface
//-----------------------------
var rANK = argument0;
var nAME = argument1;
var sCORE = argument2;
var cOLOUR = argument4;
var wIDTH = argument5;
var hEIGHT = argument6;
var shadow = argument7;

surf = surface_create(wIDTH, hEIGHT);

//Target the Surface
//-----------------------------
surface_set_target(surf);

draw_clear_alpha(c_black, 0);     //Because it draws part of the previous one in the Array otherwise ?!?!?!?!?!?!?!?!?!??!?!?!?!?!?

//Draw the BG
//---------------------------
draw_sprite_stretched_ext(spr_Black_Rect, image_index, 0, 0, wIDTH, hEIGHT, c_white, 1);


//Set Up the Text (Fonts and Alignment)
//-----------------------------

//Font From String
var Norm_Font, Shadow_Font;

if (argument3 == "normal")
{
  Shadow_Font = fontNormShadow;
  Normal_Font = fontNormG;
}
else if (argument3 == "left")
{
  Shadow_Font = fontLeftShadow;
  Normal_Font = fontLeftG;
}
else if (argument3 == "right")
{
  Shadow_Font = fontRightShadow;
  Normal_Font = fontRightG;
}

draw_set_halign(fa_right);

draw_set_valign(fa_top);


//Draw The Text
//-----------------------------

draw_set_alpha_test(true);          //enable alpha testing
draw_set_alpha_test_ref_value(128); //draw all transparent pixels

//SHADOW\\
//---------
if (shadow)
{
  draw_set_font(Shadow_Font);
 
  //Rank
  draw_set_halign(fa_right);
  draw_text(80, -1, rANK);
 
  //Name (initials)
  draw_set_halign(fa_middle);
  draw_text(200, -1, nAME);
 
  //Score WITH Digit Grouping
  draw_set_halign(fa_right);
  score_String = scr_Digit_Grouper(sCORE, ",", 3);
  draw_text(520, -1, score_String);
}

//ACTUAL\\
//---------
draw_set_font(Normal_Font);
draw_set_colour(cOLOUR);

//Rank
draw_set_halign(fa_right);
draw_text(80, -1, rANK);
 
//Name (initials)
draw_set_halign(fa_middle);
draw_text(200, -1, nAME);

//Score WITH Digit Grouping
draw_set_halign(fa_right);
score_String = scr_Digit_Grouper(sCORE, ",", 3);
draw_text(520, -1, score_String);

draw_set_alpha_test(false); //enable alpha testing

//End the Text and Reset the Surface
//-----------------------------
draw_set_halign(fa_left);

draw_set_valign(fa_top);

draw_set_colour(c_white);

surface_reset_target();


//Create the Sprite
//-----------------------------
var t_Sprite = sprite_create_from_surface(surf, 0, 0, wIDTH, hEIGHT, true, false, (wIDTH /2), 0);

//free the surface
surface_free(surf);

global.Table_Sprite_Count += 1;

return t_Sprite;
...Thanks Again Guys :):D:)

edit: Forgot to mention... My bitmap fonts have a VERY low alpha outline in them so that proportional drawing works properly for me.
I was having trouble removing this outline from the surface until I saw this...
Code:
draw_set_alpha_test(true); //enable alpha testing
draw_set_alpha_test_ref_value(0); //draw all transparent pixels
...in silverfrost's post :)
 
Last edited:

Yal

🐧 *penguin noises*
GMC Elder
Lol, I'd ended up forgetting about the color write enable function, thanks for necrobumping this 2 years old topic so I could refresh my memory about the thing I'd forgotten about. *wags finger*
 

AetherBones

Member
So I've been researching how to get surfaces to act like the application surface when drawing transparency over already drawn sprites and wanted to share my solution since I came across this thread in my search for a solution.
using this blend mode, drawing acts like you would expect on surfaces. gpu_set_blendmode_ext_sepalpha(bm_src_alpha,bm_inv_src_alpha,bm_src_alpha,bm_one);
 

Yal

🐧 *penguin noises*
GMC Elder
When I said "thanks for necrobumping this 2-year-old thread" back in 2019, I was sarcastic...

being able to draw on surfaces "like you'd expect" sounds good though, if it is what I think it is
 
Top