godot icon indicating copy to clipboard operation
godot copied to clipboard

Add premult alpha blending to 3D (spatial) shaders

Open QbieShay opened this issue 1 year ago • 6 comments

Follow-up to https://github.com/godotengine/godot/pull/68548 Implements https://github.com/godotengine/godot-proposals/issues/3431#issuecomment-1757999180

QbieShay avatar Dec 01 '23 15:12 QbieShay

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 avatar Dec 02 '23 18:12 OhiraKyou

@OhiraKyou could you give me an example usecase of this multiplier being a vec3? what kind of effect would it enable?

QbieShay avatar Dec 10 '23 10:12 QbieShay

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.

OhiraKyou avatar Dec 10 '23 20:12 OhiraKyou

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)

QbieShay avatar Dec 14 '23 14:12 QbieShay

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.

mikejohnstn avatar Apr 12 '24 20:04 mikejohnstn

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.

akien-mga avatar Apr 30 '24 14:04 akien-mga

Thanks!

akien-mga avatar May 01 '24 07:05 akien-mga

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.

jitspoe avatar May 01 '24 09:05 jitspoe

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 avatar May 09 '24 02:05 jitspoe

@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?

QbieShay avatar May 09 '24 08:05 QbieShay

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?

clayjohn avatar May 09 '24 16:05 clayjohn

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.

akien-mga avatar May 10 '24 08:05 akien-mga

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.

QbieShay avatar May 10 '24 12:05 QbieShay

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

clayjohn avatar May 10 '24 13:05 clayjohn

Because the fog should be applied only to the non transparent parts of a quad. Alpha zero, factor non zero = additive.

QbieShay avatar May 10 '24 13:05 QbieShay

@jitspoe Please test against latest master, I can't reproduce. Don't forget to use the PREMUL_ALPHA_FACTOR

QbieShay avatar May 14 '24 17:05 QbieShay

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.

jitspoe avatar May 17 '24 02:05 jitspoe

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.

jitspoe avatar May 17 '24 03:05 jitspoe

太棒了,多年来终于解决了这个问题。

xa8et67 avatar Jun 04 '24 15:06 xa8et67