【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】

Unity Build-In管线的SurfaceShader剖析

  • 在Unity Build-In 管线(Universal Render Pipeline)
      • 新建一个Standard Surface Shader
        • 文件里的代码如下:
        • 选中"MyPBR.Shader",在Inspector面板,打开"Show generated code"
        • 跳转到VScode,这里有1677行代码
        • 将其复制到shader文件里。
      • PASS
        • 删除不用的pass后的大致结构
        • FallBack "Diffuse"的作用
      • 包含文件
      • 判断语句
        • 如果/是否定义了(语义)
        • 是否使用lightmaps?
        • ifdef和ifndef的条件语句的经典应用
        • high-precision高精度,half-precision半精度
      • 结构体 Struct v2f_surf
        • UNITY_POSITION(pos); = float4 pos :SV_POSITION;
        • pack0 就是_MainTex的uv
          • 在v2f_surf 里声明三个变量用于组成成切线空间下的旋转矩阵
        • 最后v2f_surf 结构的完整代码:
      • vertex顶点着色器
        • 其中appdata_full
        • 整理后的vertex——vert_surf顶点着色器如下:
      • frag_surf 片段着色器
        • 从return c;往前解析
        • UNITY_OPAQUE_ALPHA(c.a);
        • fixed4 c = LightingStandard (o, worldViewDir, gi);
      • LightingStandard (o, worldViewDir, gi)解析
        • LightingStandard 的第一个参数"o":
          • 不同平台的编译指令区分
          • 宏:UNITY_INITIALIZE_OUTPUT(type,name) 解析
          • 金属工作流下的SurfaceOutputStandard结构
          • 给SurfaceOutputStandard 结构内的参数逐一赋值
        • 最后SurfaceOutputStandard 代码和注释
        • SurfaceOutputStandard 代码的注释补充:
          • o.Normal = worldNormal;
      • UnityGI gi;
        • UnityGI结构体
        • UnityLightingCommon.cginc文件
          • UnityLight light; 直接光照包含信息
          • UnityIndirect indirect; 间接光照包含信息
    • 完整的Shader,保留原始计算和注释的代码如下:
      • 新建一个cginc 文件
    • 完整的cginc代码,代码如下:
  • 最后精简后的Shader
  • 最后精简后的cginc代码

在Unity Build-In 管线(Universal Render Pipeline)

新建一个Standard Surface Shader

【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第1张图片

  • 命名为MyPBR
  • 双击打开文件
    【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第2张图片
文件里的代码如下:
Shader "Custom/MyPBR"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

选中"MyPBR.Shader",在Inspector面板,打开"Show generated code"

【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第3张图片

跳转到VScode,这里有1677行代码

将文件 Ctrl K 再 Ctrl 0,折叠代码。
里面有Unity的部分详细注释。
【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第4张图片

将其复制到shader文件里。
  • pass 部分的LightMode 注释
  • ForwardBase pass 主要是支持最亮主平行灯的逐像素光照。
  • ForwardAdd pass 是支持其他等的逐像素光照,这个看项目需求是否需要。
  • Deferred pass 是支持延迟渲染,手机上一般很少用这种渲染pass
  • Meta 光照烘焙
  • 保留ForwardBase pass ,其他的都去除。
    // ---- forward rendering base pass:
    Pass {
      Name "FORWARD"
      Tags { "LightMode" = "ForwardBase" }
      ...
    }
    // ---- forward rendering additive lights pass:
    Pass {
      Name "FORWARD"
      Tags { "LightMode" = "ForwardAdd" }
      ...
    }
    // ---- deferred shading pass:
    Pass {
      Name "DEFERRED"
      Tags { "LightMode" = "Deferred" }
      ...
    }
    // ---- meta information extraction pass:
    Pass {
      Name "Meta"
      Tags { "LightMode" = "Meta" }
      ...
    }

PASS

删除不用的pass后的大致结构

【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第5张图片

FallBack "Diffuse"的作用
  • 是保证不同平台的兜底着色,还有就是支持阴影,如果去掉阴影可能会不显示,
  }
  //这个的作用是保证不同平台的兜底着色,还有就是支持阴影,如果去掉阴影可能会不显示,
  FallBack "Diffuse"
}

包含文件

  • 这些包含文件,内部会相互包含串联应用。
    【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第6张图片
            // #include "HLSLSupport.cginc"
            // #define UNITY_INSTANCED_LOD_FADE
            // #define UNITY_INSTANCED_SH
            // #define UNITY_INSTANCED_LIGHTMAPSTS
            // #include "UnityShaderVariables.cginc"
            // #include "UnityShaderUtilities.cginc"

判断语句

如果/是否定义了(语义)
  • #if !defined(INSTANCIN1G_ON) 表示如果没有定义GPU实例化,那么执行 #if 到 #endif 里面的计算
  • #if defined(INSTANCING_ON) 表示如果定义了GPU实例化,那么执行 #if 到 #endif 里面的计算
  • -------- variant for: when no other keywords are defined
  • #if !defined(INSTANCING_ON)
    【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第7张图片
是否使用lightmaps?
  • #ifndef LIGHTMAP_ON 表示如果没有定义LIGHTMAP_ON
  • #ifdef LIGHTMAP_ON 表示如果定义了LIGHTMAP_ON
    【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第8张图片
ifdef和ifndef的条件语句的经典应用
  • 经典应用链接
    【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第9张图片
high-precision高精度,half-precision半精度
  • 精度片段着色器寄存器
    【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第10张图片

结构体 Struct v2f_surf

UNITY_POSITION(pos); = float4 pos :SV_POSITION;
  • UNITY_POSITION(pos);float4 pos :SV_POSITION; 是一个东西;
pack0 就是_MainTex的uv
float2 pack0 : TEXCOORD0; // _MainTex  ,其中pack0 就是_MainTex的uv

【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第11张图片

在v2f_surf 里声明三个变量用于组成成切线空间下的旋转矩阵
						   float3 tSpace0:TEXCOORD3;
						   float3 tSpace1:TEXCOORD4;
						   float3 tSpace2:TEXCOORD5;
最后v2f_surf 结构的完整代码:
                        struct v2f_surf
                        {
                            // UNITY_POSITION(pos); = float4 pos :SV_POSITION;!!!!!!!!!!!!!!!!
                            float4 pos :SV_POSITION;
                            float2 pack0 : TEXCOORD0; // _MainTex  ,其中pack0 就是_MainTex的uv
                            float3 worldNormal : TEXCOORD1;
                            float3 worldPos : TEXCOORD2;
                            #if UNITY_SHOULD_SAMPLE_SH
                                half3 sh : TEXCOORD3; // SH 球谐
                            #endif
                            UNITY_FOG_COORDS(4)
                            UNITY_SHADOW_COORDS(5)
                            float3 tSpace0:TEXCOORD6;
                            float3 tSpace1:TEXCOORD7;
                            float3 tSpace2:TEXCOORD8;
                            // #if SHADER_TARGET >= 30
                            //     float4 lmap : TEXCOORD6;
                            // #endif
                            // UNITY_VERTEX_INPUT_INSTANCE_ID
                            // UNITY_VERTEX_OUTPUT_STEREO
                        };

vertex顶点着色器

      v2f_surf vert_surf (appdata_full v)
      {
        UNITY_SETUP_INSTANCE_ID(v);
        v2f_surf o;
        // UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
        // UNITY_TRANSFER_INSTANCE_ID(v,o);
        // UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
        o.pos = UnityObjectToClipPos(v.vertex);
        o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
        float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
        float3 worldNormal = UnityObjectToWorldNormal(v.normal);
        #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)
          fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
          fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
          fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
        #endif
        #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED) && !defined(UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS)
          o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
          o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
          o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
        #endif
        o.worldPos.xyz = worldPos;
        o.worldNormal = worldNormal;
        #ifdef DYNAMICLIGHTMAP_ON
          o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
        #endif
        #ifdef LIGHTMAP_ON
          o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
        #endif

        // SH/ambient and vertex lights
        #ifndef LIGHTMAP_ON
          #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
            o.sh = 0;
            // Approximated illumination from non-important point lights
            #ifdef VERTEXLIGHT_ON
              o.sh += Shade4PointLights (
              unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
              unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
              unity_4LightAtten0, worldPos, worldNormal);
            #endif
            o.sh = ShadeSHPerVertex (worldNormal, o.sh);
          #endif
        #endif // !LIGHTMAP_ON

        UNITY_TRANSFER_LIGHTING(o,v.texcoord1.xy); // pass shadow and, possibly, light cookie coordinates to pixel shader
        #ifdef FOG_COMBINED_WITH_TSPACE
          UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,o.pos); // pass fog coordinates to pixel shader
        #elif defined FOG_COMBINED_WITH_WORLD_POS
          UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,o.pos); // pass fog coordinates to pixel shader
        #else
          UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
        #endif
        return o;
      }
其中appdata_full
                v2f_surf vert_surf (appdata_full v)
                {...
                }
  • 在UnityCG.cginc中有具体的结构体数据:
				struct appdata_base
				{...
				};
				struct appdata_tan
				{...
				};
				struct appdata_full {
				    float4 vertex : POSITION;
				    float4 tangent : TANGENT;
				    float3 normal : NORMAL;
				    float4 texcoord : TEXCOORD0;
				    float4 texcoord1 : TEXCOORD1;
				    float4 texcoord2 : TEXCOORD2;
				    float4 texcoord3 : TEXCOORD3;
				    fixed4 color : COLOR;
				    UNITY_VERTEX_INPUT_INSTANCE_ID
				};

【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第12张图片

  • UNITY_SETUP_INSTANCE_ID(v);

仅当您要访问片元着色器中的实例化属性时才需要。
关于实例化的Unity官方介绍
【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第13张图片

  • UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
    v2f_surf结构体的初始化。
  • LIGHTMAP_ON——烘焙;DIRLIGHTMAP_COMBINED 方向光源
        UNITY_SETUP_INSTANCE_ID(v);
        v2f_surf o;
        // UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
        // UNITY_TRANSFER_INSTANCE_ID(v,o);
        // UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
整理后的vertex——vert_surf顶点着色器如下:
                v2f_surf vert_surf (appdata_full v)
                {
                    // UNITY_SETUP_INSTANCE_ID(v);
                    v2f_surf o;
                    // UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
                    // UNITY_TRANSFER_INSTANCE_ID(v,o);
                    // UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
                    float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                    float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                    // #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)
                    //     fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                    //     fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
                    //     fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
                    // #endif
                    // #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED) && !defined(UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS)
                        o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
                        o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
                        o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
                    // #endif
                    o.worldPos.xyz = worldPos;
                    o.worldNormal = worldNormal;
                    // // 实时GI
                    // #ifdef DYNAMICLIGHTMAP_ON
                    //     o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
                    // #endif
                    // // o.lmap.xy光照贴图的UV采样
                    // #ifdef LIGHTMAP_ON
                    //     o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
                    // #endif

                    // SH/ambient and vertex lights
                    // #ifndef LIGHTMAP_ON
                        #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
                            o.sh = 0;
                            // Approximated illumination from non-important point lights
                            #ifdef VERTEXLIGHT_ON
                                o.sh += Shade4PointLights (
                                unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
                                unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
                                unity_4LightAtten0, worldPos, worldNormal);
                            #endif
                            o.sh = ShadeSHPerVertex (worldNormal, o.sh);
                        #endif
                    // #endif // !LIGHTMAP_ON
                    // UNITY_TRANSFER_LIGHTING(o,v.texcoord1.xy); // pass shadow and, possibly, light cookie coordinates to pixel shader
                    // #ifdef FOG_COMBINED_WITH_TSPACE
                    //     UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,o.pos); // pass fog coordinates to pixel shader
                    // #elif defined (FOG_COMBINED_WITH_WORLD_POS)
                    //     UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,o.pos); // pass fog coordinates to pixel shader
                    // #else
                        UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
                    // #endif
                    return o;
                }

frag_surf 片段着色器

                fixed4 frag_surf (v2f_surf IN) : SV_Target
                {
                    UNITY_SETUP_INSTANCE_ID(IN);
                    // prepare and unpack data
                    Input surfIN;
                    #ifdef FOG_COMBINED_WITH_TSPACE
                        UNITY_EXTRACT_FOG_FROM_TSPACE(IN);
                    #elif defined (FOG_COMBINED_WITH_WORLD_POS)
                        UNITY_EXTRACT_FOG_FROM_WORLD_POS(IN);
                    #else
                        UNITY_EXTRACT_FOG(IN);
                    #endif
                    UNITY_INITIALIZE_OUTPUT(Input,surfIN);
                    surfIN.uv_MainTex.x = 1.0;
                    surfIN.uv_MainTex = IN.pack0.xy;
                    float3 worldPos = IN.worldPos.xyz;
                    #ifndef USING_DIRECTIONAL_LIGHT
                        fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
                    #else
                        fixed3 lightDir = _WorldSpaceLightPos0.xyz;
                    #endif
                    float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
                    #ifdef UNITY_COMPILER_HLSL
                        SurfaceOutputStandard o = (SurfaceOutputStandard)0;
                    #else
                        SurfaceOutputStandard o;
                    #endif
                    o.Albedo = 0.0;
                    o.Emission = 0.0;
                    o.Alpha = 0.0;
                    o.Occlusion = 1.0;
                    fixed3 normalWorldVertex = fixed3(0,0,1);
                    o.Normal = IN.worldNormal;
                    normalWorldVertex = IN.worldNormal;

                    // call surface function
                    surf (surfIN, o);

                    // compute lighting & shadowing factor
                    UNITY_LIGHT_ATTENUATION(atten, IN, worldPos)
                    fixed4 c = 0;

                    // Setup lighting environment
                    UnityGI gi;
                    UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
                    gi.indirect.diffuse = 0;
                    gi.indirect.specular = 0;
                    gi.light.color = _LightColor0.rgb;
                    gi.light.dir = lightDir;
                    // Call GI (lightmaps/SH/reflections) lighting function
                    UnityGIInput giInput;
                    UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
                    giInput.light = gi.light;
                    giInput.worldPos = worldPos;
                    giInput.worldViewDir = worldViewDir;
                    giInput.atten = atten;
                    #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                        giInput.lightmapUV = IN.lmap;
                    #else
                        giInput.lightmapUV = 0.0;
                    #endif
                    #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
                        giInput.ambient = IN.sh;
                    #else
                        giInput.ambient.rgb = 0.0;
                    #endif
                    giInput.probeHDR[0] = unity_SpecCube0_HDR;
                    giInput.probeHDR[1] = unity_SpecCube1_HDR;
                    #if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
                        giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
                    #endif
                    #ifdef UNITY_SPECCUBE_BOX_PROJECTION
                        giInput.boxMax[0] = unity_SpecCube0_BoxMax;
                        giInput.probePosition[0] = unity_SpecCube0_ProbePosition;
                        giInput.boxMax[1] = unity_SpecCube1_BoxMax;
                        giInput.boxMin[1] = unity_SpecCube1_BoxMin;
                        giInput.probePosition[1] = unity_SpecCube1_ProbePosition;
                    #endif
                    LightingStandard_GI(o, giInput, gi);

                    // realtime lighting: call lighting function
                    c += LightingStandard (o, worldViewDir, gi);
                    UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fog
                    UNITY_OPAQUE_ALPHA(c.a);
                    return c;
                }

