phaser-ce icon indicating copy to clipboard operation
phaser-ce copied to clipboard

Applying a Filter to a Group breaks mask

Open Xan0C opened this issue 7 years ago • 5 comments

  • A bug in the API:
    • Phaser version(s): 2.7.6 probably >= 2.7
    • Live example: https://codepen.io/Nan0C/pen/RVabZZ
    • Reproduce: a. Create a Group with one or more sprites b. Apply a Filter and mask to the group
    • What should happen: Filter and mask should be applied to the group. The gray boxes should only be visible above the green line
    • What happens instead: Applying a filter breaks the mask applied to the group. The boxes are visible under the green line

This issue has probably something to do with the issues #39 #153 #154

I assume its a problem with the WebGLSpriteBatch or the FilterManager, since the bug happens after the PIXI.DisplayObjectContainer.prototype._renderWebGL method. Commenting out the parts where a Filter is applied makes the mask work again(obviously because its not used)[DisplayObjectContainer.js#L500]

Xan0C avatar Apr 20 '17 12:04 Xan0C

In v2.7.7: https://codepen.io/samme/pen/gWGgaB

samme avatar May 05 '17 01:05 samme

In 2.8.3, it seems to work when applying the same mask and filter to each child (using group.setAll):

https://codepen.io/Samid737/pen/qXOxRE

This does not work in 2.7.7 however and im not sure if it is desirable (performance)..

samid737 avatar Jul 28 '17 10:07 samid737

changing the order to first apply the mask and then the filter fixes it for this case. However in the game we have with lots of nested groups, it does not. And its probably a bad idea to just change the order. I also tried to figure out how the FilterManager and MaskManager work but only understood half of it.

https://codepen.io/Nan0C/pen/vJNjxq

PIXI.DisplayObjectContainer.prototype._renderWebGL = function (renderSession) {

    if (!this.visible || this.alpha <= 0)
    {
        return;
    }

    if (this._cacheAsBitmap)
    {
        this._renderCachedSprite(renderSession);
        return;
    }

    var i;

    if (this._mask || this._filters)
    {
        // push filter first as we need to ensure the stencil buffer is correct for any masking

        //Totally ignore the previous comment and do the opposite. 
        //shouldnt the stencil buffer be applied before masking?  
        //so rendering the filterpass already applies the mask?
        if (this._mask) {
            renderSession.spriteBatch.stop();
            renderSession.maskManager.pushMask(this.mask, renderSession);
            renderSession.spriteBatch.start();
        }
      
        if(this._filters) {
          renderSession.spriteBatch.flush();
          renderSession.filterManager.pushFilter(this._filterBlock);
        }
      

        // simple render children!
        for (i = 0; i < this.children.length; i++)
        {
            this.children[i]._renderWebGL(renderSession);
        }

        renderSession.spriteBatch.stop();
        
        if (this._filters) renderSession.filterManager.popFilter();
        if (this._mask) renderSession.maskManager.popMask(this._mask, renderSession);
      

        renderSession.spriteBatch.start();
    }
    else
    {
        // simple render children!
        for (i = 0; i < this.children.length; i++)
        {
            this.children[i]._renderWebGL(renderSession);
        }
    }

};

Xan0C avatar Jul 28 '17 12:07 Xan0C

I want to bring this issue up again. We are trying to port our framework we build ontop of phaser 2.6.2. Trying to use the latest phaser ce 2.11.1 version. We have the exact same problem. Mask do work fine in general. But as soon as we apply a filter to a group, the mask dissappears and reveals the whole group. Could it be related to #334

I tried the suggestions mentioned above, but none did help. Any suggestions, maybe there is a workaround? Or could this be a bug?

ndee85 avatar Nov 07 '18 13:11 ndee85

@samme @samid737 @photonstorm I did try out the solution of @Xan0C and change the order of applying the filter and mask (for testing purpose in the phaser.js). For both. DisplayObjectContainer and the Sprite object. It seems to work.

The comment explicitely says, that filter needs to be applied first in order for the stencil buffer being calculated correctly. But it seems this isn't the case. Flipping the order did help here. Refering to the examples mentioned above, the mask is applied first to, and afterwards the filter.

Would this be a viable solution to fix masks working together with filters? Any thoughts from more experienced phaser user? If any other solution would make more sense, I would be happy for some hints from your side.

ndee85 avatar Nov 08 '18 13:11 ndee85