Sign in to follow this  
alexzchen

Using mask with blendmodel will result in black

Recommended Posts

When I use mask and blendmode(MULTIPLY) alone, they are all right, but if they are used together, it will turn black. Is that right?

 

function setup(loader, res) {
        
        let lower =  new PIXI.Sprite(PIXI.loader.resources["lower"].texture)
        let uper =  new PIXI.TilingSprite(PIXI.loader.resources["uper"].texture)
        let mask =  new PIXI.Sprite(PIXI.loader.resources["mask"].texture)
        
        uper.blendMode = PIXI.BLEND_MODES["MULTIPLY"];
        //uper.mask = mask;

        stage.addChild(mask);
        stage.addChild(lower);
        stage.addChild(uper);
      }

 

1.png

2.png

3.png

Share this post


Link to post
Share on other sites

Your order of operations is wrong. You just cant do that multiply trick without extra layer. 

There are three ways to do this stuff:

1. Sprite Mask

2. DST_OUT aka ERASE blendMode, in separate layer. , means that you need a container with uper+mask , and AlphaFilter on it to move it to separate framebuffer.

3. Same as 2. but instead of extra container you add low on top with SRC_IN blendMode or something like that (as a result it draws behind picture). Requires transparent background.

I will set up example for you later.

Edited by ivan.popelyshev

Share this post


Link to post
Share on other sites

Here you go: https://www.pixiplayground.com/#/edit/gf4R13uySPmp2ktzAC3MT  just swap textures to whatever you want, and maybe swap maskTexture , in the demo you can draw on it.

If you still dont understand why do you need filter there, you probably have to experiment with photoshop and other editors more. Layers are essential part, without it you cant do lighting and other kind of effects. The first question should be "if we have pictures A,B,C , does it matter whether B blends on A first or C blends on B?". If you still dont have a single clue - try experiment with canvas2d without pixi, just pure RenderingContext2D drawImage method.

Edited by ivan.popelyshev

Share this post


Link to post
Share on other sites

Thanks for your solution again, now I hava another problem, when the lower sprite and mask use the same picture, it will cause a gray border, I'm trying to zoom in the mask picture, and it's going to be obvious, I guess it's because the edge of picture are not clear enough, is there anyway to solve it?

here is my code: https://www.pixiplayground.com/#/edit/DPZGFIoYSgTtkkXSAmPTm

tks

22.png

11.png

Share this post


Link to post
Share on other sites

For now you can try do the math of why that black border happens. All pixijs textures have premultiplied alpha.

https://github.com/pixijs/pixi.js/blob/dev/packages/core/src/state/utils/mapWebGLBlendModesToPixi.ts#L19

https://www.w3.org/TR/compositing-1/#blending

Otherwise,  I can look at it next week. I hope you understand that knowledge of all those blend modes is rare thing in our html5 gamedev community. That issue you are asking me to solve is HARD.

Edited by ivan.popelyshev

Share this post


Link to post
Share on other sites

I think I already know some reasons, the edge of the picture has some transparency, but the mask does not, so when the picture cut by mask multiply with the lower sprite, the edge will turn black,

does it mean that the mask solution is inappropriate in my scene, I should look for other ways?

33.png.00eba05c07a3eb8bd63b8ddff120e16e.png

Share this post


Link to post
Share on other sites

I come up with a simple idea. Since TillingSprite can handle all the effects of the upper picture that I need, including movement, rotation, displacement, etc., and then I will add a separate custom filter for multiply with lower layer pictures and cut the transparent part, it works like a mask, is my idea feasible?

 

the shader code some like:

vec4 sample = texture2D(uSampler, coord);

if (gl_FragColor.a != 0.0) {
        gl_FragColor.rgb = (sample * uColor).rgb * gl_FragColor.rgb;
 }

Edited by alexzchen

Share this post


Link to post
Share on other sites