从return c;往前解析
  • return c; 返回c。
UNITY_OPAQUE_ALPHA(c.a);
  • #define UNITY_OPAQUE_ALPHA(outputAlpha) outputAlpha = 1.0
  • Alpha值为1.0
    【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第14张图片
    另外一个:
    #if defined(_ALPHABLEND_ON) || defined(_ALPHAPREMULTIPLY_ON)
    【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第15张图片
fixed4 c = LightingStandard (o, worldViewDir, gi);
  • fixed4 c = LightingStandard (o, worldViewDir, gi); 其中的LightingStandard 再UnityPBSLighting.cginc文件内
    inline half4 LightingStandard (SurfaceOutputStandard s, half3 viewDir, UnityGI gi)
    {
        s.Normal = normalize(s.Normal);

        half oneMinusReflectivity;
        half3 specColor;
        s.Albedo = DiffuseAndSpecularFromMetallic (s.Albedo, s.Metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity);

        // shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha)
        // this is necessary to handle transparency in physically correct way - only diffuse component gets affected by alpha
        half outputAlpha;
        s.Albedo = PreMultiplyAlpha (s.Albedo, s.Alpha, oneMinusReflectivity, /*out*/ outputAlpha);

        half4 c = UNITY_BRDF_PBS (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect);
        c.a = outputAlpha;
        return c;
    }

LightingStandard (o, worldViewDir, gi)解析

LightingStandard 的第一个参数"o":

传入的第一个"o",o是片段着色段的开头部分: SurfaceOutputStandard o;
【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第16张图片

不同平台的编译指令区分
                    #ifdef UNITY_COMPILER_HLSL
                        SurfaceOutputStandard o = (SurfaceOutputStandard)0;
                    #else
                        SurfaceOutputStandard o;
                    #endif
宏:UNITY_INITIALIZE_OUTPUT(type,name) 解析
  • UNITY_INITIALIZE_OUTPUT(type,name)用于把所给结构体里的各个变量初始化为0。
  • 在HLSLSupport文件里的定义:
  • 用零值初始化任意结构。
  • 某些后端不支持(例如,基于Cg,尤其是嵌套结构)。
  • hlsl2glsl几乎会支持它,除非有数组的结构——所以也不支持。
  • hlsl2glsl:全称High Level Shader Language to OpenGL Shading Language,简写HLSL to GLSL。
// Initialize arbitrary structure with zero values.
// Not supported on some backends (e.g. Cg-based particularly with nested structs).
// hlsl2glsl would almost support it, except with structs that have arrays -- so treat as not supported there either :(
#if defined(UNITY_COMPILER_HLSL) || defined(SHADER_API_PSSL) || defined(UNITY_COMPILER_HLSLCC)
#define UNITY_INITIALIZE_OUTPUT(type,name) name = (type)0;
#else
#define UNITY_INITIALIZE_OUTPUT(type,name)
#endif
金属工作流下的SurfaceOutputStandard结构

【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第17张图片

给SurfaceOutputStandard 结构内的参数逐一赋值
  • 这里的void surf (Input IN, inout SurfaceOutputStandard o)主要作用是给SurfaceOutputStandard 结构内的参数逐一赋值。
                void surf (Input IN, inout SurfaceOutputStandard o)
                {
                    // Albedo comes from a texture tinted by color
                    fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                    o.Albedo = c.rgb;
                    // Metallic and smoothness come from slider variables
                    o.Metallic = _Metallic;
                    o.Smoothness = _Glossiness;
                    o.Alpha = c.a;
                }
最后SurfaceOutputStandard 代码和注释

【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第18张图片

SurfaceOutputStandard 代码的注释补充:
o.Normal = worldNormal;
  • appdata结构中定义NORMAL与TANGENT语义。
                struct appdata
                {
                    float4 vertex : POSITION;
                    float4 tangent : TANGENT;
                    float3 normal : NORMAL;
                    float4 texcoord : TEXCOORD0;
                    float4 texcoord1 : TEXCOORD1;
                    float4 texcoord2 : TEXCOORD2;
                    float4 texcoord3 : TEXCOORD3;
                    fixed4 color : COLOR;
                    UNITY_VERTEX_INPUT_INSTANCE_ID
                };
  • v2f_surf中新增声明
    • float3 tSpace0:TEXCOORD6;
    • float3 tSpace1:TEXCOORD7;
    • float3 tSpace2:TEXCOORD8;
    • float2 normal : TEXCOORD9; // _NormalTex
    • 用于组成切线空间下的矩阵。
                        struct v2f_surf
                        {
                            // UNITY_POSITION(pos); = float4 pos :SV_POSITION;!!!!!!!!!!!!!!!!
                            float4 pos :SV_POSITION;
                            float2 pack0 : TEXCOORD0; // _MainTex  ,其中pack0 就是_MainTex的uv
                            float3 worldNormal : TEXCOORD1;
                            float3 worldPos : TEXCOORD2;
                            #if UNITY_SHOULD_SAMPLE_SH
                                half3 sh : TEXCOORD3; // SH 球谐
                            #endif
                            UNITY_FOG_COORDS(4)
                            UNITY_SHADOW_COORDS(5)
                            float3 tSpace0:TEXCOORD6;
                            float3 tSpace1:TEXCOORD7;
                            float3 tSpace2:TEXCOORD8;
                            float2 normal : TEXCOORD9; // _NormalTex

                            // #if SHADER_TARGET >= 30
                            //     float4 lmap : TEXCOORD6;
                            // #endif
                            // UNITY_VERTEX_INPUT_INSTANCE_ID
                            // UNITY_VERTEX_OUTPUT_STEREO
                        };
  • 在顶点着色器中:
                // vertex shader
                v2f_surf vert_surf (appdata v)
                {
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                    // UNITY_SETUP_INSTANCE_ID(v);
                    v2f_surf o;
                    // UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
                    // UNITY_TRANSFER_INSTANCE_ID(v,o);
                    // UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.pack0 = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
                    o.normal = TRANSFORM_TEX(v.texcoord.zw, _NormalTex);

                    float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                    float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                    // #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)
                        fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                        fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
                        fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
                    // #endif
                    // #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED) && !defined(UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS)
                        o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
                        o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
                        o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
                    // #endif
                    o.worldPos.xyz = worldPos;
                    // o.worldNormal = worldNormal;
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                    // // 实时GI
                    // #ifdef DYNAMICLIGHTMAP_ON
                    //     o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
                    // #endif
                    // // o.lmap.xy光照贴图的UV采样
                    // #ifdef LIGHTMAP_ON
                    //     o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
                    // #endif
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                    // SH/ambient and vertex lights
                    // #ifndef LIGHTMAP_ON
                        #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
                            o.sh = 0;
                            // Approximated illumination from non-important point lights
                            #ifdef VERTEXLIGHT_ON
                                o.sh += Shade4PointLights (
                                unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
                                unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
                                unity_4LightAtten0, worldPos, worldNormal);
                            #endif
                            o.sh = ShadeSHPerVertex (worldNormal, o.sh);
                        #endif
                    // #endif // !LIGHTMAP_ON
                    // UNITY_TRANSFER_LIGHTING(o,v.texcoord1.xy); // pass shadow and, possibly, light cookie coordinates to pixel shader
                    // #ifdef FOG_COMBINED_WITH_TSPACE
                    //     UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,o.pos); // pass fog coordinates to pixel shader
                    // #elif defined (FOG_COMBINED_WITH_WORLD_POS)
                    //     UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,o.pos); // pass fog coordinates to pixel shader
                    // #else
                        UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
                    // #endif
                    return o;
                }
  • 如是在片段着色器的normal填充
                half3 normalTex = UnpackNormal(tex2D(_NormalTex,IN.normal));
                half3 worldNormal = half3(dot(IN.tSpace0,normalTex),dot(IN.tSpace1,normalTex),dot(IN.tSpace2,normalTex));
                o.Normal = worldNormal;

