Pixi.js: CacheAsBitmap has effect on filters

Created on 19 Mar 2018  ยท  9Comments  ยท  Source: pixijs/pixi.js

Pixi.js version: 4.7.1
Browser: Google Chrome V65
OS: macOS High Sierra 10.13.3
โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“

Hi everyone,

I've noticed that when combining the cacheAsBitmap option with the filters option you get weird results.

This is my sprite without the cacheAsBitmap option enabled:

screen shot 2018-03-19 at 16 58 22

This is the code I use to set up the sprite:

getImageSprite(image, texture) {
  const imageSprite = new PIXI.Sprite(texture);
  const { height, width } = this.getImageSpriteSizes(texture.baseTexture, image.size.w);

  // Set the name so it can be found later on
  imageSprite.name = image.identifier;

  // Set the anchor point in the center
  imageSprite.anchor.set(0.5);

  // Set the coordinates, width and height
  imageSprite.x = this.app.renderer.width * image.location.x;
  imageSprite.y = this.app.renderer.height * image.location.y;
  imageSprite.width = width;
  imageSprite.height = height;

  // Set up and add the filters
  const blur = new PIXI.filters.BlurFilter(1);
  const shadow = new DropShadowFilter({
    alpha: 0.9,
    blur: 6,
    color: 0x000000,
    distance: 0,
    quality: 5,
    rotation: 0
  });

  // This line makes it that the DropShadowFilter doesn't get cut off
  // https://github.com/pixijs/pixi.js/issues/4723
  blur.padding = 50;
  imageSprite.filters = [blur, shadow];

  return imageSprite;
}

As you can see everything works fine. However, when I add the cacheAsBitmap option my sprite suddenly looks like this:

screen shot 2018-03-19 at 17 00 17

My filters act different. Any idea if this is a bug or am I missing some configuration?

Don't hesitate to ask for additional information and thanks in advance!

Most helpful comment

I emailed David directly, here's my response for others that find this issue:


The problem is most likely an issue with the DropShadowFilter. Weโ€™ve had a bunch of performance problems with this and are waiting for someone to create a performant DropShadow filter. cacheAsBitmap does, in fact, work with filters https://jsfiddle.net/9sqt2Ljc/5/.

My suggestion is to use BlurFilter to create your own manual shadow with a sprite and set opacity and tint.
https://jsfiddle.net/tdn7kk9a/3/

Hope that helps.

All 9 comments

Put it inside another container. cacheAsBitmap on top, filters on bottom.

Its not clear whether filters should be applied inside cache of element or outside.

@ivanpopelyshev thanks for your quick response! I did with you suggested but still my filters act weird.

Container without cacheAsBitmap option:

screen shot 2018-03-20 at 10 33 01

Container with cacheAsBitmap option:

screen shot 2018-03-20 at 10 33 48

This is my updated code:

getImageSprite(image, texture) {
  const { height, width } = this.getImageSpriteSizes(texture.baseTexture, image.size.w);

  // First setup the container and sprite
  const container = new PIXI.Container();
  const sprite = new PIXI.Sprite(texture);

  sprite.width = width * 3;
  sprite.height = height * 3;

  // Set up and add the filters
  const blur = new PIXI.filters.BlurFilter(1);
  blur.padding = 50; // https://github.com/pixijs/pixi.js/issues/4723
  const shadow = new DropShadowFilter({
    alpha: 0.9,
    blur: 6,
    color: 0x000000,
    distance: 0,
    quality: 5,
    rotation: 0
  });

  sprite.filters = [blur, shadow];

  // Set the name so it can be found later on
  container.name = image.identifier;
  container.x = (this.app.renderer.width * image.location.x) - (width / 2);
  container.y = (this.app.renderer.height * image.location.y) - (height / 2);

  container.addChild(sprite);
  container.cacheAsBitmap = true;
  container.scale.set(1 / 3);

  return container;
}