no, because you have no access to pixel underneath. You cant read value from "gl_FragColor" :(

There is a plugin that allows to do something like that, it copies whats underneath in separate uSampler, called "pixi-picture" but i hadnt move it to v5 yet.

I think best idea is to take SpriteMaskFilter as a base. It takes sampler (whats inside container) and a sprite (texture + transform). You can add extra texture there - a colorful one , dont forget to set its wrapMode to repeat.  The only problem is that you'll need to scale it too.

I tihnk I will be able to help you tomorrow.

I bet I can do that in 10 minutes or so but my brain time is very limited and I have many other requests too :) 

Edited by ivan.popelyshev

Share this post


Link to post
Share on other sites

Yes, the topic itself is very interesting, I have experience with it, and I even had a huge tutorial video for that kind of things, but its in russian ;) Need more time (sigh) to make actual huge article or even a book chapter about it.

PixiJS has the best API for those things (among other html5 renderers) but even then its not fully documented for regular folks to use without extra help.

P.S. also you didnt take into account premultiplied alpha in your calculation - that's the main problem here we cant solve with blend :(

Edited by ivan.popelyshev

Share this post


Link to post
Share on other sites

Thanks for reply, I guess the implementation of this 'SpriteMaskFilter' is very similar to the DisplacementFilter, it will give a texture parameter as a sampler and use its pixel information to do multiply, and remove the transparent part at the same time

Share this post


Link to post
Share on other sites
5 minutes ago, alexzchen said:

Thanks for reply, I guess the implementation of this 'SpriteMaskFilter' is very similar to the DisplacementFilter, it will give a texture parameter as a sampler and use its pixel information to do multiply, and remove the transparent part at the same time

Or add second sprite if you want to position second texture without problems, applyFilter can handle two copies of positiong code ;) 

The thing with multiply is that you have to unpremultiply first.

HEre's V4 shader for OVERLAY: https://github.com/pixijs/pixi-picture/blob/master/src/OverlayShader.ts

And here's my multiply shader from secret project:

   vec4 src = texture2D(uSampler, vTextureCoord);
   vec4 dest = texture2D(uBackdrop, vTextureCoord);  
   
   if (dest.a == 0.0) {
       gl_FragColor = src; 
       return;
   }
   if (src.a == 0.0) {
       gl_FragColor = dest; 
       return;
   }
   
   vec4 mult;
   mult.rgb = (dest.rgb / dest.a) * ((1.0 - src.a) + src.rgb);
   mult.a = min(src.a + dest.a - src.a * dest.a, 1.0);
   mult.rgb *= mult.a;

 

Edited by ivan.popelyshev

Share this post


Link to post
Share on other sites

Actually now that i think about it, there's easier way, without custom filters/shaders:

1. Use TilingSprites of color and cloth to get a multiplied result in renderTexture

2. Now you have cloth and new bacgrkound, you can just mask that background with your black-white mask (sprite mask, "container.mask = myWhiteMask") and it'll work. Yes, it uses SpriteMaskFilter internally.

 

Edited by ivan.popelyshev

Share this post


Link to post
Share on other sites

Actually, I remember that I have tried the mask solution a week ago, it will cause gray border, as long as there is a certain transparency on the edge of the picture, so I will try the custom filter first tonight, even though I don't know how to write a filter, hope to succeed :lol:

Share this post


Link to post
Share on other sites

 

5 hours ago, ivan.popelyshev said:

Even easier:

Use black background and colors+mask. Put cloth on top with MULTIPLY blendMode.

I tried again with your suggestion, but still have a gray border, and the color looks a little wrong, it seems darker than it used to be

use sprite as a mask:

https://www.pixiplayground.com/#/edit/QLaZYeWHqrVkkrj-ZRL9h

use container

https://www.pixiplayground.com/#/edit/DPZGFIoYSgTtkkXSAmPTm

Edited by alexzchen

Share this post


Link to post
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.

Guest
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.

Loading...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.