UnityGI gi;

                    // compute lighting & shadowing factor
                    UNITY_LIGHT_ATTENUATION(atten, IN, worldPos)

                    // Setup lighting environment
                    UnityGI gi;
                    UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
                    gi.indirect.diffuse = 0;
                    gi.indirect.specular = 0;
                    gi.light.color = _LightColor0.rgb;
                    gi.light.dir = lightDir;
                    // Call GI (lightmaps/SH/reflections) lighting function
                    UnityGIInput giInput;
                    UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
                    giInput.light = gi.light;
                    giInput.worldPos = worldPos;
                    giInput.worldViewDir = worldViewDir;
                    giInput.atten = atten;
                    #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                        giInput.lightmapUV = IN.lmap;
                    #else
                        giInput.lightmapUV = 0.0;
                    #endif
                    #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
                        giInput.ambient = IN.sh;
                    #else
                        giInput.ambient.rgb = 0.0;
                    #endif
                    giInput.probeHDR[0] = unity_SpecCube0_HDR;
                    giInput.probeHDR[1] = unity_SpecCube1_HDR;
                    #if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
                        giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
                    #endif
                    #ifdef UNITY_SPECCUBE_BOX_PROJECTION
                        giInput.boxMax[0] = unity_SpecCube0_BoxMax;
                        giInput.probePosition[0] = unity_SpecCube0_ProbePosition;
                        giInput.boxMax[1] = unity_SpecCube1_BoxMax;
                        giInput.boxMin[1] = unity_SpecCube1_BoxMin;
                        giInput.probePosition[1] = unity_SpecCube1_ProbePosition;
                    #endif
                    LightingStandard_GI(o, giInput, gi);
UnityGI结构体

【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】_第19张图片

UnityLightingCommon.cginc文件
fixed4 _LightColor0;
fixed4 _SpecColor;

struct UnityLight
{
    half3 color;
    half3 dir;
    half  ndotl; // Deprecated: Ndotl is now calculated on the fly and is no longer stored. Do not used it.
};

struct UnityIndirect
{
    half3 diffuse;
    half3 specular;
};

struct UnityGI
{
    UnityLight light;
    UnityIndirect indirect;
};

struct UnityGIInput
{
    UnityLight light; // pixel light, sent from the engine

    float3 worldPos;
    half3 worldViewDir;
    half atten;
    half3 ambient;

    // interpolated lightmap UVs are passed as full float precision data to fragment shaders
    // so lightmapUV (which is used as a tmp inside of lightmap fragment shaders) should
    // also be full float precision to avoid data loss before sampling a texture.
    float4 lightmapUV; // .xy = static lightmap UV, .zw = dynamic lightmap UV

    #if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
    float4 boxMin[2];
    #endif
    #ifdef UNITY_SPECCUBE_BOX_PROJECTION
    float4 boxMax[2];
    float4 probePosition[2];
    #endif
    // HDR cubemap properties, use to decompress HDR texture
    float4 probeHDR[2];
};

UnityLight light; 直接光照包含信息
			struct UnityLight
			{
			    half3 color;
			    half3 dir;
			    half  ndotl; // Deprecated: Ndotl is now calculated on the fly and is no longer stored. Do not used it.
			};
UnityIndirect indirect; 间接光照包含信息
			struct UnityIndirect
			{
			    half3 diffuse;
			    half3 specular;
			};

完整的Shader,保留原始计算和注释的代码如下:

// Upgrade NOTE: replaced 'defined FOG_COMBINED_WITH_WORLD_POS' with 'defined (FOG_COMBINED_WITH_WORLD_POS)'

Shader "Custom/MyPBR"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _NormalTex ("NormalTex", 2D) = "bump" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        
        // ------------------------------------------------------------
        // Surface shader code generated out of a CGPROGRAM block:
