3
$\begingroup$

As explained here, I use "glare" to add some bloom to my scene. The problem is that it creates emissive pixels, i.e. pixels that must both transmit all the light from object behind, AND add new light on top of it. However, as far as I understand, PNG format cannot deal with such objects because it uses non-premultiplied alpha. This is visible for example on this picture:

enter image description here

if I isolate the alpha channel I see its zero on all glared parts:

enter image description here

which explains why my final saved .png has no glare:

enter image description here

To mitigate that issue, I wanted to lighten the alpha channel with the value channel and write that into the alpha channel of the final .png. If I just isolate my new alpha channel, it looks fine into blender:

enter image description here

so I decided to replace the old alpha channel with this new one using "set alpha" in replace mode:

enter image description here

However, if I display the final png, it's not really what I'm after:

enter image description here

and if I isolate the alpha channel of this new layer, I can see that it is not at all the alpha channel that I chose above, it is not "blurred" enough:

enter image description here

I can't understand why the alpha I get is not the alpha I configured in blender. I'm thinking that it may be due to some premultiplied issues, but I'm not sure at all. Any idea what's wrong in my setup?

Here is my .blend file:

PS: in case it is of any interest, here are the color management settings: enter image description here

$\endgroup$

2 Answers 2

10
$\begingroup$

This issue stems from the way Blender currently performs color management. HDR color management is a complicated subject, so I recommend some related reading first if you are unfamiliar:

The problems of using color as alpha

The Blender compositor always works on scene-referred values in the Linear color space; this cannot be changed. This means that the RGB values of the rendered image are not in the range [0.0, 1.0], but rather [0.0, +∞), and they have not yet been mapped into the display color space (usually sRGB).

After compositing has finished, Blender applies the selected View Transform, which maps the scene-referred values into the display color space. The exact way this is done is outside the scope of this answer, but you can read the above links for more details.

Alpha makes the already-complicated color management story significantly more complicated. Importantly, the alpha channel is not affected by the view transform; alpha is always linear information stored in the [0.0, 1.0] range. Blender uses associated alpha (aka “premultiplied” alpha), so the meaning of these values is simply the amount that the background is occluded when using Alpha Over compositing.

This is a problem for your compositing setup, since you are trying to use color data directly as an alpha channel:

The color-to-scalar transformation is relatively well-defined—Blender just takes the luminance—but interpreting the result as alpha is more fraught. You are using a scene-referred value in the range [0.0, +∞) where a value in the range [0.0, 1.0] is expected. This has two problems:

  1. Most obviously, the values above 1.0 are simply clipped.

  2. More subtly, even inputs that are in the [0.0, 1.0] range will not be mapped to display-referred values.

The second point is tricky to understand, but its implications are severe. Scene-referred values don’t have any useful absolute interpretation, only a relative one, which means the set of values that fall into the [0.0, 1.0] range is largely arbitrary. In other words, the value you’ve ended up with is largely meaningless, and it only looks close to correct by sheer coincidence.

Imagining a better solution

The previous section outlines why using scene-referred color values as alpha is fundamentally the wrong approach, but what could a better one look like? The answer to that question is different depending on what you’re actually trying to do. Let’s address each of those in turn.

Rendering an image for further compositing

If the goal here is to generate an output image that is subsequently composited on top of another scene, converting to straight alpha at this point isn’t what you want, anyway. Instead, you should save your render in the OpenEXR format, which will save the raw scene-referred values using associated alpha.

This allows you to do your compositing in the scene-referred Linear color space, then convert to a display-referred format only as a final step. This sidesteps all of the problems that make color management of images with alpha channels so awkward to deal with, and it ensures you’ll get the highest-quality result.

Rendering an image for display

If you want your semi-transparent output to be the final render result, intended for direct display, things are more complicated. Converting from associated to straight alpha is not, in general, a lossless process, and doing it properly depends on what background the image will eventually be displayed against.

However, in this particular case, one reasonable interpretation would be to simply assume the image will be displayed upon a solid black background and calculate the appropriate straight alpha values from there. To do that, you would need to do calculations in the display-referred color space, since you care about which absolute color values are eventually produced.

Unfortunately, Blender currently does not currently provide any mechanism for converting from scene- to display-referred data in the compositor. Providing this functionality in a proper way would likely be tricky (since applying a view transform is a whole-image operation that depends on the overall light intensity of the image), but it isn’t in principle impossible. That said, that doesn’t help you much, since there’s no way to do it right now.

If you really want a straight alpha PNG that best captures the visual characteristics of your render, your best bet is probably to render to OpenEXR and use an external tool to “digitally expose” the image in a way that handles alpha more satisfactorily. I unfortunately do not know of such a tool to recommend, but maybe someone else can chime in if they do.

Sorry.

$\endgroup$
8
  • 2
    $\begingroup$ Full props! It warms my bones reading this sort of succinct response in 2021. 👏 $\endgroup$
    – troy_s
    May 18, 2021 at 2:02
  • 1
    $\begingroup$ @troy_s Thank you! It is nice to hear from you that I got the details right—I have only just recently been learning about any of this, so I am certainly no expert. Your writing on the subject has been very helpful. $\endgroup$ May 18, 2021 at 3:29
  • 1
    $\begingroup$ Thanks a lot for the answer, and even if you don't provide a real solution (and thanks a lot for your honesty), it is really helpful to understand the source of the issue. Now, if anybody knows a more or less accurate way to obtain (straight alpha) PNG, even using an external tool, I'd love to hear about it! $\endgroup$
    – tobiasBora
    May 18, 2021 at 8:02
  • $\begingroup$ Also, now that I know that colors are linear in the compositor, i.e. in [0.0, +∞), I'm confused: what are doing nodes like RGB curves, and which point are they choosing for the right most value? Are they first clipping everything above 1 to 1, and then do the mapping? But isn't it a bit strange since you said that [0,1] does not have any "mearning" in the linear space? Also, is there a way to inspect the actual value of the linear color at a given position? $\endgroup$
    – tobiasBora
    May 18, 2021 at 9:07
  • 1
    $\begingroup$ @troy_s I notice that the current (as of 2.92) RGB Curves node includes a “Standard” versus “Film-like” toggle, but the documentation currently does not explain what it actually does. Do you know what it means? (It is frustrating how difficult it often is to find precise information about how various parts of Blender’s pipeline actually handle color information, and I do not particularly want to dig through the source code right now.) $\endgroup$ May 18, 2021 at 19:06
0
$\begingroup$

The issue at hand here (as I understand it) is that Blender generates premultiplied alpha images as an output. Should you then want to composite the image on top of another image, if you were to use an alpha over operation, premultiplied alpha would give a more accurate result.

For those using the "Glare" node in the compositor specifically, I discovered the following workaround:

enter image description here

In essence, I replace the alpha channel of the output with the clamped alpha + value_after_glare. While I'm aware this is likely a horrible hack, it worked for my use-case.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .