godot
godot copied to clipboard
Add premult alpha blending to 3D (spatial) shaders
Follow-up to https://github.com/godotengine/godot/pull/68548 Implements https://github.com/godotengine/godot-proposals/issues/3431#issuecomment-1757999180
I suggest converting this PR to an implementation of a general-purpose DELAYED_RGB_MULTIPLIER built-in vec3, as described in my comment on the associated proposal issue. Most of the necessary code is the same (minus the automatic blend mode enabling, which would be omitted).
Example:
#ifdef DELAYED_RGB_MULTIPLIER_USED
vec3 delayed_rgb_multiplier = vec3(1.0);
#endif // DELAYED_RGB_MULTIPLIER_USED
@OhiraKyou could you give me an example usecase of this multiplier being a vec3? what kind of effect would it enable?
First, vec3 * float multiplication is per-component anyway. So, it's just good form to expose each component's multiplier to the user by making the multiplier a vec3 as well. That said, here are a couple of specific use cases.
Assumptions
The use cases described below assume the following:
- The multiplier is generally available rather than coupled to the premultiplied alpha blend mode—which it really doesn't need to be coupled to.
- The multiplier is applied after the sRGB to linear conversion and after built-in lighting.
Use cases
Custom channel mixing
Custom, per-channel post-processing of shader output colors—that includes lighting—may be applied in linear space by assigning a color multiplier to the delayed multiplier.
This includes processing of per-channel, non-color data for custom buffer rendering.
Custom colored lighting
Custom colored lighting (with no actual light objects in a scene) may be implemented in linear space in otherwise sRGB compatibility renderer shaders by ignoring the existing lighting system (i.e., using unshaded shaders) and assigning custom light output to the delayed multiplier.
We've discussed this PR in the rendering meeting and the design/thinking process around this is the following:
Like everything in Godot, we want to first talk about problems, then solutions. The usecases you have provided are more along the lines of "if this was there, I could use it like this" rather than "I have this problem and I can't solve it without this".
Light multiplication is something I personally really want to do. I am hoping to be able to eventually have a post-light function (this is a wish, not a promise). But we need to respond with solution when there's a problem to begin with. But this is a whole different problem than what we're trying to solve here. The problem to begin with here is having premultiplied alpha in the engine, so we should focus of solving that problem.
Additionally, concerns have been brought up about leaving doors open for usecases that are not explicitely supported: this may be a problem in the future when optimizing shaders or refactoring them. I understand that we could say "any use outside of premul alpha is unsupported and you're on your own if you do it" but this historically has never worked: people depend on it, and are disappointed when we "break" things that were never supposed to work to begin with.
I will bring this PR to completion in this dev cycle (4.3), unless something comes up, so that we can finally have premul alpha in 3D ^^ (integrating the render mode too)
Any idea if PREMUL_ALPHA support is still targeting 4.3? I'm building a tool that depends on it, so it would help to know if I can aim to target a particular release.
This PR uses a mix of PREMULT_ALPHA and premul_alpha spelling (note the presence or absence of T). This should be unified to use only one spelling.
Thanks!
Does this PR address fog making stuff light up that should be transparent? That was one thing I never got around to fixing on mine.
Ok, just cherry-picked this and tested and verified that this does NOT properly address fog, at least independently. I did notice there were some other fog related things in the shader file that changed, but I don't think they're related. Guess that should still be addressed.
To better explain, I'm using flame sprites with premult alpha, and if I have fog enabled, the whole quad starts becoming visible, (additively blended with the fog color). I thought maybe the premult_alpha_factor would somehow get used, but looking closer, I'm not really sure what premult_alpha_factor even does, as it seems to just be renamed to premult_alpha, which is a bit confusing.
@jitspoe it's multiplied at the very end of the shader. Do you mind supplying a test scene with your setup (via DM is fine too) so that u can try and fix the dog issue?
Ok, just cherry-picked this and tested and verified that this does NOT properly address fog, at least independently. I did notice there were some other fog related things in the shader file that changed, but I don't think they're related. Guess that should still be addressed.
To better explain, I'm using flame sprites with premult alpha, and if I have fog enabled, the whole quad starts becoming visible, (additively blended with the fog color). I thought maybe the premult_alpha_factor would somehow get used, but looking closer, I'm not really sure what premult_alpha_factor even does, as it seems to just be renamed to premult_alpha, which is a bit confusing.
Can you share your shader? Are you writing to PREMUL_ALPHA_FACTOR?
Make sure to also cherry-pick #91399 if testing on a branch different from upstream master, as this PR wouldn't be functional without that fixup.
I havent had a chance to boot my dev PC yet but I think I understand the issue, I'll debug it later. If it is what I imagine, I need to multiply fog by alpha if render mode pmul alpha is on.
I havent had a chance to boot my dev PC yet but I think I understand the issue, I'll debug it later. If it is what I imagine, I need to multiply fog by alpha if render mode pmul alpha is on.
Pmul alpha is already multiplied after fog though. I don't see why you would need to multiply it twice
Because the fog should be applied only to the non transparent parts of a quad. Alpha zero, factor non zero = additive.
@jitspoe Please test against latest master, I can't reproduce. Don't forget to use the PREMUL_ALPHA_FACTOR
So it seems like PREMUL_ALPHA_FACTOR just scales the albedo color value, effectively turning it into a regular alpha, kind of defeating the purpose of the premultiplied aspect. Fixes the fog, but the whole point is to be able to have additive things like flames mixed in with alpha masked stuff like smoke. Unless I'm just not understanding how this is intended to be used? Still trying to understand the reasoning behind PREMUL_ALPHA_FACTOR. How is it different from just scaling ALBEDO?
Building latest main now to do further tests.
I'm moving the discussion to https://github.com/godotengine/godot-proposals/issues/3431#issuecomment-2116564276 so it's in one cohesive location, since there is a lot of other discussion in there as well.
太棒了,多年来终于解决了这个问题。