• 自己动手写PBR


    下面的shader参照博客修改而成:改动的地方用此颜色表示

    代码参照:

    unity build-in管线中的PBR材质Shader分析研究_郭大钦的博客-CSDN博客_shader 支持pbr材质以及cubemap  unity build-in管线中的PBR材质Shader分析研究_bulit-in pbr-CSDN博客

    最终效果如下:左边是手写的,右边是unity内置standard

    1.原shader没有阴影,根据精要我在此基础上添加了阴影.

    2.原shader由于作者追求尽量与unity内置standard效果一致,所以有些公式是按照unity独特方式写的,而且是最高质量的计算方式 ,因此有些算法还可以精简,再就是他把函数都展开写到片元着色器里面了,比较难看.有待改进.

    3.仅有不透明物体的计算方式.

    4.金属度,粗糙度只有数值调节,没有贴图控制.待完善.

    1. Shader "Custom/myPBR"
    2. {
    3. Properties
    4. {
    5. _Tint("Tint",Color)=(1,1,1,1)
    6. _MainTex ("Texture", 2D) = "white" {}
    7. //金属度要经过gama,否则即便是linear空间下渲染,unity也不会对一个滑条做操作的
    8. [Gamma]_Metallic("Metallic",Range(0,1))=0
    9. _MetallicGlossMap("Metallic", 2D) = "white" {}
    10. _Smoothness("Smoothness(Metallic.a)",Range(0,1))=0.5
    11. _BumpMap("Normal Map", 2D) = "bump" {}
    12. _Parallax ("Height Scale", Range (0.00, 0.08)) = 0.0
    13. _ParallaxMap ("Height Map", 2D) = "black" {}
    14. _OcclusionMap("Occlusion", 2D) = "white" {}
    15. }
    16. SubShader
    17. {
    18. Pass
    19. {
    20. Tags{"LightMode"="ForwardBase"}
    21. CGPROGRAM
    22. // 加上下面这行
    23. #pragma multi_compile_fwdbase
    24. #pragma vertex vert
    25. #pragma fragment frag
    26. //添加lightmap支持
    27. #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
    28. #include "UnityStandardBRDF.cginc"
    29. // 加上下面这行,不然没有阴影
    30. #include "AutoLight.cginc"
    31. struct appdata
    32. {
    33. float4 vertex : POSITION;
    34. float3 normal:NORMAL;
    35. float2 uv : TEXCOORD0;
    36. float2 uv1:TEXCOORD1;
    37. fixed4 tangent : TANGENT;
    38. };
    39. struct v2f
    40. {
    41. float2 uv : TEXCOORD0;
    42. #ifndef LIGHTMAP_OFF
    43. half2 uv1:TEXCOORD1;
    44. #endif
    45. //float4 vertex : SV_POSITION;
    46. float4 pos : SV_POSITION;//修改为pos
    47. float3 normal:TEXCOORD2;
    48. float3 worldPos:TEXCOORD3;
    49. float4 tangent:TEXCOORD4;
    50. float3x3 tangentToWorld : TEXCOORD5;
    51. float3 viewDir:COLOR1;
    52. float3x3 tangentMatrix: TEXCOORD8;
    53. float3 objectspaceViewdir:COLOR2;
    54. SHADOW_COORDS(11)//三剑客1. 注意括号里面的数字(11)========================================================================================
    55. };
    56. sampler2D _MainTex;
    57. float4 _Tint;
    58. float _Metallic;
    59. float _Smoothness;
    60. float4 _MainTex_ST;
    61. sampler2D _MetallicGlossMap;
    62. sampler2D _BumpMap;
    63. sampler2D _OcclusionMap;
    64. float _Parallax;
    65. sampler2D _ParallaxMap;
    66. inline half OneMinusReflectivityFromMetallic(half metallic)
    67. {
    68. // We'll need oneMinusReflectivity, so
    69. // 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)
    70. // store (1-dielectricSpec) in unity_ColorSpaceDielectricSpec.a, then
    71. // 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
    72. // = alpha - metallic * alpha
    73. half oneMinusDielectricSpec = unity_ColorSpaceDielectricSpec.a;
    74. return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
    75. }
    76. inline half3 DiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
    77. {
    78. specColor = lerp (unity_ColorSpaceDielectricSpec.rgb, albedo, metallic);
    79. oneMinusReflectivity = OneMinusReflectivityFromMetallic(metallic);
    80. return albedo * oneMinusReflectivity;
    81. }
    82. v2f vert (appdata v)
    83. {
    84. v2f o;
    85. //o.vertex = UnityObjectToClipPos(v.vertex);
    86. o.pos = UnityObjectToClipPos(v.vertex);
    87. o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    88. o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    89. o.normal = UnityObjectToWorldNormal(v.normal);
    90. o.normal = normalize(o.normal);
    91. o.tangent=v.tangent;
    92. float3 normalWorld = UnityObjectToWorldNormal(v.normal);
    93. float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
    94. // 对于奇怪的负缩放,我们需要sign取反(flip the sign)
    95. half sign = tangentWorld.w * unity_WorldTransformParams.w;
    96. half3 binormal = cross(normalWorld, tangentWorld) * sign;
    97. float3x3 tangentToWorld = half3x3(tangentWorld.xyz, binormal, normalWorld);
    98. o.tangentToWorld=tangentToWorld;
    99. o.viewDir=normalize(UnityWorldSpaceViewDir(o.worldPos));
    100. //Parallax viewDir need to changed from ObjectSpace to Tangent
    101. fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(o.worldPos));
    102. fixed3 objectspaceViewdir= mul(unity_WorldToObject, worldViewDir);
    103. o.objectspaceViewdir =normalize(objectspaceViewdir);
    104. float3 objectSpaceBinormal = normalize(cross(v.normal,v.tangent.xyz) * v.tangent.w);
    105. float3x3 tangentMatrix = float3x3(v.tangent.xyz, objectSpaceBinormal, v.normal);
    106. o.tangentMatrix = tangentMatrix;
    107. #ifndef LIGHTMAP_OFF
    108. o.uv1 = v.uv1.xy*unity_LightmapST.xy + unity_LightmapST.zw;
    109. #endif
    110. TRANSFER_SHADOW(o);//三剑客2================================================================================================================
    111. //重点!! 由于计算阴影的这些宏会使用上下文的变量进行相关的计算!!!!
    112. //这里的TRANSFER_SHADOW就会使用到 v.vertex或a.pos来计算
    113. //因此必须保证自定义的变量名和这些宏使用的变量名相匹配!!!!!!!
    114. //SO! appdata结构中的顶点坐标必须是 vertex !
    115. //顶点着色器的输出结构体 v2f 必须命名为 v !
    116. //v2f中顶点位置必须是pos !
    117. //否则会出现以下报错
    118. //invalid subscript 'pos' 'ComputeScreenPos': no matching 1 parameter function
    119. return o;
    120. }
    121. fixed4 frag (v2f i) : SV_Target
    122. {
    123. #ifndef LIGHTMAP_OFF
    124. fixed3 lm = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap,i.uv1));
    125. float3 albedo = _Tint*tex2D(_MainTex,i.uv);
    126. float3 finalRes = albedo * lm;
    127. return float4( finalRes,1);
    128. #endif
    129. half height = tex2D(_ParallaxMap, i.uv).g;
    130. float3 tangentspaceViewDir =normalize( mul(i.tangentMatrix, i.objectspaceViewdir));
    131. i.uv += ParallaxOffset(height,_Parallax,tangentspaceViewDir);
    132. _Metallic=tex2D(_MetallicGlossMap,i.uv).r*_Metallic;
    133. _Smoothness=tex2D(_MetallicGlossMap,i.uv).a*_Smoothness;
    134. float occlusion=tex2D(_OcclusionMap,i.uv).r;
    135. float3 normal = normalize(i.normal);//没有加normalize操作,导致其还是取的顶点法线,没有进行插值
    136. // #ifdef _NORMALMAP
    137. half3 tangent1 = i.tangentToWorld[0].xyz;
    138. half3 binormal1 = i.tangentToWorld[1].xyz;
    139. half3 normal1 = i.tangentToWorld[2].xyz;
    140. float3 normalTangent =UnpackNormal(tex2D(_BumpMap,i.uv));
    141. //return float4(1,0,0,1);
    142. // normal= normalize(float3(dot(i.TtoW0.xyz, normalTangent), dot(i.TtoW1.xyz, normalTangent), dot(i.TtoW2.xyz, normalTangent)));//矩阵变换
    143. normal=normalize((float3)(tangent1 * normalTangent.x + binormal1 * normalTangent.y + normal1 * normalTangent.z));
    144. // #endif
    145. float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
    146. //float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
    147. // float3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
    148. float3 viewDir=i.viewDir;
    149. float3 lightColor = _LightColor0.rgb;
    150. float3 halfVector = normalize(lightDir + viewDir);
    151. //roughness相关
    152. float perceptualRoughness = 1 - _Smoothness;
    153. float roughness = perceptualRoughness * perceptualRoughness;
    154. roughness=max(roughness,0.002);//即便smoothness为1,也要有点高光在
    155. float squareRoughness = roughness * roughness;
    156. float nl = max(saturate(dot(normal , lightDir ) ) , 0.0000001);//防止除0
    157. float nv = max(saturate(dot(normal, viewDir)), 0.0000001);
    158. float vh = max(saturate(dot(viewDir, halfVector)), 0.0000001);
    159. float lh = max(saturate(dot(lightDir, halfVector)), 0.0000001);
    160. float nh = max(saturate(dot(normal, halfVector)), 0.0000001);
    161. //1.1直接光漫反射部分.兰伯特光照。没有除以π,是因为会显得太暗。
    162. float3 Albedo = _Tint*tex2D(_MainTex,i.uv);
    163. //float3 rawDiffColor = DisneyDiffuse(nv,nl,lh,perceptualRoughness)*nl*lightColor;
    164. float3 rawDiffColor = nl*lightColor;//去掉了影响不大的"高级运算"
    165. //1.2.直接光镜面反射部分
    166. // 1.2.1 D项(GGX)
    167. float D=GGXTerm(nh,roughness);
    168. // 1.2.2 G项 几何函数,遮蔽变暗一些
    169. // 直接光照和间接光照时的k都在逼近二分之一,只不过直接光照时这个值最小为八分之一而不是0。这是为了保证在表面绝对光滑时
    170. // 也会吸收一部分光线,毕竟完全不吸收光线的物体在现实中不存在
    171. float G=SmithJointGGXVisibilityTerm(nl,nv,roughness);
    172. //1.2.3 F项 菲涅尔反射 金属反射强边缘反射强
    173. float3 F0 = lerp(unity_ColorSpaceDielectricSpec.rgb, Albedo, _Metallic);
    174. float3 F=FresnelTerm(F0,lh);
    175. //漫反射系数kd
    176. float3 kd = OneMinusReflectivityFromMetallic(_Metallic);
    177. kd*=Albedo;
    178. float3 specular = D * G * F ;
    179. float3 specColor = specular * lightColor*nl*UNITY_PI;//直接光镜面反射部分。镜面反射的系数就是F。漫反射之前少除π了,所以为了保证漫反射和镜面反射的比例,这里还得乘一个π
    180. float3 diffColor = kd * rawDiffColor;//直接光漫反射部分。
    181. float3 directLightResult = diffColor + specColor;
    182. //至此,直接光部分结束
    183. //2.开始间接光部分:注意间接光的漫反射需要设置光照探针,间接光的镜面反射需要设置反射探针.
    184. // 2.1间接光漫反射
    185. half3 iblDiffuse = ShadeSH9(float4(normal,1));
    186. float3 iblDiffuseResult = iblDiffuse*kd;//乘间接光漫反射系数
    187. // 2.2间接光镜面反射
    188. float mip_roughness = perceptualRoughness * (1.7 - 0.7*perceptualRoughness );
    189. float3 reflectVec = reflect(-viewDir, normal);
    190. half mip = mip_roughness * UNITY_SPECCUBE_LOD_STEPS;//得出mip层级。默认UNITY_SPECCUBE_LOD_STEPS=6(定义在UnityStandardConfig.cginc)
    191. half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectVec, mip);//视线方向的反射向量,去取样,同时考虑mip层级
    192. half3 iblSpecular = DecodeHDR(rgbm, unity_SpecCube0_HDR);//使用DecodeHDR将颜色从HDR编码下解码。可以看到采样出的rgbm是一个4通道的值,
    193. half surfaceReduction=1.0/(roughness*roughness+1.0);
    194. float oneMinusReflectivity = unity_ColorSpaceDielectricSpec.a-unity_ColorSpaceDielectricSpec.a*_Metallic; //grazingTerm压暗非金属的边缘异常高亮
    195. half grazingTerm=saturate(_Smoothness+(1-oneMinusReflectivity));
    196. float3 iblSpecularResult = surfaceReduction*iblSpecular*FresnelLerp(F0,grazingTerm,nv);
    197. float3 indirectResult = (iblDiffuseResult + iblSpecularResult)*occlusion;
    198. //至此,结束间接光部分
    199. fixed shadow = SHADOW_ATTENUATION(i);//三剑客3===============================================================================================
    200. //最终加和
    201. float3 finalResult = directLightResult*shadow + indirectResult;//在直接光后面加了 *shadow
    202. return float4(finalResult,1);
    203. }
    204. ENDCG
    205. }
    206. }
    207. FallBack"Diffuse"
    208. }

    以下代码和上面完全相同,但是用红色标出了我自己添加的阴影功能,

    Shader "Custom/myPBR"
    {
        Properties
        {
            _Tint("Tint",Color)=(1,1,1,1)
            _MainTex ("Texture", 2D) = "white" {}
            //金属度要经过gama,否则即便是linear空间下渲染,unity也不会对一个滑条做操作的
            [Gamma]_Metallic("Metallic",Range(0,1))=0
            _MetallicGlossMap("Metallic", 2D) = "white" {}
            _Smoothness("Smoothness(Metallic.a)",Range(0,1))=0.5
            _BumpMap("Normal Map", 2D) = "bump" {}
            _Parallax ("Height Scale", Range (0.00, 0.08)) = 0.0
            _ParallaxMap ("Height Map", 2D) = "black" {}
            _OcclusionMap("Occlusion", 2D) = "white" {}
        }
        SubShader
        {
            Pass
            {
                Tags{"LightMode"="ForwardBase"}
                CGPROGRAM
                // 加上下面这行
                #pragma multi_compile_fwdbase
                #pragma vertex vert
                #pragma fragment frag
                //添加lightmap支持
                #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
                #include "UnityStandardBRDF.cginc"
                // 加上下面这行,不然没有阴影
                #include "AutoLight.cginc"
                struct appdata
                {
                    float4 vertex : POSITION;
                    float3 normal:NORMAL;
                    float2 uv : TEXCOORD0;
                    float2 uv1:TEXCOORD1;
                    fixed4 tangent : TANGENT;
                };
                struct v2f
                {
                    float2 uv : TEXCOORD0;
                    #ifndef LIGHTMAP_OFF
                        half2 uv1:TEXCOORD1;
                    #endif
                    //float4 vertex : SV_POSITION;
                    float4 pos : SV_POSITION;//修改为pos
                    float3 normal:TEXCOORD2;
                    float3 worldPos:TEXCOORD3;
                    float4 tangent:TEXCOORD4;
                    float3x3 tangentToWorld : TEXCOORD5;
                    float3 viewDir:COLOR1;
                    float3x3 tangentMatrix: TEXCOORD8;
                    float3 objectspaceViewdir:COLOR2;
                     SHADOW_COORDS(11)//三剑客1. 注意括号里面的数字================
                };
                sampler2D _MainTex;
                float4 _Tint;
                float _Metallic;
                float _Smoothness;
                float4 _MainTex_ST;
                sampler2D _MetallicGlossMap;
                sampler2D _BumpMap;
                sampler2D _OcclusionMap;
                float _Parallax;
                sampler2D _ParallaxMap;
                inline half OneMinusReflectivityFromMetallic(half metallic)
                {
                    // We'll need oneMinusReflectivity, so
                    //   1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) =  lerp(1-dielectricSpec, 0, metallic)
                    // store (1-dielectricSpec) in unity_ColorSpaceDielectricSpec.a, then
                    //   1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
                    //                  = alpha - metallic * alpha
                    half oneMinusDielectricSpec = unity_ColorSpaceDielectricSpec.a;
                    return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
                }
                inline half3 DiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out  half3 specColor, out half oneMinusReflectivity)
                {
                    specColor = lerp (unity_ColorSpaceDielectricSpec.rgb, albedo, metallic);
                    oneMinusReflectivity = OneMinusReflectivityFromMetallic(metallic);
                    return albedo * oneMinusReflectivity;
                }
                v2f vert (appdata v)
                {
                    v2f o;
                     //o.vertex = UnityObjectToClipPos(v.vertex);
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                    o.normal = UnityObjectToWorldNormal(v.normal);
                    o.normal = normalize(o.normal);
                    o.tangent=v.tangent;
                    float3 normalWorld =  UnityObjectToWorldNormal(v.normal);
                    float4 tangentWorld =  float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
                    // 对于奇怪的负缩放,我们需要sign取反(flip the sign)
                    half sign = tangentWorld.w *  unity_WorldTransformParams.w;
                    half3 binormal = cross(normalWorld, tangentWorld) *  sign;
                    float3x3 tangentToWorld = half3x3(tangentWorld.xyz,  binormal, normalWorld);
                    o.tangentToWorld=tangentToWorld;
                    o.viewDir=normalize(UnityWorldSpaceViewDir(o.worldPos));
                    //Parallax viewDir need to changed from ObjectSpace to  Tangent
                    fixed3 worldViewDir =  normalize(UnityWorldSpaceViewDir(o.worldPos));
                    fixed3 objectspaceViewdir= mul(unity_WorldToObject, worldViewDir);
                    o.objectspaceViewdir =normalize(objectspaceViewdir);
                    float3 objectSpaceBinormal = normalize(cross(v.normal,v.tangent.xyz)  * v.tangent.w);
                    float3x3 tangentMatrix = float3x3(v.tangent.xyz,  objectSpaceBinormal, v.normal);
                    o.tangentMatrix = tangentMatrix;
                    #ifndef LIGHTMAP_OFF
                        o.uv1 = v.uv1.xy*unity_LightmapST.xy +  unity_LightmapST.zw;
                    #endif
                     TRANSFER_SHADOW(o);//三剑客2===========================
                    //重点!! 由于计算阴影的这些宏会使用上下文的变量进行相关的计算!!!!
                    //这里的TRANSFER_SHADOW就会使用到 v.vertex或a.pos来计算
                    //因此必须保证自定义的变量名和这些宏使用的变量名相匹配!!!!!!!
                    //SO! appdata结构中的顶点坐标必须是 vertex !
                    //顶点着色器的输出结构体 v2f 必须命名为 v !
                    //v2f中顶点位置必须是pos !
                    //否则会出现以下报错
                    //invalid subscript 'pos' 'ComputeScreenPos': no  matching 1 parameter function
                    return o;
                }
                fixed4 frag (v2f i) : SV_Target
                {
                    #ifndef LIGHTMAP_OFF
                        fixed3 lm =  DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap,i.uv1));
                        float3 albedo = _Tint*tex2D(_MainTex,i.uv);
                        float3 finalRes = albedo * lm;
                        return float4( finalRes,1);
                    #endif
                    half height = tex2D(_ParallaxMap, i.uv).g;
                    float3 tangentspaceViewDir =normalize( mul(i.tangentMatrix,  i.objectspaceViewdir));
                    i.uv += ParallaxOffset(height,_Parallax,tangentspaceViewDir);
                    _Metallic=tex2D(_MetallicGlossMap,i.uv).r*_Metallic;
                    _Smoothness=tex2D(_MetallicGlossMap,i.uv).a*_Smoothness;
                    float occlusion=tex2D(_OcclusionMap,i.uv).r;
                    float3 normal = normalize(i.normal);//没有加normalize操作,导致其还是取的顶点法线,没有进行插值
                    //     #ifdef _NORMALMAP
                    half3 tangent1 = i.tangentToWorld[0].xyz;
                    half3 binormal1 = i.tangentToWorld[1].xyz;
                    half3 normal1 = i.tangentToWorld[2].xyz;
                    float3 normalTangent  =UnpackNormal(tex2D(_BumpMap,i.uv));
                    //return float4(1,0,0,1);
                    //                   normal= normalize(float3(dot(i.TtoW0.xyz,  normalTangent), dot(i.TtoW1.xyz, normalTangent), dot(i.TtoW2.xyz,  normalTangent)));//矩阵变换
                    normal=normalize((float3)(tangent1 * normalTangent.x +  binormal1 * normalTangent.y + normal1 * normalTangent.z));
                    // #endif
                    float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                    //float3 viewDir = normalize(_WorldSpaceCameraPos.xyz  - i.worldPos.xyz);
                    //            float3 viewDir =  normalize(UnityWorldSpaceViewDir(i.worldPos));
                    float3 viewDir=i.viewDir;
                    float3 lightColor = _LightColor0.rgb;
                    float3 halfVector = normalize(lightDir + viewDir);
                    //roughness相关
                    float perceptualRoughness = 1 - _Smoothness;
                    float roughness = perceptualRoughness *  perceptualRoughness;
                    roughness=max(roughness,0.002);//即便smoothness为1,也要有点高光在
                    float squareRoughness = roughness * roughness;
                    float nl = max(saturate(dot(normal , lightDir ) ) ,  0.0000001);//防止除0
                    float nv = max(saturate(dot(normal, viewDir)),  0.0000001);
                    float vh = max(saturate(dot(viewDir, halfVector)),  0.0000001);
                    float lh = max(saturate(dot(lightDir, halfVector)),  0.0000001);
                    float nh = max(saturate(dot(normal, halfVector)),  0.0000001);
                   
                    //1.1直接光漫反射部分.兰伯特光照。没有除以π,是因为会显得太暗。
                    float3 Albedo = _Tint*tex2D(_MainTex,i.uv);
                     //float3 rawDiffColor =  DisneyDiffuse(nv,nl,lh,perceptualRoughness)*nl*lightColor;
                    float3 rawDiffColor =  nl*lightColor;//去掉了影响不大的"高级运算"
                    //1.2.直接光镜面反射部分
                    // 1.2.1 D项(GGX)
                    float D=GGXTerm(nh,roughness);
                    // 1.2.2 G项 几何函数,遮蔽变暗一些
                    //      直接光照和间接光照时的k都在逼近二分之一,只不过直接光照时这个值最小为八分之一而不是0。这是为了保证在表面绝对光滑时
                    //      也会吸收一部分光线,毕竟完全不吸收光线的物体在现实中不存在
                    float G=SmithJointGGXVisibilityTerm(nl,nv,roughness);
                    //1.2.3 F项 菲涅尔反射 金属反射强边缘反射强
                    float3 F0 = lerp(unity_ColorSpaceDielectricSpec.rgb,  Albedo, _Metallic);
                    float3 F=FresnelTerm(F0,lh);
                    //漫反射系数kd
                    float3 kd =  OneMinusReflectivityFromMetallic(_Metallic);
                    kd*=Albedo;
                   
                    float3 specular = D * G * F ;
                    float3 specColor = specular *  lightColor*nl*UNITY_PI;//直接光镜面反射部分。镜面反射的系数就是F。漫反射之前少除π了,所以为了保证漫反射和镜面反射的比例,这里还得乘一个π
                    float3 diffColor = kd * rawDiffColor;//直接光漫反射部分。
                    float3 directLightResult = diffColor + specColor;
                    //至此,直接光部分结束
                   
                    //2.开始间接光部分:注意间接光的漫反射需要设置光照探针,间接光的镜面反射需要设置反射探针.
                    //     2.1间接光漫反射
                    half3 iblDiffuse = ShadeSH9(float4(normal,1));
                    float3 iblDiffuseResult = iblDiffuse*kd;//乘间接光漫反射系数
                    //     2.2间接光镜面反射
                    float mip_roughness = perceptualRoughness * (1.7 -  0.7*perceptualRoughness );
                    float3 reflectVec = reflect(-viewDir, normal);
                    half mip = mip_roughness *  UNITY_SPECCUBE_LOD_STEPS;//得出mip层级。默认UNITY_SPECCUBE_LOD_STEPS=6(定义在UnityStandardConfig.cginc)
                    half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0,  reflectVec, mip);//视线方向的反射向量,去取样,同时考虑mip层级
                    half3 iblSpecular = DecodeHDR(rgbm,  unity_SpecCube0_HDR);//使用DecodeHDR将颜色从HDR编码下解码。可以看到采样出的rgbm是一个4通道的值,
                    half surfaceReduction=1.0/(roughness*roughness+1.0);
                    float oneMinusReflectivity =  unity_ColorSpaceDielectricSpec.a-unity_ColorSpaceDielectricSpec.a*_Metallic;      //grazingTerm压暗非金属的边缘异常高亮
                    half  grazingTerm=saturate(_Smoothness+(1-oneMinusReflectivity));
                    float3 iblSpecularResult =  surfaceReduction*iblSpecular*FresnelLerp(F0,grazingTerm,nv);
                    float3 indirectResult = (iblDiffuseResult +  iblSpecularResult)*occlusion;
                    //至此,结束间接光部分
                   
                   
                     fixed shadow = SHADOW_ATTENUATION(i);//三剑客3=====================
                    //最终加和
                     float3 finalResult = directLightResult*shadow +  indirectResult;//在直接光后面加了 *shadow
                    return float4(finalResult,1);
                   
                }
                ENDCG
            }
        }
        FallBack"Diffuse"
    }
  • 相关阅读:
    【Flutter小记5】Isolate && ffi && Method Channel 使用简介与总结
    企业如何保护机密文件安全
    JSTL标签库
    C++设计模式_04_Strategy 策略模式
    66页三级医院智慧医院 信息化建设规划
    [ERROR Swap]: running with swap on is not supported. Please disable swap
    在亚马逊云科技Amazon SageMaker上部署构建聊天机器人的开源大语言模型
    js仿toDoList(待办事项)练习
    ZYNQ7020--AMP下裸机程序开发 <2>
    实践 uboot kernel编译下载
  • 原文地址:https://blog.csdn.net/qq_34593121/article/details/133814017