Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opposite of Masking? #252

Closed
Squeakrats opened this issue Aug 7, 2013 · 20 comments
Closed

Opposite of Masking? #252

Squeakrats opened this issue Aug 7, 2013 · 20 comments
Assignees
Labels
🙏 Feature Request Community request for new features, APIs, packages.
Milestone

Comments

@Squeakrats
Copy link

is there anyway to instead of showing whats in the mask, hide it?Thanks!
(btw Pixi is really awesome!)

@drkibitz
Copy link
Contributor

drkibitz commented Aug 7, 2013

I really don't see a use case for this. Why would you want to do this?

@Squeakrats
Copy link
Author

I have a texture I am using as a light. I have generated shadow geometry and rendered it to a RenderTexture(or I can just keep it as a Graphic). I want to make the part that is overlapping with the shadow geometry to become invisible. If I just used a mask, I would only see the shadow.

@drkibitz
Copy link
Contributor

drkibitz commented Aug 7, 2013

Ah yes, that is a perfect use case, but I'm not exactly sure how to do it yet, sorry.

@englercj
Copy link
Member

englercj commented Aug 7, 2013

I think that this is a good feature to have as well, unfortunately it isn't there yet (correct me if I am wrong @GoodBoyDigital). Adding to the request list!

@Squeakrats
Copy link
Author

my original thought was that I could just fill up a Rendertexture, mask that with my shadow geometry to get the negative, and then use THAT as a mask. But then I realized you can only use Graphics to mask; :/

@englercj
Copy link
Member

englercj commented Aug 7, 2013

Yup, that is due to how masking works in Canvas (via the clip method).

@drkibitz
Copy link
Contributor

drkibitz commented Aug 7, 2013

Would blending work for this, too expensive, or any other way?

@namuol
Copy link
Contributor

namuol commented Aug 7, 2013

I got inverted masks to work with WebGL by changing line 111 of WebGLRenderGroup.js to the following:

if(renderable.mask.invertMask) {
    func = gl.EQUAL;
} else {
    func = gl.NOTEQUAL;
}
gl.stencilFunc(func,0,0xff);

Now, you can set mask.invertMask = true on any display object to cut out anything inside the mask region.

I'll add a PR when I get it to work with the CanvasRender, but does anyone have an idea of how to achieve this with canvas already? context.clip() doesn't seem to support this kind of thing; we'd probably need to use globalCompositeOperation and a duplicate canvas, which could be a substantial performance penalty.

@englercj
Copy link
Member

englercj commented Aug 7, 2013

It is trivial in WebGL, but in canvas it is not. Since PIXI is built on both renderers looking exactly the same, that places some limitations on how we implement features. It will take more time to come up with a solution that works the same in both renderers.

@photonstorm
Copy link
Collaborator

You have 2 choices (re: canvas) really - you either carefully construct the clip mask so that it simulates an inverted mask (which would be really hard with just the Pixi Graphics primitives, but a bit easier if you build the path yourself), or you use a "destination-out" Global Composite Op. This would require using a 2nd canvas and a mask image, but has the advantage that you can have any shape you like for the mask and even include feathering, alpha areas, etc. I cover it in my article here: http://html5hub.com/cutting-through-images-in-canvas/#i.wgzkq4zc3crby5 but I've no idea how easy it would be to replicate in WebGL as well.

@namuol
Copy link
Contributor

namuol commented Aug 8, 2013

@photonstorm Exactly.

I personally think it's more intuitive to use a straightforward texture as a mask instead of a graphics object, particularly because I think of "masking" in terms of blendmode tricks, rather than stencil buffer tricks.

I know there was a roadmap feature for blend modes; the right combination of blendmodes should allow for (8 bit?) per-pixel masking.

@twboc
Copy link

twboc commented Aug 10, 2014

