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

How to customize Standard Shader using Surface Shader?

Discussion in 'Shaders' started by a_p_u_r_o, Feb 12, 2016.

  1. a_p_u_r_o

    a_p_u_r_o

    Joined:
    May 27, 2015
    Posts:
    23
    I would start by getting the source code of full featured Standard shader implemented using surface shader.
    But where is it? ... I couldn't find.
    So, I tried to forge it myself.

    As far as I could check it gives the same results as the Standard shader for Opaque and Cutout.

    For Fade and Transparent you have to switch optional parameter of the #pragma manually.
    And for these two blending modes, it seems it still gives slightly different results as Standard shader.

    Notice: Unless you constrain the usage of each features to either enable or disable,
    compilation time is very long, like 20 to 30 sec.
    May be the reason it's not have been provided by Unity is this long compilation time, I guess.

    Any comments or ideas?
     

    Attached Files:

    DouglasLee likes this.
  2. a_p_u_r_o

    a_p_u_r_o

    Joined:
    May 27, 2015
    Posts:
    23
    OK, no response so far.
    Maybe it's more useful to just post the shader code here.

    StandardSurface.shader
    Code (Shader):
    1. Shader "Standard[Surface]"
    2. {
    3.     Properties
    4.     {
    5.         _Color("Color", Color) = (1,1,1,1)
    6.         _MainTex("Albedo", 2D) = "white" {}
    7.      
    8.         _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
    9.  
    10.         _Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5
    11.         [Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0
    12.         _MetallicGlossMap("Metallic", 2D) = "white" {}
    13.  
    14.         _BumpScale("Scale", Float) = 1.0
    15.         _BumpMap("Normal Map", 2D) = "bump" {}
    16.  
    17.         _Parallax ("Height Scale", Range (0.005, 0.08)) = 0.02
    18.         _ParallaxMap ("Height Map", 2D) = "black" {}
    19.  
    20.         _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
    21.         _OcclusionMap("Occlusion", 2D) = "white" {}
    22.  
    23.         _EmissionColor("Color", Color) = (0,0,0)
    24.         _EmissionMap("Emission", 2D) = "white" {}
    25.      
    26.         _DetailMask("Detail Mask", 2D) = "white" {}
    27.  
    28.         _DetailAlbedoMap("Detail Albedo x2", 2D) = "grey" {}
    29.         _DetailNormalMapScale("Scale", Float) = 1.0
    30.         _DetailNormalMap("Normal Map", 2D) = "bump" {}
    31.  
    32.         [Enum(UV0,0,UV1,1)] _UVSec ("UV Set for secondary textures", Float) = 0
    33.  
    34.  
    35.         // Blending state
    36.         [HideInInspector] _Mode ("__mode", Float) = 0.0
    37.         [HideInInspector] _SrcBlend ("__src", Float) = 1.0
    38.         [HideInInspector] _DstBlend ("__dst", Float) = 0.0
    39.         [HideInInspector] _ZWrite ("__zw", Float) = 1.0
    40.     }
    41.  
    42. CGINCLUDE
    43.     // You may define one of these to expressly specify it.
    44.     // #define UNITY_BRDF_PBS BRDF1_Unity_PBS
    45.     // #define UNITY_BRDF_PBS BRDF2_Unity_PBS
    46.     // #define UNITY_BRDF_PBS BRDF3_Unity_PBS
    47.  
    48.     // You can reduce the time to compile by constraining the usage of eash features.
    49.     // Corresponding shader_feature pragma should be disabled.
    50.     // #define _NORMALMAP 1
    51.     // #define _ALPHATEST_ON 1
    52.     // #define _EMISSION 1
    53.     // #define _METALLICGLOSSMAP 1
    54.     // #define _DETAIL_MULX2 1
    55. ENDCG
    56.  
    57.     SubShader
    58.     {
    59.         Tags { "RenderType"="Opaque" "PerformanceChecks"="False" }
    60.         LOD 300
    61.  
    62.         // It seems Blend command is getting overridden later
    63.         // in the processing of  Surface shader.
    64.         // Blend [_SrcBlend] [_DstBlend]
    65.         ZWrite [_ZWrite]
    66.  
    67.     CGPROGRAM
    68.         #pragma target 3.0
    69.         // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
    70.         #pragma exclude_renderers gles
    71.  
    72.  
    73.         #pragma shader_feature _NORMALMAP
    74.         // #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
    75.         #pragma shader_feature _ALPHATEST_ON
    76.         #pragma shader_feature _EMISSION
    77.         #pragma shader_feature _METALLICGLOSSMAP
    78.         #pragma shader_feature ___ _DETAIL_MULX2
    79.         #pragma shader_feature _PARALLAXMAP
    80.  
    81.         // may not need these (not sure)
    82.         // #pragma multi_compile_fwdbase
    83.         // #pragma multi_compile_fog
    84.  
    85.         #pragma surface surf Standard vertex:vert finalcolor:final fullforwardshadows // Opaque or Cutout
    86.         // #pragma surface surf Standard vertex:vert finalcolor:final fullforwardshadows alpha:fade // Fade
    87.         // #pragma surface surf Standard vertex:vert finalcolor:final fullforwardshadows alpha:premul // Transparent
    88.  
    89.         #include "StandardSurface.cginc"
    90.     ENDCG
    91.  
    92.         // For some reason SHADOWCASTER works. Not ShadowCaster.
    93.         // UsePass "Standard/ShadowCaster"
    94.         UsePass "Standard/SHADOWCASTER"
    95.     }
    96.  
    97.     SubShader
    98.     {
    99.         Tags { "RenderType"="Opaque" "PerformanceChecks"="False" }
    100.         LOD 150
    101.  
    102.         // Blend [_SrcBlend] [_DstBlend]
    103.         ZWrite [_ZWrite]
    104.  
    105.     CGPROGRAM
    106.         #pragma target 2.0
    107.  
    108.         #pragma shader_feature _NORMALMAP
    109.         // #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
    110.         #pragma shader_feature _ALPHATEST_ON
    111.         #pragma shader_feature _EMISSION
    112.         #pragma shader_feature _METALLICGLOSSMAP
    113.         #pragma shader_feature ___ _DETAIL_MULX2
    114.         // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP
    115.  
    116.         #pragma skip_variants SHADOWS_SOFT DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
    117.  
    118.         // #pragma multi_compile_fwdbase
    119.         // #pragma multi_compile_fog
    120.  
    121.         #pragma surface surf Standard vertex:vert finalcolor:final // Opaque or Cutout
    122.         // #pragma surface surf Standard vertex:vert finalcolor:final alpha:fade // Fade
    123.         // #pragma surface surf Standard vertex:vert finalcolor:final alpha:premul // Transparent
    124.  
    125.         #include "StandardSurface.cginc"
    126.     ENDCG
    127.  
    128.         UsePass "Standard/SHADOWCASTER"
    129.     }
    130.  
    131.     FallBack Off
    132.     CustomEditor "StandardShaderGUI"
    133. }
    134.  
    StandardSurface.cginc
    Code (CG):
    1.  
    2. #include "UnityStandardInput.cginc"
    3.  
    4. // just for NormalizePerPixelNormal()
    5. #include "UnityStandardCore.cginc"
    6.  
    7. // LightingStandard(), LightingStandard_GI(), LightingStandard_Deferred() and
    8. // struct SurfaceOutputStandard are defined here.
    9. #include "UnityPBSLighting.cginc"
    10.  
    11. struct appdata_vert {
    12.    float4 vertex : POSITION;
    13.    half3 normal : NORMAL;
    14.    float2 uv0 : TEXCOORD0;
    15.    float2 uv1 : TEXCOORD1;
    16.    float4 texcoord1 : TEXCOORD2; // lightmaps and meta pass (not sure)
    17.    float4 texcoord2 : TEXCOORD3; // dynamig GI and meta pass (not sure)
    18. #ifdef _TANGENT_TO_WORLD
    19.    float4 tangent : TANGENT;
    20. #endif
    21. };
    22.  
    23. struct Input {
    24.    float4 texcoords;
    25. #if defined(_PARALLAXMAP)
    26.    half3 viewDirForParallax;
    27. #endif
    28. };
    29.  
    30. void vert (inout appdata_vert v, out Input o) {
    31.    UNITY_INITIALIZE_OUTPUT(Input,o);
    32.    o.texcoords.xy = TRANSFORM_TEX(v.uv0, _MainTex); // Always source from uv0
    33.    o.texcoords.zw = TRANSFORM_TEX(((_UVSec == 0) ? v.uv0 : v.uv1), _DetailAlbedoMap);
    34. #ifdef _PARALLAXMAP
    35.    TANGENT_SPACE_ROTATION; // refers to v.normal and v.tangent
    36.    o.viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex));
    37. #endif
    38. }
    39.  
    40. void surf (Input IN, inout SurfaceOutputStandard o) {
    41. #ifdef _PARALLAXMAP
    42.    half3 viewDirForParallax = NormalizePerPixelNormal(IN.viewDirForParallax);
    43. #else
    44.    half3 viewDirForParallax = half3(0,0,0);
    45. #endif
    46.    float4 texcoords = IN.texcoords;
    47.    texcoords = Parallax(texcoords, viewDirForParallax);
    48.    half alpha = Alpha(texcoords.xy);
    49. #if defined(_ALPHATEST_ON)
    50.    clip (alpha - _Cutoff);
    51. #endif
    52.    o.Albedo = Albedo(texcoords);
    53. #ifdef _NORMALMAP
    54.    o.Normal = NormalInTangentSpace(texcoords);
    55.    o.Normal = NormalizePerPixelNormal(o.Normal);
    56. #endif
    57.    o.Emission = Emission(texcoords.xy);
    58.    half2 metallicGloss = MetallicGloss(texcoords.xy);
    59.    o.Metallic = metallicGloss.x; // _Metallic;
    60.    o.Smoothness = metallicGloss.y; // _Glossiness;
    61.    o.Occlusion = Occlusion(texcoords.xy);
    62.    o.Alpha = alpha;
    63. }
    64.  
    65. void final (Input IN, SurfaceOutputStandard o, inout fixed4 color)
    66. {
    67.    color = OutputForward(color, color.a);
    68. }
    69.  
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    https://unity3d.com/get-unity/download/archive
    Downloads > Built In Shaders

    That gets you the full source, but the real standard shader does not use a surface shader, it's written as a straight vertex / fragment shader with all the bits in several cginc files.

    For a surface shader you can select the shader and click on "show generated code" if you want to see what it actually looks like. Surface shaders are just intended as short hand that's used to generate a much longer vertex fragment shader that's actually what gets used.
     
  4. a_p_u_r_o

    a_p_u_r_o

    Joined:
    May 27, 2015
    Posts:
    23
    Bgolus, thank you for your response.
    For that approach of using the provided source code of built-in shaders, we have another thread on it.
    > How to customize Standard shader?
    http://forum.unity3d.com/threads/how-to-customize-standard-shader.377065/
    It would be roughly summarized as "It's a bit fiddly but it can be done." but "Still, it's a pretty big task."

    With surface shader, I think, it's much easier to say modify the texcoords just before it's used, for example.
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    If all you want to do is modify the UVs you can do that with a surface shader using a vertex override or in the surface function itself. You can setup similar shader feature sets using a surface shader still, even with out a custom editor, using [Toggle] properties. However doing opaque, alpha test, alpha in the same shader will require a custom editor, and not using a surface shader. In that case it's easy enough just to make the 3-4 permutations you wish to use. Before the Standard shader and Unity 5.0 that's how you handled just about everything.
     
  6. mtringel

    mtringel

    Joined:
    Dec 8, 2015
    Posts:
    1
    Great work a_p_u_r_o, saved my life, thanks
     
  7. a_p_u_r_o

    a_p_u_r_o

    Joined:
    May 27, 2015
    Posts:
    23
    My pleasure!