-
-
Notifications
You must be signed in to change notification settings - Fork 22.8k
Blend Factor Specification in Shaders #102366
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
base: master
Are you sure you want to change the base?
Blend Factor Specification in Shaders #102366
Conversation
4ff3ac6
to
ea74d67
Compare
This PR fixes an important issue in my game that has no viable workaround. I'd love to see this in 4.5! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested locally (rebased on top of master
6b5b84c), it works as expected.
Testing project: test_pr_102366.zip
advanced_blend_modes.mp4
Forward+ | Mobile | Compatibility |
---|---|---|
![]() |
![]() |
![]() |
Some of the materials in the testing project look noticeably different when using Compatibility. I'm not sure if this is a bug or a limitation or what's available in Compatibility, so please check this.
Some feedback:
- There's no autocompletion for
blend_factors
options, which impacts usability. - If you specify less than 4 arguments (or more than 4), you'll get a cryptic error message:
Instead, a dedicated error should be shown to mention that blend_factors
accepts exactly 4 arguments separated by commas.
ea74d67
to
41cec58
Compare
It's rendering the editor background color ( |
Ahh, good call. Then that explains why the final alpha value of the framebuffer is so important, and why it's initially set to 1.0 when it gets cleared. That being the case, I would say that the PR is working as expected, as far as I can tell. The blending operation is producing the output color & alpha values it is directed to produce. |
Just checking in; are there outstanding issues here that I need to be resolving? The PR appears to be producing the right images in the framebuffer; there are just differences in how the framebuffer's alpha channel goes on to be treated, by the different renderers. |
servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
Outdated
Show resolved
Hide resolved
servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
Outdated
Show resolved
Hide resolved
41cec58
to
31cf95e
Compare
Is there anything else that I need to address, with this PR? |
It's good on my end, but it needs a review from another rendering maintainer before it can be merged. |
I saw this supports BlendFactor, does it support BlendOperation ? https://docs.godotengine.org/en/latest/classes/class_rdpipelinecolorblendstateattachment.html#class-rdpipelinecolorblendstateattachment |
No, this PR only deals with BlendFactor. Adding support for more BlendOperation modes is being at least partially addressed by other PRs (e.g., PR #48654). |
#48654 just adds two render mode presets, not custom blend operation. I wonder if it will work if we add |
Those "render modes" primarily just end up setting the blend equation. Once this PR and that one were merged, I think the only missing flexibility would be having different blend equations for RGB vs Alpha.
Sure, it would work. I'm not going to try to cram that into this PR, but sure, a follow-on could allow direct specification of blend operations. That said, I think the motivation for doing so might be somewhat harder to demonstrate; I can't think of a time when I've ever seen a technique that relied on having different blend equations for RGB than Alpha. I'm sure they exist, but I couldn't point one out to justify why we should go changing the renderer. |
31cf95e
to
0d8c58c
Compare
Rebased to resolve merge conflicts |
0d8c58c
to
f25991f
Compare
Anything we can do to get this reviewed by a second rendering maintainer? |
To be blunt, I don't see any path towards this being merged. It looks well done and LunaticinAHat has clearly done excellent work. But exposing every blend operation totally goes counter to Godot's philosophy of keeping things simple. It exposes the entire range of blend modes from the underlying graphics APIs directly to users. There are thousands of possible blend modes and fewer than a dozen are actually useful. What we should be doing is exposing the useful blend modes directly that people need (like what we did recently with the premultiplied alpha blend mode). This keeps Godot shaders simple and manageable for users. Users that know what they are doing and want to play around with the full range of options exposed by the graphics API can use the RenderingDevice API directly. But GDShaders should remain simple easy to understand for the majority of users who don't need that complexity. Our best practices make this quite clear as well |
Thank you, and thank you for being clear about your perspective. I'm not entirely surprised to hear this, but I have a few counterpoints I'd like to present:
First, I disagree to a certain degree about how narrow the set of blend modes that "people need" is. When you are authoring new content, and aren't trying to reproduce any particular aesthetic from the past, it's probably true that there are only a handful of blend modes that matter. But some users (including myself) use Godot to try to recreate old games. And there is an era of gaming where artists were using lots of weird blend modes. I am pretty confident that I (and those other users) would never succeed in trying to convince you to add specific support for those oddball modes, so I wanted to pursue this feature because the alternative is to not be able to faithfully recreate the look of the old games at all. Second, we just added support for stencil-buffer operations to GDShaders (#80710). When we did, we didn't just implement support for a couple of usecases that we thought were most common. We exposed the stencil buffer -- operation, compare value, write mask. This PR is just doing the same thing for blend modes. I haven't removed any of the "canned" blend modes, and I'm not pushing in that direction; as I said in my PR description, I think the canned modes should serve the vast majority of needs. This PR adds a new capability, but if people can't grok it, they can just ignore it, just like the stencil stuff.
As far as I was able to tell, when researching before implementing this PR, the door to rare use cases is actually pretty much shut, in this area. Maybe you can point me at something I missed, but I was entirely unable to find a way to hook anything material-/or shader-esque into the existing renderers, in any way such that I could put pipeline attachments on it, to control the blend modes. It looked very much like my only option, for getting control over blending, was to effectively reimplement the renderer. And that is just setting the bar way too high, for something minor like blend modes, in my opinion. Maybe I misunderstood something, or maybe the docs aren't clear, but I tried going down the RenderingDevice avenue before I ever even considered writing this PR, and I felt like I just ran into a brick wall. Finally, I'd like to make the point that I think this PR provides a useful and extensible framework for implementing additional blend modes in the future. Even if you disagree with my above points, and want me to drop the That is, rather than having a render-time (in the case of the GLES3 renderer, at least) Then, when you have to add another new blend mode in the future, rather than having to do work inside of each of the renderers, the work is limited to the shader compiler, expanding the set of blend factors that the user is capable of expressing to it (which it then places into the materials). If you're interested in moving in that direction, I'd be happy to pull the |
I want to first of all thank you for spending time to supporting this feature. As one of the people that pushed premul alpha forward, i understand the need for more of what Godot exposes. However, this is not really the process that we do to include features in the engine. To expand on what clay said, we don't do speculative features, not even for the sake of getting feature parity with other engines. Please @milesturin and/or @LunaticInAHat take time to detail what artistic approach you're currently unable to achieve due to lack of exposed blend functions, that's what may move this forward.
This is not how stencil has been exposed. We didn't ship masks or incr/decr operations yet precisely because of this broader discussion.
@clayjohn want to pitch in on this specifically? |
This PR is an implementation of Proposal 7058, which I had linked in the PR description, but perhaps I didn't make the relationship clear enough. The implementation differs in a couple of details from that proposal (choice of keyword, separate color vs alpha factors), but that proposal was the inspiration for my work. Perhaps I should have commented on that proposal, documenting my reasons for believing these alterations were necessary. No-one from the rendering team had popped into that proposal to weigh in, so it didn't look like it was being paid attention to, and I figured it would stand a better shot of acceptance if there was real code backing it up. If your process is to carry the rest of the discussion on about what the right API for the feature is, in that proposal, that's fine by me.
I would say that there isn't too much "speculation" about the need for more blend modes. It's been a capability of graphics cards that game engines have been exposing since the 90s, and there are plenty of users who want to use additional blend modes beyond what is currently available (like this proposal, plus the ones I already linked in my PR description). The usecases and exact blend modes that they want are often different, but the common theme of "we need to specify different blend modes" remains. The API we use to expose this is plenty open to debate, sure. Is it a keyword in the shader? Is it a function we call on the It can't be specified at the My motivation for specifying it within the shader program text was roughly this:
My motivation for allowing direct user specification of the four blend factors was largely because I was daunted by the prospect of trying to come up with descriptive, meaningful names that would fit in a
Sure. Understand that I am not an artist: I am a programmer, seeking to re-engineer classic games. At a high level, what I am currently trying to achieve (and am unable to, without finer control of blend factors), is to be able to render assets from World of Warcraft, and have them look right. WoW uses (at least) the following set of blend modes:
I can't justify or defend most of those modes. I don't know why they chose those specific modes. Quite a few of them are similar to existing modes, but differ in how they treat the alpha channel, so mis-blending only shows up when multiple translucent objects are overlapping, which makes it difficult to find and showcase examples for you. But, to try to help you see where I'm coming from, here is an example of one of the more obvious modes in action: Here is what it looks like, with a regular Notice how much darker the affected surfaces are.
A fair point. I would say that, despite the holdout of those features (at least for now), users are given significantly more nuanced control of the stencil buffer than they are of blend modes. |
This PR augments shaders to allow explicit specification of which blend factors should be used for the material, and adds a directive to the shading language accordingly (
blend_factors
). These blend factors are expressed in terms that are already familiar toRenderingDevice
, but lowercased to fit in with other identifiers in the shading language (e.g.,src_alpha
,one_minus_src_alpha
,dst_color
, etc.)The current paradigm for specifying blend modes (
render_mode
) provides only the handful of most commonly-used blend modes, but the underlying graphics APIs support thousands of possible blend modes (4 fields, 19 possible values in each position = many thousands of options). Some applications would wish to use some of those blend modes which are not currently accessible to shaders (e.g., emulation/recreation of old games).Additionally, direct support for specifying blend modes will provide more flexibility when using premultiplied alpha. It would also allow users to force material opacity, for shaders which don't currently support
blend_disabled
.Finally, this would bring our blending flexibility much closer to what is supported by other engines, which would make it easier for developers using those engines to transition their materials to Godot. This Unigine documentation of the feature gives some nice examples of effects that can be achieved by combining various blend factors.
The underlying blend factors are already supported in
RenderingDevice
; this PR just allows shaders to explicitly specify the quartet that they want.This does not seek to replace or remove the existing blend mode specifications in
render_mode
for two reasons:blend_*
specifications are perfectly sufficient and much more user-friendlyADD
,REVERSE_SUBTRACT
,MIN
,MAX
, etc.), and theblend_*
specifications seem perfect for thatThis feature is very straightforward to add to the
RenderingDevice
-based renderers, with minimal intrusion. Adding it to the Compatibility renderer is a bit more intrusive, but these blend modes have been supported since ancient, fixed-function OpenGL days, so there was no reason not to add them to the GLES3 renderer.render_mode
godot-proposals#2621.