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

20191218 add support for blend modes #1578

Conversation

johnSjo
Copy link

@johnSjo johnSjo commented Dec 18, 2019

A suggestion for adding support for blendModes in the Three.js runtime

The idea (from andrew_spn) is basically to make several geometry groups and materials.

I'm not sure why gitHub thinks the entier files have been modified
Ok, turn on "Hide whitespace changes" to see only the proper changes :)

@badlogic badlogic self-assigned this Dec 18, 2019
@adevart
Copy link

adevart commented Jan 7, 2020

@johnSjo Thanks very much for implementing this. I'm testing it just now. I noticed that the screen blending mode throws an error. To do screen blending, the following seems to work in ThreeJS:

material.blending = THREE.CustomBlending
material.blendDst = THREE.OneFactor

In the function toThreeJsBlending, maybe that can return a custom value (or array/object) for screen blending and in findMaterialGroup, check if blending equals that value and if so, set meshMaterial_1.blendDst = THREE.OneFactor.

@johnSjo
Copy link
Author

johnSjo commented Jan 8, 2020

@adevart Sure :)
Can we assume 'screen' is the only missing blendMode or is there a chance more will come in the future?
Basically: is it ok to hard code 'screen' to material.blending = THREE.CustomBlending and material.blendDst = THREE.OneFactor, or should I make it more customizable?

(Btw, are you sure it's suppose to be 'blendDst = OneFactor'? When looking at the WebGL runtime it looks like it's 'blendSrc' that should be set to OneFactor...)

@adevart
Copy link

adevart commented Jan 8, 2020

Screen is the only missing blend mode for Spine. It only supports normal, add, multiply, screen:

http://esotericsoftware.com/spine-api-reference#BlendMode

I don't think they'll add more so it would be ok to hard-code 'screen' to those values. One way I did it was to set a variable in ThreeJsTexture:

static BLEND_SCREEN = "SCREEN";
and returned ThreeJsTexture.BLEND_SCREEN in toThreeJsBlending
Then in MeshBatcher, check if (blending == ThreeJsTexture.BLEND_SCREEN) then set the blending to CustomBlending and blendDst to Three.OneFactor.

Then cast the blending assignments:
meshMaterial.blending = blending as THREE.Blending;

but it's ok if you return CustomBlending for screen to avoid the type workarounds. It's also possible to return an object for all the options in ThreeJsBlending like {mode:THREE.CustomBlending, blendDst:THREE.OneFactor}

I'm not sure if it should be blendDst = OneFactor. That gives the correct visual output. This page shows the blend modes:

https://threejs.org/examples/webgl_materials_blending_custom.html#

According to the following page, screen mode should be
blendSrc = THREE.OneFactor
blendDst = THREE.OneMinusSrcColorFactor:

https://stackoverflow.com/questions/3253932/how-to-do-something-like-photoshops-screen-blending-with-glblendfunc-opengl-es

That also gives the correct visual output for screen mode. It's probably best to go with that one if it matches the screen mode equation.

@johnSjo
Copy link
Author

johnSjo commented Jan 8, 2020

Added support for screen blendMode

@adevart
Copy link

adevart commented Jan 8, 2020

Nice, thanks. I'll do some testing on this update.

@johnSjo
Copy link
Author

johnSjo commented Feb 10, 2020

Hey @adevart @badlogic :)
Any update? is it good to go or does it need more work?

@adevart
Copy link

adevart commented Feb 10, 2020

@johnSjo Hi, I tested it on a number of Spine animations and for the most part it works really well. No layering issues and mixed blending modes works fine for normal, screen and additive modes. The one issue I saw was with multiply mode.

For some reason multiply mode renders some faces black. I attached an image showing the raptor Spine animation where its materials have been changed to multiply mode. Next to it shows the source spritesheet in multiply mode as a sprite.

The Spine correctly renders some of the parts, where transparency is rendered as a black outline but some of the parts like the tail render completely black. From what I could tell, this seems to be an issue in ThreeJS rather than this update because this happens in other places with multiply mode.

I tested it on the original Spine runtime implementation with a single material and switched the blending mode to multiply and the entire Spine object rendered black. I don't know if it's to do with the shader material that is used in the Spine runtime, maybe there's some custom code in the normal shaders for multiply mode.

multiply-mode-black

ThreeJS interprets transparency as black for multiply mode when it should interpret it as white. With a white background in the texture map, it renders much better. But doing this didn't fix every Spine animation for me, some layers still rendered as solid black.

multiply-mode-white_bg

I couldn't see any obvious reason why it would do this because it seems to work ok for some layers. At random, an object or layer in multiply mode just renders solid black.

@johnSjo
Copy link
Author

johnSjo commented Feb 10, 2020

Humm, odd
I'll investigate a little to see if I can find something

@johnSjo
Copy link
Author

johnSjo commented Feb 12, 2020

Hello @adevart :)
ok, found the issue

It's working as it should but maybe not as expected...

The normal 'multiply' works on the color values of the pixels, regardless if they are transparent or not, i.e. a pixel with the value (123,43,23,0) would normally be invisible, but with blenMode 'multiply' turned on the color of (123,43,23) will be used.

That's why you get those black boxes around items (if you set the alpha on every pixel to 1 you will see that black is used as the "background" color). A white background (like what you tried) will work, the reason that the "tail-shadow" still stayed black was because they animated the alpha (but were using black as the base color, "color": "0000004a" instead of "color": "ffffff4a")

When I change that I get this:
Screen Shot 2020-02-12 at 10 45 00

So the take away is that if you're going to use 'multiply' you need to prep your textures (and possibly your animation) in the right way. It's not the most intuitive way and I don't think it's explained enough in the three.js docs...

Do you think we should do anything more with this or leave it as is?

@adevart
Copy link

adevart commented Feb 13, 2020

So the take away is that if you're going to use 'multiply' you need to prep your textures (and possibly your animation) in the right way. It's not the most intuitive way and I don't think it's explained enough in the three.js docs...

Aha, thanks for checking that out. Yes there needs to be special consideration for the assets when dealing with multiply mode in ThreeJS.

Do you think we should do anything more with this or leave it as is?

I think it's working great. I don't think there's much that can be done to improve on this solution for supporting multiple blend modes.

@johnSjo
Copy link
Author

johnSjo commented Jun 15, 2020

@NathanSweet So was it decided not to add this, or? since it's closed without a merge.

@NathanSweet
Copy link
Member

Ah, sorry! I didn't notice that GitHub closed this PR automatically when the 3.9-beta branch was deleted. Our next release will be quite large so we are skipping 3.9 and the next release will be 4.0. Can I bother you to create a new PR on the 4.0-beta branch? Sorry for the trouble.

@johnSjo
Copy link
Author

johnSjo commented Jun 15, 2020

sure, I'll make a new one

@johnSjo johnSjo deleted the 20191218_add_support_for_blendModes branch October 20, 2021 07:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

None yet

4 participants