// pass 部分的LightMode 注释
//ForwardBase pass 主要是支持最亮主平行灯的逐像素光照
//ForwardAdd pass 是支持其他等的逐像素光照,这个看项目需求是否需要。
// Deferred pass 是支持延迟渲染,手机上一般很少用这种渲染pass
// Meta 光照烘焙

        // ---- forward rendering base pass:
        Pass {
            Name "FORWARD"
            Tags { "LightMode" = "ForwardBase" }

            CGPROGRAM
            // compile directives
            #pragma vertex vert_surf
            #pragma fragment frag_surf
            #pragma target 3.0
            #pragma multi_compile_instancing
            #pragma multi_compile_fog
            #pragma multi_compile_fwdbase
            // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            //这些包含文件,内部会相互包含串联应用,

            // #include "HLSLSupport.cginc"
            // #define UNITY_INSTANCED_LOD_FADE
            // #define UNITY_INSTANCED_SH
            // #define UNITY_INSTANCED_LIGHTMAPSTS
            // #include "UnityShaderVariables.cginc"
            // #include "UnityShaderUtilities.cginc"

            // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

            // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

// 是否定义了(语义)
// #if !defined(INSTANCING_ON) 表示如果没有定义,那么执行 #if 到 #endif 里面的计算
// #if defined(INSTANCING_ON) 表示如果定义了,那么执行 #if 到 #endif 里面的计算
// -------- variant for: 
// #if !defined(INSTANCING_ON)


                // Surface shader code generated based on:
                // writes to per-pixel normal: no
                // writes to emission: no
                // writes to occlusion: no
                // needs world space reflection vector: no
                // needs world space normal vector: no
                // needs screen space position: no
                // needs world space position: no
                // needs view direction: no
                // needs world space view direction: no
                // needs world space position for lighting: YES
                // needs world space view direction for lighting: YES
                // needs world space view direction for lightmaps: no
                // needs vertex color: no
                // needs VFACE: no
                // needs SV_IsFrontFace: no
                // passes tangent-to-world matrix to pixel shader: no
                // reads from normal: no
                // 1 texcoords actually used
                //   float2 _MainTex
                #include "UnityCG.cginc"
                #include "Lighting.cginc"
                #include "UnityPBSLighting.cginc"
                #include "AutoLight.cginc"

                // #define INTERNAL_DATA
                // #define WorldReflectionVector(data,normal) data.worldRefl
                // #define WorldNormalVector(data,normal) normal

                // // Original surface shader snippet:
                // #line 13 ""
                // #ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
                // #endif
                // /* UNITY: Original start of shader */
                // // Physically based Standard lighting model, and enable shadows on all light types
                // //#pragma surface surf Standard fullforwardshadows

                // // Use shader model 3.0 target, to get nicer looking lighting
                // //#pragma target 3.0

                half _Glossiness;
                half _Metallic;
                fixed4 _Color;
                sampler2D _MainTex , _NormalTex;
                float4 _MainTex_ST , _NormalTex_ST;
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//struct Input 结构 传到void surf (Input IN, ...),所以这里也可以注释掉。
                // struct Input
                // {
                //     float2 uv_MainTex;
                // };
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                // // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
                // // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
                // // //#pragma instancing_options assumeuniformscaling
                // UNITY_INSTANCING_BUFFER_START(Props)
                // // put more per-instance properties here
                // UNITY_INSTANCING_BUFFER_END(Props)
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//这里的void surf (Input IN, inout SurfaceOutputStandard o)主要作用是给SurfaceOutputStandard 结构内的参数逐一赋值。
                // void surf (Input IN, inout SurfaceOutputStandard o)
                // {
                //     // Albedo comes from a texture tinted by color
                //     fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                //     o.Albedo = c.rgb;
                //     // Metallic and smoothness come from slider variables
                //     o.Metallic = _Metallic;
                //     o.Smoothness = _Glossiness;
                //     o.Alpha = c.a;
                // }
                
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// 是否使用lightmaps?
// #ifndef LIGHTMAP_ON 表示如果没有定义LIGHTMAP_ON
// #ifdef LIGHTMAP_ON 表示如果定义了LIGHTMAP_ON
//ifdef和ifndef的条件语句的区别

                // vertex-to-fragment interpolation data
                // no lightmaps:
                // #ifndef LIGHTMAP_ON
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                    // 半精度
                    // half-precision fragment shader registers:
                    // #ifdef UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS
                    //     #define FOG_COMBINED_WITH_WORLD_POS
                    //     struct v2f_surf {
                    //         UNITY_POSITION(pos);
                    //         float2 pack0 : TEXCOORD0; // _MainTex
                    //         float3 worldNormal : TEXCOORD1;
                    //         float4 worldPos : TEXCOORD2;
                    //         #if UNITY_SHOULD_SAMPLE_SH
                    //             half3 sh : TEXCOORD3; // SH
                    //         #endif
                    //         UNITY_LIGHTING_COORDS(4,5)
                    //         #if SHADER_TARGET >= 30
                    //             float4 lmap : TEXCOORD6;
                    //         #endif
                    //         UNITY_VERTEX_INPUT_INSTANCE_ID
                    //         UNITY_VERTEX_OUTPUT_STEREO
                    //     };
                    // #endif
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
                    // 高精度
                    // high-precision fragment shader registers:
                    // #ifndef UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS
                        struct v2f_surf
                        {
                            // UNITY_POSITION(pos); = float4 pos :SV_POSITION;!!!!!!!!!!!!!!!!
                            float4 pos :SV_POSITION;
                            float2 pack0 : TEXCOORD0; // _MainTex  ,其中pack0 就是_MainTex的uv
                            float3 worldNormal : TEXCOORD1;
                            float3 worldPos : TEXCOORD2;
                            #if UNITY_SHOULD_SAMPLE_SH
                                half3 sh : TEXCOORD3; // SH 球谐
                            #endif
                            UNITY_FOG_COORDS(4)
                            UNITY_SHADOW_COORDS(5)
                            float3 tSpace0:TEXCOORD6;
                            float3 tSpace1:TEXCOORD7;
                            float3 tSpace2:TEXCOORD8;
                            float2 normal : TEXCOORD9; // _NormalTex

                            // #if SHADER_TARGET >= 30
                            //     float4 lmap : TEXCOORD6;
                            // #endif
                            // UNITY_VERTEX_INPUT_INSTANCE_ID
                            // UNITY_VERTEX_OUTPUT_STEREO
                        };
                    // #endif
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                // #endif
                // // with lightmaps:
                // #ifdef LIGHTMAP_ON
                //     // half-precision fragment shader registers:
                //     #ifdef UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS
                //         #define FOG_COMBINED_WITH_WORLD_POS
                //         struct v2f_surf {
                //             UNITY_POSITION(pos);
                //             float2 pack0 : TEXCOORD0; // _MainTex
                //             float3 worldNormal : TEXCOORD1;
                //             float4 worldPos : TEXCOORD2;
                //             float4 lmap : TEXCOORD3;
                //             UNITY_LIGHTING_COORDS(4,5)
                //             UNITY_VERTEX_INPUT_INSTANCE_ID
                //             UNITY_VERTEX_OUTPUT_STEREO
                //         };
                //     #endif
                //     // high-precision fragment shader registers:
                //     #ifndef UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS
                //         struct v2f_surf {
                //             UNITY_POSITION(pos);
                //             float2 pack0 : TEXCOORD0; // _MainTex
                //             float3 worldNormal : TEXCOORD1;
                //             float3 worldPos : TEXCOORD2;
                //             float4 lmap : TEXCOORD3;
                //             UNITY_FOG_COORDS(4)
                //             UNITY_SHADOW_COORDS(5)
                //             #ifdef DIRLIGHTMAP_COMBINED
                //                 float3 tSpace0 : TEXCOORD6;
                //                 float3 tSpace1 : TEXCOORD7;
                //                 float3 tSpace2 : TEXCOORD8;
                //             #endif
                //             UNITY_VERTEX_INPUT_INSTANCE_ID
                //             UNITY_VERTEX_OUTPUT_STEREO
                //         };
                //     #endif
                // #endif
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                struct appdata
                {
                    float4 vertex : POSITION;
                    float4 tangent : TANGENT;
                    float3 normal : NORMAL;
                    float4 texcoord : TEXCOORD0;
                    float4 texcoord1 : TEXCOORD1;
                    float4 texcoord2 : TEXCOORD2;
                    float4 texcoord3 : TEXCOORD3;
                    fixed4 color : COLOR;
                    UNITY_VERTEX_INPUT_INSTANCE_ID
                };

// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
                // vertex shader
                v2f_surf vert_surf (appdata v)
                {
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                    // UNITY_SETUP_INSTANCE_ID(v);
                    v2f_surf o;
                    // UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
                    // UNITY_TRANSFER_INSTANCE_ID(v,o);
                    // UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.pack0 = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
                    o.normal = TRANSFORM_TEX(v.texcoord.zw, _NormalTex);

                    float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                    float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                    // #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)
                        fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                        fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
                        fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
                    // #endif
                    // #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED) && !defined(UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS)
                        o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
                        o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
                        o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
                    // #endif
                    o.worldPos.xyz = worldPos;
                    // o.worldNormal = worldNormal;
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                    // // 实时GI
                    // #ifdef DYNAMICLIGHTMAP_ON
                    //     o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
                    // #endif
                    // // o.lmap.xy光照贴图的UV采样
                    // #ifdef LIGHTMAP_ON
                    //     o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
                    // #endif
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                    // SH/ambient and vertex lights
                    // #ifndef LIGHTMAP_ON
                        #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
                            o.sh = 0;
                            // Approximated illumination from non-important point lights
                            #ifdef VERTEXLIGHT_ON
                                o.sh += Shade4PointLights (
                                unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
                                unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
                                unity_4LightAtten0, worldPos, worldNormal);
                            #endif
                            o.sh = ShadeSHPerVertex (worldNormal, o.sh);
                        #endif
                    // #endif // !LIGHTMAP_ON
                    // UNITY_TRANSFER_LIGHTING(o,v.texcoord1.xy); // pass shadow and, possibly, light cookie coordinates to pixel shader
                    // #ifdef FOG_COMBINED_WITH_TSPACE
                    //     UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,o.pos); // pass fog coordinates to pixel shader
                    // #elif defined (FOG_COMBINED_WITH_WORLD_POS)
                    //     UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,o.pos); // pass fog coordinates to pixel shader
                    // #else
                        UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
                    // #endif
                    return o;
                }
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                // fragment shader
                fixed4 frag_surf (v2f_surf IN) : SV_Target
                {
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------


                    // UNITY_SETUP_INSTANCE_ID(IN);
                    // prepare and unpack data
                    // Input surfIN;
                    UNITY_EXTRACT_FOG(IN);
                    // UNITY_INITIALIZE_OUTPUT(Input,surfIN);
                    // #ifdef FOG_COMBINED_WITH_TSPACE
                    //     UNITY_EXTRACT_FOG_FROM_TSPACE(IN);
                    // #elif defined (FOG_COMBINED_WITH_WORLD_POS)
                    //     UNITY_EXTRACT_FOG_FROM_WORLD_POS(IN);
                    // #else
                    //     UNITY_EXTRACT_FOG(IN);
                    // #endif
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                    // surfIN.uv_MainTex.x = 1.0;
                    // IN.uv_MainTex = IN.pack0.xy;
                    float3 worldPos = IN.worldPos.xyz;


                    // #ifndef USING_DIRECTIONAL_LIGHT
                    //     fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
                    // #else
                    //     fixed3 lightDir = _WorldSpaceLightPos0.xyz;
                    // #endif

                    float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));

// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//将SurfaceOutputStandard的数据填充完整。
                    SurfaceOutputStandard o;
                    UNITY_INITIALIZE_OUTPUT(SurfaceOutputStandard,o);
                    // #ifdef UNITY_COMPILER_HLSL
                    //     SurfaceOutputStandard o = (SurfaceOutputStandard)0;
                    // #else
                    //     SurfaceOutputStandard o;
                    // #endif

                    fixed4 mainTex = tex2D (_MainTex, IN.pack0) * _Color;
                    o.Albedo = mainTex.rgb;

                    // Metallic and smoothness come from slider variables
                    // fixed4 metallic = tex2D (_MetallicTex, IN.uv_MainTex);//如果要用金属度贴图或者金属度遮罩,可以采样2D贴图,然后填充。
                    o.Metallic = _Metallic;      // 0=non-metal, 1=metal
                    // 平滑是面向用户的名称,它应该是感知平滑,但用户不应该处理它。
                    // 在代码的任何地方,你都会遇到平滑,这就是感知平滑。
                    o.Smoothness = _Glossiness;
                    o.Alpha = mainTex.a;
                    o.Emission = 0.0;
                    //如果有AO贴图,
                    o.Occlusion = 1.0;
                    // fixed3 normalWorldVertex = fixed3(0,0,1);
                    half3 normalTex = UnpackNormal(tex2D(_NormalTex,IN.normal));
                    half3 worldNormal = half3(dot(IN.tSpace0,normalTex),dot(IN.tSpace1,normalTex),dot(IN.tSpace2,normalTex));
                    o.Normal = worldNormal;
                    // normalWorldVertex = IN.worldNormal;
//检索 void surf (Input IN, inout SurfaceOutputStandard o),这里有注释
                    // // call surface function
                    // surf (surfIN, o);
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                    // compute lighting & shadowing factor
                    UNITY_LIGHT_ATTENUATION(atten, IN, worldPos)

                    // Setup lighting environment
                    UnityGI gi;
                    UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
                    gi.indirect.diffuse = 0;
                    gi.indirect.specular = 0;
                    gi.light.color = _LightColor0.rgb;

                    gi.light.dir = _WorldSpaceLightPos0.xyz;
                    // Call GI (lightmaps/SH/reflections) lighting function
                    UnityGIInput giInput;
                    UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
                    giInput.light = gi.light;
                    giInput.worldPos = worldPos;
                    giInput.worldViewDir = worldViewDir;
                    giInput.atten = atten;
                    #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                        giInput.lightmapUV = IN.lmap;
                    #else
                        giInput.lightmapUV = 0.0;
                    #endif
                    #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
                        giInput.ambient = IN.sh;
                    #else
                        giInput.ambient.rgb = 0.0;
                    #endif
                    giInput.probeHDR[0] = unity_SpecCube0_HDR;
                    giInput.probeHDR[1] = unity_SpecCube1_HDR;
                    #if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
                        giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
                    #endif
                    #ifdef UNITY_SPECCUBE_BOX_PROJECTION
                        giInput.boxMax[0] = unity_SpecCube0_BoxMax;
                        giInput.probePosition[0] = unity_SpecCube0_ProbePosition;
                        giInput.boxMax[1] = unity_SpecCube1_BoxMax;
                        giInput.boxMin[1] = unity_SpecCube1_BoxMin;
                        giInput.probePosition[1] = unity_SpecCube1_ProbePosition;
                    #endif
                    LightingStandard_GI(o, giInput, gi);
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
                    
//PBR的核心计算,基于物理着色,BRDF的相关计算
                    // realtime lighting: call lighting function
                    fixed4 c = LightingStandard (o, worldViewDir, gi);
                    UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fog
                    // Alpha值为1.0
                    UNITY_OPAQUE_ALPHA(c.a);
                    return c;
                }

// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            // #endif

            // // -------- variant for: INSTANCING_ON 
            // #if defined(INSTANCING_ON)
            // ...
            // #endif
            // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

            ENDCG

        }

    }
    //这个的作用是保证不同平台的兜底着色,还有就是支持阴影,如果去掉阴影可能会不显示,
    FallBack "Diffuse"
}

新建一个cginc 文件

#ifndef MYPBRCGINC_CGINC
    #define MYPBRCGINC_CGINC

#endif

完整的cginc代码,代码如下:

#ifndef MYPBRCGINC_CGINC
    #define MYPBRCGINC_CGINC
// ----------------------------------------------------------------------------
half3 Unity_GlossyEnvironment_MY (UNITY_ARGS_TEXCUBE(tex), half4 hdr, Unity_GlossyEnvironmentData glossIn)
{
    half perceptualRoughness = glossIn.roughness /* perceptualRoughness */ ;

// TODO: CAUTION: remap from Morten may work only with offline convolution, see impact with runtime convolution!
// For now disabled
#if 0
    float m = PerceptualRoughnessToRoughness(perceptualRoughness); // m is the real roughness parameter
    const float fEps = 1.192092896e-07F;        // smallest such that 1.0+FLT_EPSILON != 1.0  (+1e-4h is NOT good here. is visibly very wrong)
    float n =  (2.0/max(fEps, m*m))-2.0;        // remap to spec power. See eq. 21 in --> https://dl.dropboxusercontent.com/u/55891920/papers/mm_brdf.pdf

    n /= 4;                                     // remap from n_dot_h formulatino to n_dot_r. See section "Pre-convolved Cube Maps vs Path Tracers" --> https://s3.amazonaws.com/docs.knaldtech.com/knald/1.0.0/lys_power_drops.html

    perceptualRoughness = pow( 2/(n+2), 0.25);      // remap back to square root of real roughness (0.25 include both the sqrt root of the conversion and sqrt for going from roughness to perceptualRoughness)
#else
    // MM: came up with a surprisingly close approximation to what the #if 0'ed out code above does.
    perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness);
#endif
// #endif
// #ifndef UNITY_SPECCUBE_LOD_STEPS
// UNITY_SPECCUBE_LOD_STEPS <6
//mip 是一个非线性函数,perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness);
// perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness); 简化 x = x*(1.7 - 0.7*x) 在0-1的范围是一个上拱非线性函数
// #define UNITY_SPECCUBE_LOD_STEPS (6)
// #endif
//    perceptualRoughnessToMipmapLevel = perceptualRoughness * UNITY_SPECCUBE_LOD_STEPS;
    half mip = perceptualRoughnessToMipmapLevel(perceptualRoughness);
    half3 R = glossIn.reflUVW;
    half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(tex, R, mip);//tex2Dlod

    return DecodeHDR(rgbm, hdr);
}

// ----------------------------------------------------------------------------