I'm still struggling with this problem. That's why I decided to open this StackOverflow question.

Any help is welcome!

DropShadowFilter isnt working for me. I'm sorry that no one helped you for the week, but you have no chance for this question in stackoverflow.

I suggest to poke @bigtimebuddy instead.

I emailed David directly, here's my response for others that find this issue:


The problem is most likely an issue with the DropShadowFilter. Weโ€™ve had a bunch of performance problems with this and are waiting for someone to create a performant DropShadow filter. cacheAsBitmap does, in fact, work with filters https://jsfiddle.net/9sqt2Ljc/5/.

My suggestion is to use BlurFilter to create your own manual shadow with a sprite and set opacity and tint.
https://jsfiddle.net/tdn7kk9a/3/

Hope that helps.

@bigtimebuddy thanks for your help so far!

However, your solution doesn't really work. I've managed to render the 'fake shadows' on the right spots but I've also encountered two problems so far:

  • My images can be moved and during this animation they will also scale a little. This means I also need to move and scale my 'fake shadows', which is very hard to do since the positioning of these sprites behaves differently compared to my containers.
  • More importantly, the performance is not good. When I render 100+ of these 'fake shadows' the performance drops to 1 FPS.

This is my update code:

getImageSprite({ image, texture }) {
  const { height, width } = this.getImageSpriteSizes({ baseTexture: texture.baseTexture, ratio: image.size.w });

  // First setup the container and sprite
  const container = new PIXI.Container();
  const sprite = new PIXI.Sprite(texture);
  const spriteWidth = width * ZOOMED_STAGE_SCALE;
  const spriteHeight = height * ZOOMED_STAGE_SCALE;

  // Set the sprite dimensions and position
  sprite.width = spriteWidth;
  sprite.height = spriteHeight;
  sprite.x = -spriteWidth / 2;
  sprite.y = -spriteHeight / 2;

  // Add the blur filter used for the 'fake' shadow
  sprite.filters = [new PIXI.filters.BlurFilter(16, 16)];

  // Give the container a name so it can be found later on and set the position
  container.name = image.identifier;
  container.x = this.app.renderer.width * image.location.x;
  container.y = this.app.renderer.height * image.location.y;

  // Add the sprite to the container and scale it down
  // Also set the zIndex used for sorting
  container.addChild(sprite);
  container.scale.set(1 / ZOOMED_STAGE_SCALE);
  container.zIndex = image.location.z;

  // Setup a RenderTexture to 'fake' a shadow
  // https://github.com/pixijs/pixi.js/issues/4773#issuecomment-376544044
  const renderTexture = PIXI.RenderTexture.create(APPLICATION_WIDTH, APPLICATION_HEIGHT);
  this.app.renderer.render(container, renderTexture);

  const shadow = new PIXI.Sprite(renderTexture);
  shadow.anchor.set(0.5);
  shadow.name = `${image.identifier}_shadow`;
  shadow.opacity = 0.1;
  shadow.tint = 0x0;
  shadow.x = this.app.renderer.width * 0.5;
  shadow.y = this.app.renderer.height * 0.5;
  shadow.zIndex = image.location.z - 0.5;

  // Set the filter used for the image and cache the container as bitmap
  sprite.filters = [new PIXI.filters.BlurFilter(1)];
  container.cacheAsBitmap = true;

  return {
    imageSprite: container,
    shadow
  };
}

@bigtimebuddy @ivanpopelyshev I'm almost there!

Just need to solve the following issue: https://github.com/pixijs/pixi.js/issues/4812

Any help would be appreciated!

Solution to this problem is posted in https://github.com/pixijs/pixi.js/issues/4812

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zcr1 picture zcr1  ยท  3Comments

YuryKuvetski picture YuryKuvetski  ยท  3Comments

courtneyvigo picture courtneyvigo  ยท  3Comments

readygosports picture readygosports  ยท  3Comments

neciszhang picture neciszhang  ยท  3Comments