Jump to content

Alpha from blurred PNG is lost in shader


Recommended Posts

Hi all, i've been messing with something for a couple days.  I'm passing in a transparent blurred PNG to a shader, as well as a solid PNG background, and running it through a grayscale shader.

If I simply display the pixels of the blurred PNG, it is output on top of the solid background as expected.  The grayscale part of the shader works fine.  However, the grayscale portion of the photo has a harsh transition to the background.  It doesn't fade nicely and follow the alpha of the blurred PNG, like a blendMode would.  I realize they are different things, but I feel like I am missing something obvious, and that it should work as I'm expecting.

I have a playground setup to demonstrate the issue.  Ignore the ugliness of the assets, it gets the point across better :)


In the photo attached, the desired result is on the left (from Photoshop Color BlendMode).   The right is the result from the playground.  You can tell that the grayscale area on the right is much larger, since I believe that any alpha that is NOT 0, it being set to 1.   

I would like to try and maintain the alpha from the original blurred PNG.  It may not seem like much but it really kills what I'm going for with the aliased edge like that. Thank you!



Link to comment
Share on other sites

grayMask = 0.299 * target.r + 0.587 * target.g + 0.114 * target.b

just for your knowledge, those values (r g b) are premultiplied by alpha in pixi, so this gray is actually gray*target.a. Yet it should work because you need premultiplied color in "grayed" :)

the real fix is here, its usual normal blendmode:


gl_FragColor = source * (1.0 - grayed.a) + grayed;
Link to comment
Share on other sites

Hi, I tried putting this in the playground and it looks like the same result.  The same as the image attached above on the right side.

gl_FragColor = source * (1.0 - grayed.a) + grayed;

I've tried playing around and I can get the solid border to shrink if I check for the alpha == 1, then only return those pixels.  This may be enough, but it's not optimal.

if (source.a == 1.0) {
  gl_FragColor =  source * (1.0 - grayed.a) + grayed;

Just can't get anything that is less than 1.0 alpha to really blend properly.  I actually get the same result if it just returns only "grayed".

Still hacking around in the playground!  I greatly appreciate your response.



Side note: the playgrounds are awesome...

Link to comment
Share on other sites

This did the trick, thanks!

void main(void)
    vec4 source = texture2D(color, vUvs);
    vec4 target = texture2D(base, vtestUvs);
    if (source.a > 0.0) {
        float grayMask = 0.299 * target.r + 0.587 * target.g + 0.114 * target.b;
        gl_FragColor = vec4(grayMask*source.a, grayMask*source.a, grayMask*source.a, source.a);
    } else {
        gl_FragColor = vec4(0, 0, 0, 0);


Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...