//
// // ----------------------------------------------------------------------------                                              //
//     // GlossyEnvironment - Function to integrate the specular lighting with default sky or reflection probes                 //
// // ----------------------------------------------------------------------------                                              //
//     struct Unity_GlossyEnvironmentData                                                                                       //
//     {                                                                                                                        //
//         // - Deferred case have one cubemap                                                                                  //
//         // - Forward case can have two blended cubemap (unusual should be deprecated).                                       //
//         // Surface properties use for cubemap integration                                                                    //
//         half    roughness; // CAUTION: This is perceptualRoughness but because of compatibility this name can't be change :( //
//         half3   reflUVW;                                                                                                     //
//     };                                                                                                                       //
//

// 计算Gi的镜面反射
    inline half3 UnityGI_IndirectSpecular_MY(UnityGIInput data, half occlusion, Unity_GlossyEnvironmentData glossIn)
    {
        half3 specular;
//如果开启了BoxProjection
        // #ifdef UNITY_SPECCUBE_BOX_PROJECTION
        //     // we will tweak reflUVW in glossIn directly (as we pass it to Unity_GlossyEnvironment_MY twice for probe0 and probe1), so keep original to pass into BoxProjectedCubemapDirection
        //     half3 originalReflUVW = glossIn.reflUVW;
        //     glossIn.reflUVW = BoxProjectedCubemapDirection (originalReflUVW, data.worldPos, data.probePosition[0], data.boxMin[0], data.boxMax[0]);
        // #endif
//如果勾选了Standard材质面板中的禁用反射功能的情况
        #ifdef _GLOSSYREFLECTIONS_OFF
            specular = unity_IndirectSpecColor.rgb;
        #else
            half3 env0 = Unity_GlossyEnvironment_MY (UNITY_PASS_TEXCUBE(unity_SpecCube0), data.probeHDR[0], glossIn);
            #ifdef UNITY_SPECCUBE_BLENDING
                const float kBlendFactor = 0.99999;
                float blendLerp = data.boxMin[0].w;
                UNITY_BRANCH
                if (blendLerp < kBlendFactor)
                {
                    #ifdef UNITY_SPECCUBE_BOX_PROJECTION
                        glossIn.reflUVW = BoxProjectedCubemapDirection (originalReflUVW, data.worldPos, data.probePosition[1], data.boxMin[1], data.boxMax[1]);
                    #endif

                    half3 env1 = Unity_GlossyEnvironment_MY (UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1,unity_SpecCube0), data.probeHDR[1], glossIn);
                    specular = lerp(env1, env0, blendLerp);
                }
                else
                {
                    specular = env0;
                }
            #else
                specular = env0;
            #endif
        #endif

        return specular * occlusion;
    }
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    // UnityGlobalIllumination_MY 重载函数!!!!!!!!!!!!!!!!!!!!!!!!
    // inline UnityGI UnityGlobalIllumination_MY (UnityGIInput data, half occlusion, half3 normalWorld)
    // {
        //     return UnityGI_Base(data, occlusion, normalWorld);
    // }

    inline UnityGI UnityGlobalIllumination_MY (UnityGIInput data, half occlusion, half3 normalWorld, Unity_GlossyEnvironmentData glossIn)
    {
        //UnityGI_Base只计算Gi的漫反射
        UnityGI o_gi = UnityGI_Base(data, occlusion, normalWorld);
        //UnityGI_IndirectSpecular_MY计算Gi的镜面反射
        o_gi.indirect.specular = UnityGI_IndirectSpecular_MY(data, occlusion, glossIn);
        return o_gi;
    }
    // //
    // // Old UnityGlobalIllumination_MY signatures. Kept only for backward compatibility and will be removed soon
    // //

    // inline UnityGI UnityGlobalIllumination_MY (UnityGIInput data, half occlusion, half smoothness, half3 normalWorld, bool reflections)
    // {
        //     if(reflections)
        //     {
            //         Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup_MY(smoothness, data.worldViewDir, normalWorld, float3(0, 0, 0));
            //         return UnityGlobalIllumination_MY(data, occlusion, normalWorld, g);
        //     }
        //     else
        //     {
            //         return UnityGlobalIllumination_MY(data, occlusion, normalWorld);
        //     }
    // }
    // inline UnityGI UnityGlobalIllumination_MY (UnityGIInput data, half occlusion, half smoothness, half3 normalWorld)
    // {
        //     #if defined(UNITY_PASS_DEFERRED) && UNITY_ENABLE_REFLECTION_BUFFERS
        //         // No need to sample reflection probes during deferred G-buffer pass
        //         bool sampleReflections = false;
        //     #else
        //         bool sampleReflections = true;
        //     #endif
        //     return UnityGlobalIllumination_MY (data, occlusion, smoothness, normalWorld, sampleReflections);
    // }

// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//
    half SmoothnessToPerceptualRoughness(half smoothness)
    {
        return (1 - smoothness);
    }
//
    Unity_GlossyEnvironmentData UnityGlossyEnvironmentSetup_MY(half Smoothness, half3 worldViewDir, half3 Normal, half3 fresnel0)
    {
        Unity_GlossyEnvironmentData g;
        // g.roughness /* perceptualRoughness */   = (1 - smoothness);
        g.roughness /* perceptualRoughness */   = SmoothnessToPerceptualRoughness(Smoothness);
        //反射球的采样坐标
        g.reflUVW   = reflect(-worldViewDir, Normal);

        return g;
    }
// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

// ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //PBR 光照模型 GI
    inline void LightingStandard_GI_MY (SurfaceOutputStandard s,UnityGIInput data,inout UnityGI gi)
    {
        //&& 表示的是两个条件都满足,才会执行下面的计算。否则执行 #else 下面的计算。
        //UNITY_PASS_DEFERRED 是延迟渲染
        // 其中UNITY_ENABLE_REFLECTION_BUFFERS - 使用延迟着色时,以延迟方式渲染反射探测
        #if defined(UNITY_PASS_DEFERRED) && UNITY_ENABLE_REFLECTION_BUFFERS
            //UnityGlobalIllumination_MY
            gi = UnityGlobalIllumination_MY(data, s.Occlusion, s.Normal);
        #else
            Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup_MY(s.Smoothness, data.worldViewDir, s.Normal, lerp(unity_ColorSpaceDielectricSpec.rgb, s.Albedo, s.Metallic));
            // 返回gi
            gi = UnityGlobalIllumination_MY(data, s.Occlusion, s.Normal, g);
        #endif

    }

#endif

最后精简后的Shader

