Search Unity

strange management of Specular

Discussion in 'Shaders' started by ghiboz, Aug 22, 2016.

  1. ghiboz

    ghiboz

    Joined:
    Sep 7, 2012
    Posts:
    465
    hello everyone!
    i'm building my own shader derived from the standard specular shader and I've got this issue:

    this is my albedo:

    this is the alpha channel of albedo:

    and this is the result using a specular reflectivity color of 109 109 109:
    Code (csharp):
    1. o.Specular = _SpecColor.rgb;

    now, I've got to hack this thing and use directly a float value as specular reflectivity:
    Code (csharp):
    1. o.Specular = fixed3(0.427, 0.427, 0.427);
    and I obtain this:

    that's wrong, to have the same image I need to use this value:
    Code (csharp):
    1. o.Specular = fixed3(0.2, 0.2, 0.2);
    that's the 51 51 51 rgb color...
    why this? where I'm wrong?

    I'm on Deferred/Linear on unity 5.4.0p2

    thanks for your patience
     
  2. michal_gjk

    michal_gjk

    Joined:
    Aug 13, 2016
    Posts:
    69
    First of all you should provide the source code otherwise there's too much guess work as to what you're actually trying to do.

    Standard shader (specular) derives reflectivity from the specular color. reflectivity of a given fragment = max(max(SpecularColor.r, SpecularColor.g), SpecularColor.b). (or simply SpecularColor.r on SM2).

    On the other hand the half3(0.22, 0.22, 0.22) color does play a role but in the Metallic workflow not the Specular one. Either you confused the two somehow or you didn't express clearly enough what you want to achieve.
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    This is actually a very straight forward issue.

    Specular color normally comes from an sRGB texture, so 109, 109, 109 is actually a value of 0.1529, 0.1529, 0.1529 in the shader when using linear color space rendering.

    The conversion formula for going from the 0-255 value to the linear value (and back) is here: https://en.wikipedia.org/wiki/SRGB

    However you can get a very close approximation by doing: (color value/255)^2.2 which in the case of 109 gives (109/255)^2.2 = 0.1542

    Inversely a value of 0.427 in the shader is 174/255 in sRGB "gamma space".
     
  4. marcatore

    marcatore

    Joined:
    May 22, 2015
    Posts:
    160
    ghiboz, I've tested something similar to your needs using alpha as a trasparent mask for shadowing.
    This is my results


    It's clear that alpha is not affected by the "bypass sRGB sampling"..but what it's not clear also for me and I'd like to know is...
    ... in the alpha channel world...if I'd like to set a mid-grey that influence something for half of the channel...what color should I use? Alpha channel is not in linear mode? If it's gamma corrected, why the "bypass sRGB sampling" works only for the RGB channel?

    I come from the Not RealTime Renderer and there all maps related to shading operations (like normal maps, alpha, bumps, displacement, etc...) must be in linear mode and there are controls to force the linearity when using this kind of mapping...where am I wrong with Unity?

    I've prepared a scene to better understand what I did... TestGamma

    thank in advance!
     
  5. ghiboz

    ghiboz

    Joined:
    Sep 7, 2012
    Posts:
    465
    thanks for all your replies.

    here is my shader:
    Code (CSharp):
    1. Shader "ghiboz/specular v1"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex("Albedo", 2D) = "white" {}
    6.         _NormalMap("NormalMap", 2D) = "bump" {}
    7.  
    8.         _SpecColor("Specular", Color) = (0.21569, 0.21569, 0.21569)
    9.     }
    10.  
    11.     // SM3+
    12.     SubShader
    13.     {
    14.         Tags{ "RenderType" = "Opaque" }
    15.         CGPROGRAM
    16.         #pragma surface surf StandardSpecular fullforwardshadows addshadow
    17.        
    18.         #pragma exclude_renderers gles
    19.         #pragma target 3.0
    20.  
    21.         struct Input
    22.         {
    23.             float4 color : COLOR;
    24.             float2 uv_MainTex;
    25.             float2 uv_NormalMap;
    26.             float3 viewDir;
    27.         };
    28.  
    29.         sampler2D _MainTex;
    30.         sampler2D _NormalMap;
    31.  
    32.         void surf(Input IN, inout SurfaceOutputStandardSpecular o)
    33.         {
    34.             // tex
    35.             fixed4 albedo1 = tex2D(_MainTex, IN.uv_MainTex);
    36.             fixed3 normal1 = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));
    37.  
    38.             // specular
    39.             o.Specular = _SpecColor.rgb;
    40.             //o.Specular = fixed3(0.2, 0.2, 0.2);
    41.  
    42.           o.Smoothness = albedo1.a;
    43.  
    44.             o.Normal = normal1;
    45.         }
    46.         ENDCG
    47.     }
    48.  
    49.     CustomEditor "grs_ShaderRoadGUI"
    50. }
    51.  

    @michal_gjk , here is the chart of the specular shader:
    https://blogs.unity3d.com/wp-content/uploads/2014/11/UnitySpecularChart.png
    and tell that the specular rgb defines the reflectivity of a material...
     
  6. michal_gjk

    michal_gjk

    Joined:
    Aug 13, 2016
    Posts:
    69
    I already wrote you how Speccolor relates to reflectivity in the standard spec workflow.

    You may want to look into UnityStandardUtils.cginc for details of how albedo, specular and reflectivity are calculated in both specular and metallic workflow.
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    The alpha component is always linear, and Unity sets normal maps to be linear for all channels. Modern GPUs have the option to treat just the RGB as being sRGB values (hence sRGB and not sRGBA) and will convert them from "gamma" space values to linear space automatically if the target render buffer is in linear. Otherwise in gamma space rendering it just leaves all texture values as they are and does not apply an sRGB conversion to either sRGB color channels, or linear channels.

    I believe a small group of GPUs have support for treating alpha as an sRGB channel as well, but it's not common so Unity doesn't offer support for it.
     
    Last edited: Aug 23, 2016
  8. ghiboz

    ghiboz

    Joined:
    Sep 7, 2012
    Posts:
    465
    thanks all! converting to linear with ^ 2.2 seems ok
     
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    There are actually built in functions for going from gamma to linear space and back that are still approximations but surprisingly accurate ones.

    Use GammaToLinearSpace(value) when converting a linear texture channel output into the equivalent sRGB texture output.
     
  10. ghiboz

    ghiboz

    Joined:
    Sep 7, 2012
    Posts:
    465
    thanks!!! I've seen that there's also a GammaToLinearSpaceExact for a simple float value :)
     
  11. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,900
    you have forgotten to write to o.Albedo like this:
    o.Albedo = albedo1.rgb;
    i do not know what shaderlab does with a shader that does not write to albedo...
     
  12. ghiboz

    ghiboz

    Joined:
    Sep 7, 2012
    Posts:
    465
    lol! that was a copy/paste error, 'cause the original shader was much bigger, i've extracted only the parts relative to the issue...