pixijs / spine

Pixi.js plugin that enables Spine support.
Other
564 stars 217 forks source link

Masking spine animation container that contains images with blendMode 'add' issue #356

Open kulabros opened 3 years ago

kulabros commented 3 years ago

Hi there all,

I'm getting unexpected result when applying bitmap mask (or SpriteMaskFilter) on Spine animation container, that contains images, that uses 'add' blend modes. When I apply mask, or set the mask as filter, in both cases the spine animation looses it's look on the scene, because the applied mask disables all blendMode settings inside Spine animation.

Is it somehow possible to apply bitmap mask for the whole spine container, without having this issue?

It is necessary for the visual look of the animation to keep the blendModes on layers inside the animation, as it interacts with the background on the scene. But I need to 'cut off' borders of fragments that overlap scene borders. I was doing it extra image, acting as mask, but it was actually overlaying the animation. Now I'm trying to figure out to do this masking of spine animation with bitmap mask. The bitmap mask is rendered ok and I can see the masking. But as I wrote, all blendModes inside the spine animation are loosen in time I apply the masking.

I've found some old threads about problems with setting alpha to the spine container, which said about having all containers inside the spine animation with worldAlpha = 1. Unfortunately, the animation I'm using is created with different worldAlpha's than 1, isn't this somehow related?

I was also trying to apply the mask (or mask filter) to the nested containers inside the spine, but it also doesn't work, the blend modes are loosed.

Thanks a lot for any help regarding this issue. Best regards, have a nice day! M.

I'm running pixi.js 5.3.3, pixi-spine 2.0.5

ivanpopelyshev commented 3 years ago

Two ways to do that

  1. Modify pixi MaskSystem that stencil can be used instead sprite masks - HARD difficulty.
  2. Hack sprite renderer that for ADD it doesnt actually change blendmode, but puts a tint (r*a,g*a,b*a,0) instead of (r*a,g*a,b*a,a). - MEDIUM difficulty

I can help with that in weekend. No one actually did that so I cant point you to pieces of code.

kulabros commented 3 years ago

Hi Ivan,

thank you very much for quick response - awesome! I'm trying to figure out both options you mentioned, but I think I'd need more help about doing this. 1 - do I have to modify push/pop methods, to use stencil in case of sprites, or the push sprite mask method itself? 2 - not sure, where should I do the change, is it the _render method of Sprite's prototype? If you could help me further that would be great, I really appreciate it. We can leave her the solution for others who will need to solve this.

ivanpopelyshev commented 3 years ago

1

Mesh as mask, need a mesh-shader that discards transparent pixels. Its easy to enable stencil - just use container.mask = new MaskData(obj) and specify stencil somewhere in that maskdata, i dont remember

2

this part of docs doesnt exist. at all. @SukantPal is making https://github.com/pixijs/pixi-batch-renderer/tree/master/packages/pixi-batch-renderer , but i have easy example: https://www.pixiplayground.com/#/edit/CMKvgOt-bvlCG4QHdswIP .

You have to override this method: https://github.com/pixijs/pixi.js/blob/dev/packages/core/src/batch/AbstractBatchRenderer.ts#L744 and adjust calculation of tint. Also, https://github.com/pixijs/pixi.js/blob/dev/packages/core/src/batch/AbstractBatchRenderer.ts#L486 should batch ADD and NORMAL together. Either do it through different field than blendmode, either override that part in custom renderer too.

The best option is actually to wait the weekend, and i'll make you full example :)

ivanpopelyshev commented 3 years ago

In general, your question isnt issue, its huge problem that no one made a documented workaround yet. The fact that I know how to do it, its because of my big experience with blendModes and layering. Tint trick (2) is actually used Unity implementation of spine.

kulabros commented 3 years ago

Amazing, full example would be very nice, I'll wait for that. I'll have a look at the code, links and examples you sent, but it's a bit low level for me. It's very cool that you have this knowledge about the blendModes, maybe this discussion and the example can help to move on forward with this problem. Good luck!:)

ivanpopelyshev commented 3 years ago

Thank you!

Here are materials about blending modes: https://ciechanow.ski/alpha-compositing/ http://www.adriancourreges.com/blog/2017/05/09/beware-of-transparent-pixels/ https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode https://www.w3.org/TR/compositing-1/#blending

Unfortunately, trick with "alpha=0 tint is same as ADD for opaque background" is not mentioned there.

ivanpopelyshev commented 3 years ago

@kulabros Anyway, I solved your problem , took 20 minutes: https://github.com/gameofbombs/pixi-heaven/#batch-add-blending-mode-with-normal . Here's how I did it: https://github.com/gameofbombs/pixi-heaven/commit/634eaa1d702fef4d7bc19b7e94b98b205c521efb#diff-d4316df935075db55a5ef6b2e476ef5eR110-R112

of course, it requires pixi-heaven plugin, that's my collection of hacks for spine.

Btw, look at maskSprite there, it can be handy too.

ivanpopelyshev commented 3 years ago

Demo is here: https://pixijs.io/examples/#/plugin-heaven/unity-add-blend.js

Notice that container with all sprites is filtered (same as SpriteMaskFilter)

kulabros commented 3 years ago

Hi Ivan, great, thank you very much! But now, I'm not sure if this is the same as my case, maybe we didn't understand well, or is it applicable for my case, using the heaven plugin? ... Because, I wanted to use bitmap mask over Spine animation container, is this the same problem? :) Thank you!