-
Notifications
You must be signed in to change notification settings - Fork 1
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
How to handle additive transparency #1
Comments
Just keeping a braindump here so I don't clutter up the issue tracker on UnityGLTF I'm tempted to attempt to implement KHR_blend as documented as an import/export plugin for UnityGLTF and use the new Open Brush export implementation as a test case. I'm not sure how to move KhronosGroup/glTF#1302 forward or whether it really matters. I'm more of a "rough consensus and running code" kind of guy and the concept of "unofficial but widely supported extensions" seems to be the way things are going with glTF. |
Wasn't aware of this proposal, thanks for the ping! @pfcDorn can you take a look? I think with the new plugin infrastructure it totally makes sense to support this in UnityGLTF, and if someone doesn't want it they just turn the plugin off. @andybak we may want to rename the extension to EXT_blend if there is no plan at Khronos to ratify KHR_blend. (Regarding implementations, Needle Engine does indeed support additive blending in glTF as part of a bigger NEEDLE_* extension but not in a standardization-happy format.) |
Yep. If we're going back to the drawing board I would consider some other changes. Is the current proposal too specific to how glsl/hlsl define blending ops? Is it too flexible and therefore complex? How would an importer for something like Blender work? I'm no Blender expert and I struggled to define an additive material at all using a Cycles material node graph. I'd be happy with an extension that just handled additive alone. I think the "additive vs alpha/multiplicative vs stencil" distinction accounts for 99% of use cases I see in the real world and additive is the only one of the three that is currently absent from glTF. |
I checked Shader Graph and it supports four transparent blending modes. They aren't documented but they are the same four that URP supports in the lit shader: https://docs.unity3d.com/Packages/[email protected]/manual/lit-shader.html
For an opaque shader you additionally get alpha clipping which is arguably a 5th mode. I'm still personally only really interested in additive but I wonder if adding Multiply and Premultiply would be a good baseline set (given that alpha and alpha clipping are already supported) |
In hindsight, I agree that my https://www.w3.org/TR/webgpu/#blend-state Also, better to have string enums than integer GL constants. |
In an ideal world this would simply be another potential value for alphaMode property: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#alpha-coverage If we want to ease the path towards standardization Maybe the extension should simply be an "extended alphaMode" - one that follows the same syntax and is used in preference for any client that supports the extension. In which case I'd be tempted to name the extension something like EXT_advanced_alphaMode |
If it's just another allowed value on that then some existing materials wouldn't translate over, for example "mesh has alpha cutout at 0.5 and is additively blended". |
My first thought is that setting any values on EXT_advanced_alphaMode would indicate that the "legacy" alphaMode, and alphaCutoff should be ignored. Is this consistent with how other extensions interact with existing properties? |
I tend to view this as a two-part problem:
|
The existing alphaMode supports:
EPIC_blend_modes has the following valid values:
and their behavior is described here: https://docs.unrealengine.com/5.1/en-US/material-blend-modes-in-unreal-engine/ As mentioned previously Unity Shader Graph has:
This matches the Unreal list perfectly from my brief reading. (I listed them in the same order above so you can see the matches) three.js is a bit different and closer to @donmccurdy 's suggestion in that alpha clipping and other blending modes are not mutually exclusive. I don't know unreal very well but this is doable in Unity. Alpha clipping would have to be done manually in non-opaque shaders. three.js doesn't have premultiplied blend but it does have subtractive blend. I'm personally in favour of leaving both out of this extension and going with the common subset. I'm still not clear how Blender handles this. It used to have additive as a simple setting but it was removed. I also suspect Cycles and Eevee might behave differently - I only looked at Cycles. I know Blender isn't the only non-realtime 3d app to consider but it's the one I have handy so I'm using it as a proxy for others. |
This seems to be the best Blender equivalent: https://developer.blender.org/docs/images/Eevee2.81_transparent_bsdf2.png The emission strength needs to probably be higher than 1.0 to match typical the look of typical glsl additive. EDIT fix link because Blender website doesn't update url when viewing an image. Grumble... |
Thinking about how interactions with the existing alphaMode would work:
The "common subset" discussed above reduces to:
Three of these map perfectly to existing alphaModes:
Which leaves:
Simply adding a new alphaMode property that has possible values of add/multiply would give us these two. @donmccurdy said:
Not sure what "existing materials" you're referring to? I'm assuming we'd doing "SrcAlpha One" in GL terms so the existing alpha is taking into account. You can't specify a hard cutoff but you can do alpha-masking. Is "alpha clip plus additive" used much? I just did a survey of Open Brush shaders (the ones used in brushes which is the reason we want additive blending) and it's actually fairly complex. On the whole we're doing However we're also using an even mix of |
Since there is a discussion of allowing "alpha clip plus additive" and/or However, can somebody clarify: If using a hypothetical "BLEND_AND_MASK" mode, is the cutoff value for "everything below this is fully transparent and everything above is blended" or is it "everything below this is blended and everything above is fully opaque"?
What about HASH, SUBTRACT, MAX, MIN? If we do as I suggest above and include a mask/clip boolean, then it might make sense to have this extension be comprehensive (even if most implementations don't support some of them), otherwise to do HASH with a mask/clip you'd need two extensions to avoid overlap (this ext for the bool, plus another ext). |
BLEND_AND_MASK : I believe it would be "everything below this is fully transparent and everything above is blended" in line with how Unity and Unreal handle "transparent + masked" surfaces. From a shader perspective it would probably be "everything below is discarded and everything above is blended". I think the question here starts to become "should we handle explicit cases, or should we just do blend modes". I believe the explicit cases are more useful in the context of glTF. |
OK. I sense a tension between a "maximalist" and "minimalist" spec here. I was aiming towards the latter because it felt like both:
I'm a bit dubious about alpha-hashing as it's not an out of the box mode in most of the platforms I looked at. And doesn't it potentially need another parameter? It also raises the question of what specific dither patterns to support. I know the term "hashing" implies a very specific algorithm but the underlying "fake opacity via selective discard" can be implemented in many ways. @aaronfranke are you mostly in favour of it because it's well specified in Godot? I guess I was arguing for a spec that had the common subset of modes. They seem to be both the most useful, easy to implement and widely supported in existing shader frameworks. I know implementers don't have to implement the whole extension but partial implementations are a pain point for users - and I fear some implementers might be dissuaded from supporting an extension if they can't easily support all of it. |
@andybak Hash is in Godot, plus @donmccurdy mentioned it here. I don't have any other reason, I have not used it personally (nor have I used most of these, as I'm not an expert in alpha blending modes). We can remove it if desired, leaving it to another extension, especially if it needs another parameter. @donmccurdy Can you weigh in on this? |
So - the minimalist spec would be just add and multiply (the common subset that seems to be universally supported) plus a bool for "always clip". I've already mentioned my doubts about hash. I don't recall seeing subtract used much "in the wild". Premultiply I'm unsure about. |
I don't have a very strong opinion but would be favourable towards including "alpha hashing" as mode. My reasoning would be that it's a way for asset authors to handle multi-layer transparencies that doesn't have a equivalent in glTF currently, and it isn't really possible to "guess" that an asset should use alpha hashing in a general case. One curious case I've seen in the wild is that when models are opaque and use an opacity value and an alpha cutoff value, then e.g. Apple's QuickLook will interpret that as alpha hashing. |
@hybridherbst To keep support for this mode, I'd like help collecting information on which apps have support for it (and what those apps call it). Also, do we need to add a new parameter for it? Godot has |
A lot depends on what you mean by "support". With Unity I looked at what Shader Graph supported. Unity does support code-based shaders but it's currently a rather fluid situation (the old render pipeline is deprecated, writing code shaders in URP and HDRP is poorly documented if you want to integrate with fog/lighting etc, the new unified pipeline is not yet available). I don't know enough about other ecosystems but my data above was based on what seemed to be supported in the obvious "out of the box" PBR shaders or graphical authoring system. With full hlsl/glsl access I presume anything is possible but it might be more work for implementers. We probably need to try a toy implementation across a few platforms or canvas some experts on those platforms. (also - some platforms offer support for low-level shader writing but with big caveats. i.e. a lot of Unity integration SDKs only support shader graph shaders. You can't build for Apple VisionOS if you use code shaders etc) |
The lack of support for additive blending has been discussed on the main glTF repo:
KhronosGroup/glTF#1189
and in the broader context of blending modes here:
KhronosGroup/glTF#1302
Unreal's glTF export plugins and their web viewer use an extension called EPIC_blend_modes but I can't find any documentation on it beyond the implementation here: https://github.com/ue4plugins/GLTFWebViewer
So we have two potential extensions - one documented with no implementation and the other with a single undocumented implementation.
I'm also wondering if regular PBR emissive could somehow be used to partially fake additive blending.
I'm surprised at the lack of interest in additive blending considering it's a fairly standard feature in most realtime and non-realtime engines and renderers and is a common technique to implement light beams, sparks, flames etc.
It is also useful as for avoiding issues with sorting of transparent objects. Additive blending is inherently order independent. This is one of the reasons that Open Brush uses is so extensively (z-sorting of brush strokes is especially problematic)
The text was updated successfully, but these errors were encountered: