GM:S 1.4 [SOLVED] 'Overlay' blend mode in Gamemaker

Discussion in 'Programming' started by Nathan Laing, Feb 26, 2017.

  1. Nathan Laing

    Nathan Laing Member

    Joined:
    Jul 31, 2016
    Posts:
    355
    Hello everyone,

    What blend mode in Game maker would be considered the technical equivalent of 'Overlay' in say, Photoshop?

    Cheers,
    Nathan
     
  2. mariospants

    mariospants Member

    Joined:
    Jun 21, 2016
    Posts:
    94
    There really isn't one, according to Rogelio Bernal Andreo (a respected astrophotographer), the formula for Overlay is: (Source> 0.5) * (1 - (1-2*(Source-0.5)) * (1-Destination)) + (Source<= 0.5) * ((2*Source) * Destination), which is pretty specific.

    You can possibly try to emulate with bm_add when using a Source image that's lighter than the Destination and playing with alpha, and using bm_subtract for the opposite.

    The closest I've gotten is using draw_set_blend_mode_ext(bm_dest_color,bm_src_color), give that a try and see if it gives you the results you're looking for.
     
    Nathan Laing likes this.
  3. Nathan Laing

    Nathan Laing Member

    Joined:
    Jul 31, 2016
    Posts:
    355
    Thanks for the information mariospants, that's interesting to know.
    I've been experimenting with the brilliant, free blend mode test utility on the Gamemaker market place -- the blend results differ wildly depending on the images used, so it's tough to pin down a definitive mode.
     
  4. Perseus

    Perseus Not Ragarnak Forum Staff Moderator

    Joined:
    Dec 29, 2016
    Posts:
    951
    A shader might be able to do what you want.

    Code:
    // Fragment (Overlay)
    
    varying vec2 v_vTexcoord;
    varying vec4 v_vColour;
    uniform sampler2D texOverlay;
    void main() {
        vec4 inColor = v_vColour * texture2D(gm_BaseTexture, v_vTexcoord);
        vec4 outColor = vec4(0.0,0.0,0.0, inColor.a);
        vec4 overlay = texture2D(texOverlay, v_vTexcoord);
        if (inColor.r > 0.5) {
            outColor.r = (1.0 - (1.0 - 2.0 * (inColor.r - 0.5)) * (1.0 - overlay.r));
        }
        else {
            outColor.r = ((2.0 * inColor.r) * overlay.r);
        }
        if (inColor.g > 0.5) {
            outColor.g = (1.0 - (1.0 - 2.0 * (inColor.g - 0.5)) * (1.0 - overlay.g));
        }
        else {
            outColor.g = ((2.0 * inColor.g) * overlay.g);
        }
        if (inColor.b > 0.5) {
            outColor.b = (1.0 - (1.0 - 2.0 * (inColor.b - 0.5)) * (1.0 - overlay.b));
        }
        else {
            outColor.b = ((2.0 * inColor.b) * overlay.b);
        }
        gl_FragColor = mix(outColor, inColor, 1.0 - overlay.a);
    }
    
     
    Zerb Games and Nathan Laing like this.
  5. flyingsaucerinvasion

    flyingsaucerinvasion Member

    Joined:
    Jun 20, 2016
    Posts:
    2,033
    According to my tests, the following fragment shader will produce exactly the same results as the photoshop overlay blend mode.

    A few notes first though.

    It appears that the formula by @mariospants is incorrect because the source and destination colors have been swapped.

    Also, I'm avoiding using any if statements because as far as I understand, if different fragments execute different segments of code, it will slow down the execution of the shader, perhaps by a lot.

    Code:
    //---------------------------------------------------------------
        uniform sampler2D overlayTexture;
        //---------------------------------------------------------------
        varying vec2 v_vTexcoord;
        //---------------------------------------------------------------
        float overlay( float S, float D ) {
            return float( D > 0.5 ) * ( 2.0 * (S + D - D * S ) - 1.0 )
            + float( D <= 0.5 ) * ( ( 2.0 * D ) * S );
        }
        //---------------------------------------------------------------
        void main() {
            vec4 D = texture2D( gm_BaseTexture, v_vTexcoord );  //destination color
            vec4 S = texture2D( overlayTexture, v_vTexcoord );  //source color
            //---------------------------------------------------------------
            gl_FragColor = vec4(
                mix(
                    vec3( overlay( S.r, D.r ), overlay( S.g, D.g ), overlay( S.b, D.b ) ),
                    D.rgb,
                    1.0 - S.a
                ),
                D.a
            );
        }
    //---------------------------------------------------------------
    
    EDIT: slight simplification.
     
    Last edited: Jul 11, 2019 at 7:04 PM
  6. mariospants

    mariospants Member

    Joined:
    Jun 21, 2016
    Posts:
    94
    I was having some difficulty trying to shove one paradigm's terminology into another, and it ended up being a 50/50 crap shoot. Thanks for fixing my error, and thanks for the shader code... we need a KB for these kinds of things - something we can easily look up after hitting F1 in Game Maker. e.g., do search for "Photoshop overlay blend mode" or whatever, and get this code...
     
  7. Nathan Laing

    Nathan Laing Member

    Joined:
    Jul 31, 2016
    Posts:
    355
    Bloody hell! What is this magnificence!? mariospants you're awesome for getting the ball rolling here and posting in the code as well. And then, flyingsaucerinvasion rocks up and just puts the icing on the cake!

    I've tested this and it works flawlessly. Thanks a million and then some guys, truly wonderful!

    P.S. Maybe you guys missed this thread haha
    https://forum.yoyogames.com/index.php?threads/screen-blend-mode-in-gamemaker.18935/
     
    mariospants likes this.
  8. COWCAT

    COWCAT Member

    Joined:
    Jul 26, 2016
    Posts:
    56
    Hello,

    I'm trying to implement that "overlay" shader to implement some lighting effects for my game. (currently doing tests to see what art style works best)

    I'd like to blend a "background" picture with a "lighting" sprite in order to get this (simulated with Photoshop) :

    overlaytest.jpg

    I'm not really a specialist with shaders so I'm not sure how to use it.
    If I'm being correct, I'm supposed to pass a texture to the shader? But how?

    I've tried finding some examples and did *something* :

    Code:
    uni_overlayTexture = shader_get_sampler_index(sh_overlay, "overlayTexture");
    draw_sprite(bg, -1, 0, 0);
    
    textbg = sprite_get_texture(bg, 0);
    shader_set(sh_overlay);
    texture_set_stage(uni_overlayTexture, textbg);
    draw_sprite(light, -1, 0, 0);
    shader_reset();
    
    But the result doesn't work :

    result.jpg

    (Also I'm not sure if this shader will really help me at all because the background will actually be made of separate objects moving independently so passing a single texture might be complex and there will be other elements like HUD over the whole thing...)

    Any help? Or other ways to simulate this "lighting" effect?
    The only other alternative working for me is using the "bm_add" blend mode but it "burns" the picture...

    Even the suggested "bm_dest_color,bm_src_color" blend mode doesn't work for me, the transparent parts of the light sprite get used for some reason.
     
  9. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,315
    I would play around with the different blend modes first.
    If you know the blend equation this helps too. It's srcColor × scrFactor ? DestColor × destFactor.
    Where ? Is the blend function (+ by default).


    As for the shader, you would want to first render to a surface, then pass that surface in to be post processed. That is how you can apply it to multiple objects at a time.

    Unless you want more complex equations, you shouldn't need to use a shader. Blend equations should do most of what you need.
     
  10. COWCAT

    COWCAT Member

    Joined:
    Jul 26, 2016
    Posts:
    56
    I admit I can't really guess how blending modes will work until I try them.

    - Some blending modes don't work with all platforms (I'm exporting to PC/Consoles and potentially mobile too)
    - I remember trying varied combinations for my previous game already and never finding a satisfying result (other than bm_add again)

    Still I guess I'll try that again because yes, the shader solution seems a tiny bit too complex... and would be very slow, especially if I have to generate + render a surface of the whole screen size at each step.

    I would have thought other devs would have encountered similar issues? Lighting should be pretty common but I actually never find any good examples... I just want something that works similarly to what Photoshop does. (it doesn't have to be perfect, just not burning the picture...)
     
  11. GMWolf

    GMWolf aka fel666

    Joined:
    Jun 21, 2016
    Posts:
    3,315
    Don't need to create the surface every frame, keep it around!
    Instead of rendering directly to the back buffer, you first render to your surface, then render that surface to the back buffer.
    It's a very common technique for post processing like this. Having one full screen surface is cheap. Many games make use of 10+ (but that is starting to be expensive..)!
     
  12. COWCAT

    COWCAT Member

    Joined:
    Jul 26, 2016
    Posts:
    56
    Well I have bad memories of using a lot of surfaces with my previous game, which became a messy nightmare. Drawing some sprites on a surface and not others, transparency issues etc...
    Also with old Intel HD Graphics chipsets, even drawing the full 1080p picture one or two times is enough to make them slow down.

    Anyway, I've settled to a different solution.
    Instead of generating light, I draw over the character sprite with a default ambient light (with just image_blend) to make him darker - and I vary the alpha of this according to position in the room (compared to the light sources) So the closer to a light source, the less dark it becomes. Which gives the impression the character gets lit!

    Not a full replacement for the overlay but it's simple and it works correctly :)
     

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