[Solved] alpha blending and surfaces(?)

Discussion in 'Programming' started by basement ape, Aug 22, 2017.

Tags:
  1. basement ape

    basement ape Member

    Joined:
    Mar 6, 2017
    Posts:
    99
    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?
     
  2. muki

    muki Member

    Joined:
    Mar 5, 2017
    Posts:
    220
    what does it look like with pixel interpolation turned off?
     
  3. basement ape

    basement ape Member

    Joined:
    Mar 6, 2017
    Posts:
    99
    alphabug2.png

    Same thing happens.
     
  4. Tsa05

    Tsa05 Member

    Joined:
    Jun 21, 2016
    Posts:
    553
    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
     
    Bapsilon and basement ape like this.
  5. Nocturne

    Nocturne Friendly Tyrant Forum Staff Admin

    Joined:
    Apr 13, 2016
    Posts:
    6,859
    Yal and basement ape like this.
  6. basement ape

    basement ape Member

    Joined:
    Mar 6, 2017
    Posts:
    99
    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?
     
  7. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,556
    Really useful blog post, this kind of thing happens a lot so it's nice to know there's a dedicated function to avoid it now~
     
  8. Tsa05

    Tsa05 Member

    Joined:
    Jun 21, 2016
    Posts:
    553
    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.
     
    basement ape likes this.
  9. basement ape

    basement ape Member

    Joined:
    Mar 6, 2017
    Posts:
    99
    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 :)
     
    Tsa05 likes this.
  10. silverfrost

    silverfrost Member

    Joined:
    Apr 3, 2017
    Posts:
    4
    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 and Ido-f like this.
  11. Bapsilon

    Bapsilon Member

    Joined:
    Mar 4, 2018
    Posts:
    3
    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: Sep 11, 2019
    Nocturne likes this.
  12. The Reverend

    The Reverend Member

    Joined:
    Sep 8, 2016
    Posts:
    552
    Just in case anyone is still interested ... I got a video explaining the problem and offering different solutions on this topic:
     
    Bapsilon and Nocturne like this.
  13. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,556
    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*
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice