alexzchen

anchor doesn't work in custom filter

Recommended Posts

I wrote a filter to achieve special effects. Part of the code is as follows,scale and rotate works well,but the anchor I set seems not right,the sprite still rotates around the upper left corner.

constructor(texture:PIXI.Texture) {
            super(MyFilter.vertSrc, MyFilter.fragSrc)
            this.maskMatrix = new PIXI.Matrix();  
            let sprite = new PIXI.Sprite(texture);
            app.stage.addChild(sprite);
            sprite.visible = false;

            this.maskSprite = sprite;
            this.maskSprite.anchor.set(0.5)     //it doesn't work!
            this._translate = [0, 0];
            this.uniforms.mapSampler = sprite.texture;
            this.uniforms.filterMatrix = this.maskMatrix;
        }

        translate(x:number, y:number) {
            this._translate[0] = x;
            this._translate[1] = y;
            this.uniforms.vTranslate = this._translate;
        }

        scale(x:number, y:number) {
            this.maskSprite.scale.set(x, y);
        }
         
        rotate(rad:number) {
            this.maskSprite.rotation = rad;
        }

 

Share this post


Link to post
Share on other sites

calculateSpriteMatrix takes anchor into account: https://github.com/pixijs/pixi.js/blob/dev/packages/core/src/filters/FilterSystem.js#L395

It should work. You've made a mistake in a place that is hidden from my telepathy, please provide a demo on codepen/jsfiddle/pixi-playground.

Share this post


Link to post
Share on other sites
On 9/13/2019 at 12:44 AM, ivan.popelyshev said:

calculateSpriteMatrix takes anchor into account: https://github.com/pixijs/pixi.js/blob/dev/packages/core/src/filters/FilterSystem.js#L395

It should work. You've made a mistake in a place that is hidden from my telepathy, please provide a demo on codepen/jsfiddle/pixi-playground.

I provided a demo on codepen,please visit this url: https://codepen.io/alexzchen/pen/GRKYZWq

I expect to draw filters based on the center point when tile/rotate/scale/move, not the upper left corner now, please help me, thanks.

Share this post


Link to post
Share on other sites

OK, I can explain how to work with calculateSpriteMatrix: imagine that you have both cloth and flowers inside the scene as a separate sprites. One covers another. Use "flowerSprite.position" , "anchor", "scale" and everything else to position FLOWER SPRITE correctly. the matrix will reflect it.

Share this post


Link to post
Share on other sites

Right now your approach is hybrid: you use both sprite matrix and manually add rotate/scale inside shader.

step 1: Forget about filter, use two sprites, set "flowerSprite.blendMode = PIXI.BLEND_MODES.ADD". Check that you correctly position/rotate/scale that flower sprite. 

step 2: add a filter, but keep flowerSprite in the stage for transform recalculation, set "flowerSprite.renderable=false" so it doesnt render. Dont use any rotations/scales/stuff inside filter, just use that filterMatrix and vFilterCoord.

Share this post


Link to post
Share on other sites

Also, if you are going to do "A.rgb*B.rgb" stuff - its basically MULTIPLY blendMode that can be achieved without filter. Try TilingSprite! 
 

var ts = new PIXI.TilingSprite(myTexture, w, h);
ts.tileTransform.position.set(w/2,h/2);
ts.tileTransform.scale.set(...);
ts.tileTransform.rotation = ...
ts.tileTransform.pivot.set(...); //offset

//might actually swap position/pivot there, i dont remember ;)

ts.blendMode = PIXI.BLEND_MODES.MULTIPLY;

Also see if you'll need to switch off mipmaps for flower texture. "flowerTexture.baseTexture.mipmap=false". Or set wrapMode to REPEAT, but that's only for pow2-textures. for non-pow2 you can also set mipmap to PIXI.MIPMAP_MODES.ON - that'll work for WEBGL2 (unavailable un most mobiles). Cant explain it all in one post, its tricky webgl stuff.

If you manage to make it work with sprite or tilingSprite, then filter is also easy - filterMatrix, vFilterCoord helps you to get correct coords for sampling, then you apply your own equation for colors. Dont forget that its premultiplied alpha - might have some problems if your flowers are transparent.

Share this post


Link to post
Share on other sites

In addition, there may be multiple sprites on my stage.

Yes, that looks like a Filter. But you can do the following: add flower inside cloth, and add a AlphaFilter on cloth. That way MULTIPLY approach can work :) The idea is that any filter forces pixi to use temporary FrameBuffer to calculate the result.

I'm not against approach of custom filter - I supply you alternatives that are easier to do, and that cant be tested and debugged fast - then you can make your own filter when everything else (transforms) is already solved.

Share this post


Link to post
Share on other sites

Thanks for your advice, I've tried it as you said. It seems to work, but how do I remove the black area? I want it became transparent which is black now

22.jpg11.png

 

function setup(loader, res) {
      
      let cloth = new PIXI.Sprite(PIXI.loader.resources["cloth"].texture)
      let flower = new PIXI.TilingSprite(PIXI.loader.resources["flower"].texture);
      
      let fw = 328;
      let fh = 240;
      let cw = 179;
      let ch = 182;

      flower.anchor.set(0.5,0.5);
      flower.rotation = 0.3;
      flower.scale.set(1.1,1.1);
      flower.width = fw;
      flower.height = fh;
      flower.position.set(fw/2,fh/2);
      flower.tilePosition.set((fw-cw)/2,(fh-ch)/2);

      flower.blendMode= PIXI.BLEND_MODES["MULTIPLY"];
      cloth.filters = [new PIXI.filters.AlphaFilter()];

      cloth.addChild(flower);
      app.stage.addChild(cloth);     
    }

 

Share this post


Link to post
Share on other sites

if your cloth wont be rotated, you can just change filterArea every frame - that will limit the temporary buffer pixi uses to draw this thing on.

cloth.filterArea = cloth.getBounds(); // execute every frame or every time you change something

If you start rotating cloth... well.. I believe you'll need to get inside filter and use that multiply formula you did before, "gl_FragColor = stuff1 * stuff2". However this time, you already have formulaes for position, scale and pivot (which is basically tilePosition of tilingSprite)

Actually, why do you even rotate that TilingSprite? I thought "tilingSprite.tileTransform.rotation" is better in your case :)

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

  • Recently Browsing   0 members

    No registered users viewing this page.