Search Unity

Incorrect Blending Values

Discussion in 'Shaders' started by Avol, Sep 20, 2019.

  1. Avol

    Avol

    Joined:
    May 27, 2016
    Posts:
    46
    How would I blend RGBA texture using Blend Add in such fashion (r, g, b, a) + (r2, g2, b2, a2).
    All the blend modes I've tried don't directly sum the results. Even if I render a single fragment with 0.2, 0.2, 0.2, 0.2 values I get alpha and rgb value as 1 or more while I would expect those values to be at 0.2. I assume Blend One One, One One should just sum the values, but it doesn't - values always turn out to be higher. Can it be a texture precision issue(tried different ones same result) or something like that?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    7,930
    Can you explain more about what exactly you’re doing and how you’re testing the final color values?

    If you have a additive shader (using Blend One One) just outputting the texture values, the results should be identical to adding the two colors together. Random things are some built in Unity shaders use ColorMask RGB, which means it doesn’t write to the alpha, and if you’re checking the final color using ReadPixels to a Color32 value, those values are byte colors so an output of 0.2 is 51/255.
     
  3. Avol

    Avol

    Joined:
    May 27, 2016
    Posts:
    46
    Drawing a line strip using DrawProceduralNow. Using custom RT for color buffer(clearing it every frame before rendering) and depth buffer of current camera.
    Then composing that RT values in OnRenderImage() to screen. While drawing a single line strip with One One, I need to use a low alpha value such as 0.004, lower will be filled with 0 and something higher like 0.01 will fill alpha value to 1. Using other blend modes it writes values correctly, but instead of summing two separate fragment values, overwrites them with new one.

    Code (CSharp):
    1.         Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
    2.  
    3.          ZWrite Off
    4.          Cull Back
    5.          BlendOp Add, Add
    6.          Blend One One, One One
    7.  
    8.  
    9.  
    10.                 float3  albedo  = float3(0.004f, 0.004f, 0);
    11.                 float   alpha   = 0.004;
    12.  
    13.                 return float4(albedo, alpha);
     

    Attached Files:

  4. Avol

    Avol

    Joined:
    May 27, 2016
    Posts:
    46
    this is an example of many line strips overlapping, I would expect the alpha and color values to be much lower when using a 0.004 value.
     

    Attached Files:

  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    7,930
    The alpha value isn't a factor in the shader snippet you showed at all. You're using straight additive blending, which just uses the color value. You could change the alpha value to be 1.0 or 0.0, or 10000.0 and it won't change the image you're seeing. If you want the alpha to do something you need to multiply the color by the alpha either in the shader or by using Blend SrcAlpha One.

    Are you sure your strips aren't duplicating any geometry?
    What color space is your render texture? ie: are you rendering to a gamma or linear space RT, and what's the read mode?
    How are you compositing the result? Is that also using Blend One One?
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    7,930
    Generally when rendering to an external buffer that you want to composite back into the main view later, you need to be extra careful with the output alpha and blend mode as the values written to the alpha channel when rendering directly to a buffer don't actually matter. You also then need to make sure you're using a premultiplied alpha blend (Blend One OneMinusSrcAlpha) when doing the composite. You also want to make sure you're rendering to a RT using the same color space as your main rendering.

    When rendering an additive shader to the RT, you should be using:
    ColorMask RGB
    Blend One One

    or:
    Blend One One, Zero One

    If you want the output alpha to affect the blended color in the RT, then use:
    ColorMask RGB
    Blend SrcAlpha One

    or:
    Blend SrcAlpha One, Zero One


    For alpha blended objects rendered to the RT, you should be using:
    Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha


    For premultiplied objects, use:
    Blend One OneMinusSrcAlpha, One OneMinusSrcAlpha


    The end result is the values in the RT is appropriate for use with a premultiplied alpha blend to composite. That would be that last blend mode shown above, with or without the alpha handling, since once you blend back with the main buffer the alpha values no longer really matter. If you're doing the composite within the shader, it'd be:
    Code (csharp):
    1. half4 main = tex2D(_MainTex, uv); // OnRenderImage src
    2. half4 rt = tex2D(_RT, uv); // your render texture
    3.  
    4. // again, we no longer care about the alpha values on output
    5. half4 out = half4(rt.rgb + main.rgb * (1 - rt.a), 1);
    6.  
    7. // alternatively you could set the alpha like this
    8. // but I can guarantee the alpha of the src won't have good values anyway
    9. // out.a = rt.a + main.a * (1 - rt.a);
    10.  
    11. return out;
     
  7. Avol

    Avol

    Joined:
    May 27, 2016
    Posts:
    46
    Yup, after close look I noticed that I'm drawing multiple lines in the same place. Was entering a stride value in instanceCount of a DrawProcedural func. Feeling very silly now :p thanks for your help.
     
unityunity