Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug Shader functions pow and log glitch: fragment shader output color flickers to black [deferred r.]

Discussion in 'Shaders' started by uani, Apr 4, 2021.

  1. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    Edit: see reply #9 https://forum.unity.com/threads/sha...ers-to-black-deferred-r.1087412/#post-7012687


    custom shader:

    outputColor.rgb = lerp(_Color.rgb, _LightColor.rgb, value);


    and

    outputColor.rgb = _Color.rgb + (_LightColor.rgb - _Color.rgb) * value;


    fragment output flickers between color and black over frames [deferred rendering].


    _Color is constant property, _LightColor varies over time, value is continuous from 0 to 1 over time.


    Code (CSharp):
    1. outputColor.rgb = _Color.rgb;  // constant
    2. outputColor.rgb = value;  // continous shades of grey over time
    3. outputColor.rgb = _LightColor.rgb;  // varies over time
    4. outputColor.rgb = (_LightColor.rgb - _Color.rgb) * value;  // "delta color" "modulated" as expected
    5. outputColor.rgb = _Color.rgb * value;  // even this color "modulated" continuously

    but "sum of all parts" flickers.


    Anyone an idea why this is? which?

    Hoping for a finding.

    2021.1.1
     
    Last edited: Apr 6, 2021
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    _LightColor
    isn't supposed to be valid during deferred rendering. The fact it shows something at all is kind of the bug.

    The whole idea behind deferred rendering is when you're rendering the objects themselves, you don't know anything about the lighting of the scene. Most real time games modify this a bit such that they'll know about fully baked direct / baked ambient lighting, but any real time lights the shader intentionally has no knowledge of. If something like
    _LightColor
    is still set with any value during the rendering of an object during deferred rendering it's because it wasn't unset from the previous time it was set to something. But that doesn't mean it'll be at all valid.

    Or it means the object you're rendering isn't opaque, thus its being rendered using forward rendering and not deferred.
     
  3. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    Sure? See attachment. But perhaps i forgot to include the cginc
     

    Attached Files:

  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Is the custom shader one you have directly on an object, or is it a copy of Internal-DeferredShading.shader that you're overriding in the Graphics settings. If it's on the object, then you can't rely on
    _LightColor
    . If it's an override of the internal shader, then what you have should work, though you'd need to be setting
    _Color
    as a shader global.
     
  5. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    The shader is on a material which is the single material assigned to a meshrenderer of a mesh on a GameObject

    are you implying unitys documentation is unsuited to the case the title of the category the documentation is in implies it is suited for? The shader is a vertex / fragment shader and the code is in the fragment part.

    thank you for (attempting to) help!
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    The entire premise behind deferred rendering techniques is that the lighting and the object rendering are separated into different unrelated shaders. The "lighting pass shader" mentioned in the documentation is specifically referring to the Internal-DeferredShading.shader I mentioned above. I'll agree the documentation isn't terribly clear about that.
     
  7. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    Thank you! I‘ll try various changes and report back
     
  8. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    I also replaced
    _LightDir
    ,

    the issue is caused by the
    pow
    function. I use
    pow
    to power decimal exponents for calculation of the value.
     
  9. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    pow(x, y)
    expressed as
    exp(log(x) * y)
    experiences the same issue.

    The issue is the
    log
    function.

    The
    log
    function used in a shader (conditions see original post) causes flicker.

    Btw.: the reference implementation on http://developer.download.nvidia.com/cg/pow.html is either wrong or
    pow(x,y)
    ==
    y^x


    For 0 <= x <=1 a good approximation of the Cg log function (which calculates the natural logarithm (ln) of its parameter) is:

    Code (CSharp):
    1. y = 1.5 - 2 / (x + .32);
     
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    That's the reference implementation for Cg.

    Unity doesn't use Cg, it uses HLSL. And even then, the reference implementation isn't necessarily the required implementation. The "reference" is just an "example" implementation that GPUs can implement any way they choose. HLSL doesn't even include any reference for it in their spec.

    Yes, the Unity shader code uses
    CGPROGRAM
    and there are
    .cginc
    files everywhere. But Unity delete the last uses of Cg about 5 years ago and actively stopped using Cg as the main shader language about 8 years ago when Nvidia themselves ceased development on Cg. They just never bothered to update the shader code and file extensions to reflect that fact until the Post Processing Stack and Scriptable Render Pipelines, all of which use
    HLSLPROGRAM
    and
    .hlsl
    files. But really
    CGPROGRAM
    and
    HLSLPROGRAM
    are interchangeable and both are running HLSL.
     
    Last edited: Apr 6, 2021
  11. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    Thank you for the elaboration.


    Approximating
    log(x)
    (delivering the natural logarithm of x) for x between 0 and 1:

    using a similar looking easy function (-1/x) offset in x (by c) and y (by a) and scaled (by b):

    y = a - b / (x + c)


    with y(1) = log(1) = 0:

    b = a * (1 + c)


    y becomes

    y = a * ((x - 1) / (x + c))



    Determining a and c to minimize the difference area between y and log:

    absolute of integral from 0 to 1 of (log(x) - y(x)) dx
    :

    with the help of wolframalpha.com:

    area = abs(-1 - a - a * log((c / (c + 1)) ^ (c+1)))


    liking to minimize area for a and c or simpler, try area = 0:

    a = -1 / (log((c / (c + 1)) ^ (c + 1)) + 1)


    yields

    y = -(1 / (log((c / (c + 1)) ^ (c + 1)) + 1)) * ((x - 1) / (x + c))


    c > 0 freely choosable, note log(...c...) is a pre-calculatable value


    "y and log even out between 0 and 1"

    but intersecting 1 or 2 times, parts inbetween can be large, only cancelling each other.

    Better to minimize the sum of the areas inbetween the intersections.


    Visually, used geogebra.org:

    quality | range of quality | c | a
    *** | .75 to 1.0 | .4 | 1.326
    ** | .66 to 1.0 | .39 | 1.304
    * | .5 to 1.0 | .34 | 1.193
    o | .33 to 1.0 | .28 | 1.057
    - | .25 to 1.0 | .26 | 1.011
    -- | .0 to 1.0 | .24 | 0.964
     
  12. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    to reduce the number of shader operations, using the original approximation form

    y = a - b / (x + c)


    giving
    b
    for the values in the table in my previous post row by row from *** to --:

    | b
    | 1.857
    | 1.813
    | 1.599
    | 1.353
    | 1.274
    | 1.196

    to approximate log(x), the natural logarithm of x
     
  13. uani

    uani

    Joined:
    Sep 6, 2013
    Posts:
    232
    has this been fixed? The Shader
    log
    function corrupting the shader?

    i don't have the need for it myself anymore right now but if not i like to draw Units attention to it.