Search Unity

DstAlpha, Alpha BlendMode, Alpha BlendOp

Discussion in 'Shaders' started by chrismarch, Mar 12, 2018.

  1. chrismarch

    chrismarch

    Joined:
    Jul 24, 2013
    Posts:
    471
    I'd like to better understand how the alpha channel behaves under DX11 (2017.1.1, deferred, linear, hdr):

    1. What do you expect DstAlpha values to be after the opaque/"geometry" render queue? 1? (Assume all the opaque rendering is done with shaders like Standard that don't do anything unusual with alpha)

    2. Is the formula for the resulting alpha channel values different from the rgb channels for some BlendMode and BlendOp? For example, it doesn't make sense to me that dstAlpha = srcAlpha*srcAlpha + dstAlpha if I specify Blend SrcAlpha One (I would expect dstAlpha = srcAlpha).
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,338
    For the most part the alpha of the emission buffer / light accumulation buffer / frame buffer (they're all effectively the same thing at different stages of the deferred rendering passes) is left at 1.0. There's also no blend mode set (Blend One Zero) when filling out the gbuffers. For the Standard shader in deferred this is the line where it sets the emissive color.
    Code (CSharp):
    1.     // Emissive lighting buffer
    2.     outEmission = half4(emissiveColor, 1);
    As you can see it's hardcoded to a value of 1.0.

    Similarly the deferred lighting passes call the UNITY_BRDF_PBS function to calculate lighting, and that function returns a half4 with a hardcoded alpha value of 1, which will step on whatever alpha value was already there. Additionally, if you're not using an HDR render target the output color value gets stored using exp2(-c), then decoded using -log2(buffer). which means by default there's some good chance you're going to loose a little precision there if you're expecting perfectly accurate values, but they should roughly remain the same. You could trivially modify Internal-DeferredShading.shader to just pass the alpha along if you wanted it unmodified. Note some platforms do optionally use ARGB_2101010 for HDR which makes the alpha essentially useless.

    By default the same blend op is applied to both the alpha and the color.

    Blend SrcAlpha One is indeed dstAlpha = srcAlpha * srcAlpha + dstAlpha * 1.0. This is because most people simply don't care about the alpha after it's been "used". However you can specify separate blends modes and ops for the color and alpha values using a comma and defining a second blend mode pair or blend op. For deferred output you'd want to specify different blend modes for each target as the main gbuffers should likely remain Blend One Zero (unless you're doing decals).
    https://docs.unity3d.com/Manual/SL-Blend.html

    So you could do something like this if you want to output a transparent color, but also retain the exact alpha:
    Blend SrcAlpha OneMinusSrcAlpha, One One

    or optionally:
    Blend SrcAlpha OneMinusSrcAlpha
    BlendOp Add, Max
     
    Last edited: Mar 12, 2018
    HeyItsLollie and chrismarch like this.
  3. TheElumenati

    TheElumenati

    Joined:
    Jan 22, 2014
    Posts:
    38
    Thank you this helped me!