Additionally to have the same effect working in canvas without the webGL you can use a hack that i have invented. What you have to do is to draw a opposite of the mask as a shape with a hole inside (that was my case). If you'll draw everything with one line without move to the canvas renderer will be able to handle it.

            var thing = new PIXI.Graphics();
                _renderer.stage.addChild(thing);
                thing.position.x = 0;
                thing.position.y = 0;
                thing.lineStyle(0);
                thing.beginFill(0xFFFF0B, 0.5);

                thing.moveTo(0,0);
                thing.lineTo((gameCanvas.width/10) * 5, 0);
                thing.lineTo((gameCanvas.width/10) * 5, (gameCanvas.height/10) * 3.25);
                thing.lineTo((gameCanvas.width/10) * 4.77, (gameCanvas.height/10) * 3.35);
                thing.lineTo((gameCanvas.width/10) * 4.6, (gameCanvas.height/10) * 3.7);
                thing.lineTo((gameCanvas.width/10) * 4.525, (gameCanvas.height/10) * 4.15);
                thing.lineTo((gameCanvas.width/10) * 4.6, (gameCanvas.height/10) * 4.6);
                thing.lineTo((gameCanvas.width/10) * 4.77, (gameCanvas.height/10) * 4.95);
                thing.lineTo((gameCanvas.width/10) * 5, (gameCanvas.height/10) * 5);
                thing.lineTo((gameCanvas.width/10) * 5.23, (gameCanvas.height/10) * 4.95);
                thing.lineTo((gameCanvas.width/10) * 5.4, (gameCanvas.height/10) * 4.6);
                thing.lineTo((gameCanvas.width/10) * 5.475, (gameCanvas.height/10) * 4.15);
                thing.lineTo((gameCanvas.width/10) * 5.4, (gameCanvas.height/10) * 3.7);
                thing.lineTo((gameCanvas.width/10) * 5.23, (gameCanvas.height/10) * 3.35);
                thing.lineTo((gameCanvas.width/10) * 5, (gameCanvas.height/10) * 3.25);
                thing.lineTo((gameCanvas.width/10) * 5, 0);
                thing.lineTo(gameCanvas.width, 0);
                thing.lineTo(gameCanvas.width, gameCanvas.height);
                thing.lineTo(0, gameCanvas.height);

                thing.endFill();

                _camera['entities'].mask = thing;

this is an example code that I used in my case!

And this is the effect:
http://imgur.com/wX9V8rd

But remember that it is still a hack!

www.sevenative.com

@GoodBoyDigital
Copy link
Member

closing this for now. We won't be making inverted masks - but this is entirely possible with the new spriteMasking in v3. Thanks all!

@englercj englercj added this to the v3.x milestone Feb 18, 2015
@jdoleary
Copy link

Is this now complete in v3.x? How would inverted masks be used? I looked around the source in v3.x and didn't find anything regarding inverted masks.

@englercj
Copy link
Member

Like @GoodBoyDigital said, we will not be making inverted vector masks, but you can accomplish it with sprite masking.

Since you can use an image for masking, you can do anything. Including having a sprite that uses a canvas as a texture and drawing whatever you want to it.

@jdoleary
Copy link

My mistake, I thought since it was added to the v3.x milestone that it would be added.

I still don't understand how I could use a sprite to invert a mask. I'd still have the same problems wouldn't I? I want to draw a series of polygons to a sprite, invert them, and use that as a mask. I don't see how that is possible.

@englercj
Copy link
Member

alpha masks use alpha / color, so black and alpha of 0 will mask the item. You can draw black/alpha 0 wherever you want in an image, then apply that mask. #1639.

So you can draw a polygon where it is filled with white, and all the other transparent areas that are not drawn will be the masks, or you can do the reverse. Whatever you draw is the mask.

@Squeakrats
Copy link
Author

Awesome to see this is working! That makes sense.

@Saltallica
Copy link

I now this is closed, but I figured I'd throw another opinion in the mix, since I would find it practical to be able to have a mask similar to canvas "destination-out" compositing.

In the game I'm building, I want to "punch a hole" in a blimp. The way I currently have it set up, I dynamically create a white, rectangular mask, with a few black polygons to represent the holes.
I save to a texture, then a sprite, then set it as the mask to the blimp sprite. This gives the illusion that the blimp sprite has holes in it. This works, for simple static masking.

Some visuals - A blimp, and a mask with the same bounds and a few holes.

image

If I want to "fade in" the holes over an amount of time, I thought maybe I could just adjust animate the alpha value of the mask - this didn't end up with the expected result, as the white and black are required for the mask to behave "correctly." When animated, the whole blimp fades in, not just the wholes.

Ideally, I would like to simply have a mostly transparent sprite with a few areas that are completely white. These would then get set up as mask and subtract the alpha of the container/sprite it's assigned to. A destination-out style blend mode would accomplish this.

@lock
Copy link

lock bot commented Feb 25, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked and limited conversation to collaborators Feb 25, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
🙏 Feature Request Community request for new features, APIs, packages.
Projects
None yet
Development

No branches or pull requests

9 participants