Shader "Custom/MyPBR"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _NormalTex ("NormalTex", 2D) = "bump" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200
        Pass {
            Name "FORWARD"
            Tags { "LightMode" = "ForwardBase" }
            CGPROGRAM
            #pragma vertex vert_surf
            #pragma fragment frag_surf
            #pragma target 3.0
            #pragma multi_compile_instancing
            #pragma multi_compile_fog
            #pragma multi_compile_fwdbase
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            #include "UnityPBSLighting.cginc"
            #include "AutoLight.cginc"
            #include "MYPBRCGINC.cginc"

            half _Glossiness;
            half _Metallic;
            fixed4 _Color;
            sampler2D _MainTex , _NormalTex;
            float4 _MainTex_ST , _NormalTex_ST;
            struct v2f_surf
            {
                float4 pos :SV_POSITION;
                float2 pack0 : TEXCOORD0;
                float3 worldNormal : TEXCOORD1;
                float3 worldPos : TEXCOORD2;
                #if UNITY_SHOULD_SAMPLE_SH
                    half3 sh : TEXCOORD3;
                #endif
                UNITY_FOG_COORDS(4)
                UNITY_SHADOW_COORDS(5)
                float3 tSpace0:TEXCOORD6;
                float3 tSpace1:TEXCOORD7;
                float3 tSpace2:TEXCOORD8;
                float2 normal : TEXCOORD9;
            };
            struct appdata
            {
                float4 vertex : POSITION;
                float4 tangent : TANGENT;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
                float4 texcoord1 : TEXCOORD1;
                float4 texcoord2 : TEXCOORD2;
                float4 texcoord3 : TEXCOORD3;
                fixed4 color : COLOR;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };
            v2f_surf vert_surf (appdata v)
            {
                v2f_surf o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.pack0 = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
                o.normal = TRANSFORM_TEX(v.texcoord.zw, _NormalTex);
                float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
                fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
                o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
                o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
                o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
                o.worldPos.xyz = worldPos;
                #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
                    o.sh = 0;
                    #ifdef VERTEXLIGHT_ON
                        o.sh += Shade4PointLights (
                        unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
                        unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
                        unity_4LightAtten0, worldPos, worldNormal);
                    #endif
                    o.sh = ShadeSHPerVertex (worldNormal, o.sh);
                #endif
                UNITY_TRANSFER_FOG(o,o.pos);
                return o;
            }
            fixed4 frag_surf (v2f_surf IN) : SV_Target
            {
                UNITY_EXTRACT_FOG(IN);
                float3 worldPos = IN.worldPos.xyz;
                float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
                SurfaceOutputStandard o;
                UNITY_INITIALIZE_OUTPUT(SurfaceOutputStandard,o);
                fixed4 mainTex = tex2D (_MainTex, IN.pack0) * _Color;
                o.Albedo = mainTex.rgb;
                o.Metallic = _Metallic;
                o.Smoothness = _Glossiness;
                o.Alpha = mainTex.a;
                o.Emission = 0.0;
                o.Occlusion = 1.0;
                half3 normalTex = UnpackNormal(tex2D(_NormalTex,IN.normal));
                half3 worldNormal = half3(dot(IN.tSpace0,normalTex),dot(IN.tSpace1,normalTex),dot(IN.tSpace2,normalTex));
                o.Normal = worldNormal;
                UNITY_LIGHT_ATTENUATION(atten, IN, worldPos)
                UnityGI gi;
                UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
                gi.indirect.diffuse = 0;
                gi.indirect.specular = 0;
                gi.light.color = _LightColor0.rgb;

                gi.light.dir = _WorldSpaceLightPos0.xyz;
                UnityGIInput giInput;
                UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
                giInput.light = gi.light;
                giInput.worldPos = worldPos;
                giInput.worldViewDir = worldViewDir;
                giInput.atten = atten;
                giInput.lightmapUV = 0.0;
                #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
                    giInput.ambient = IN.sh;
                #else
                    giInput.ambient.rgb = 0.0;
                #endif
                giInput.probeHDR[0] = unity_SpecCube0_HDR;
                LightingStandard_GI_MY(o, giInput, gi);
                fixed4 c = LightingStandard (o, worldViewDir, gi);
                UNITY_APPLY_FOG(_unity_fogCoord, c);
                UNITY_OPAQUE_ALPHA(c.a);
                return c;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

最后精简后的cginc代码

#ifndef MYPBRCGINC_CGINC
    #define MYPBRCGINC_CGINC
    half3 Unity_GlossyEnvironment_MY (UNITY_ARGS_TEXCUBE(tex), half4 hdr, Unity_GlossyEnvironmentData glossIn)
    {
        half perceptualRoughness = glossIn.roughness /* perceptualRoughness */ ;
        #if 0
            float m = PerceptualRoughnessToRoughness(perceptualRoughness); // m is the real roughness parameter
            const float fEps = 1.192092896e-07F;        // smallest such that 1.0+FLT_EPSILON != 1.0  (+1e-4h is NOT good here. is visibly very wrong)
            float n =  (2.0/max(fEps, m*m))-2.0;        // remap to spec power. See eq. 21 in --> https://dl.dropboxusercontent.com/u/55891920/papers/mm_brdf.pdf

            n /= 4;                                     // remap from n_dot_h formulatino to n_dot_r. See section "Pre-convolved Cube Maps vs Path Tracers" --> https://s3.amazonaws.com/docs.knaldtech.com/knald/1.0.0/lys_power_drops.html

            perceptualRoughness = pow( 2/(n+2), 0.25);      // remap back to square root of real roughness (0.25 include both the sqrt root of the conversion and sqrt for going from roughness to perceptualRoughness)
        #else
            perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness);
        #endif
        half mip = perceptualRoughnessToMipmapLevel(perceptualRoughness);
        half3 R = glossIn.reflUVW;
        half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(tex, R, mip);//tex2Dlod
        return DecodeHDR(rgbm, hdr);
    }
    inline half3 UnityGI_IndirectSpecular_MY(UnityGIInput data, half occlusion, Unity_GlossyEnvironmentData glossIn)
    {
        half3 specular;
        #ifdef _GLOSSYREFLECTIONS_OFF
            specular = unity_IndirectSpecColor.rgb;
        #else
            half3 env0 = Unity_GlossyEnvironment_MY (UNITY_PASS_TEXCUBE(unity_SpecCube0), data.probeHDR[0], glossIn);
            #ifdef UNITY_SPECCUBE_BLENDING
                const float kBlendFactor = 0.99999;
                float blendLerp = data.boxMin[0].w;
                UNITY_BRANCH
                if (blendLerp < kBlendFactor)
                {
                    #ifdef UNITY_SPECCUBE_BOX_PROJECTION
                        glossIn.reflUVW = BoxProjectedCubemapDirection (originalReflUVW, data.worldPos, data.probePosition[1], data.boxMin[1], data.boxMax[1]);
                    #endif

                    half3 env1 = Unity_GlossyEnvironment_MY (UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1,unity_SpecCube0), data.probeHDR[1], glossIn);
                    specular = lerp(env1, env0, blendLerp);
                }
                else
                {
                    specular = env0;
                }
            #else
                specular = env0;
            #endif
        #endif

        return specular * occlusion;
    }
    inline UnityGI UnityGlobalIllumination_MY (UnityGIInput data, half occlusion, half3 normalWorld, Unity_GlossyEnvironmentData glossIn)
    {
        UnityGI o_gi = UnityGI_Base(data, occlusion, normalWorld);
        o_gi.indirect.specular = UnityGI_IndirectSpecular_MY(data, occlusion, glossIn);
        return o_gi;
    }
    half SmoothnessToPerceptualRoughness(half smoothness)
    {
        return (1 - smoothness);
    }
    Unity_GlossyEnvironmentData UnityGlossyEnvironmentSetup_MY(half Smoothness, half3 worldViewDir, half3 Normal, half3 fresnel0)
    {
        Unity_GlossyEnvironmentData g;
        g.roughness = SmoothnessToPerceptualRoughness(Smoothness);
        g.reflUVW   = reflect(-worldViewDir, Normal);
        return g;
    }
    inline void LightingStandard_GI_MY (SurfaceOutputStandard s,UnityGIInput data,inout UnityGI gi)
    {
        #if defined(UNITY_PASS_DEFERRED) && UNITY_ENABLE_REFLECTION_BUFFERS
            gi = UnityGlobalIllumination_MY(data, s.Occlusion, s.Normal);
        #else
            Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup_MY(s.Smoothness, data.worldViewDir, s.Normal, lerp(unity_ColorSpaceDielectricSpec.rgb, s.Albedo, s.Metallic));
            gi = UnityGlobalIllumination_MY(data, s.Occlusion, s.Normal, g);
        #endif
    }
#endif

你可能感兴趣的:(Unity,Shader,ShaderLab,unity,游戏引擎,算法,着色器,经验分享)