// *********************************************************************** // Author : Kimch // Created : 2018-7-1 // Description : 角色Shader // Last Modified By : Kimch // Last Modified On : 2019-7-1 // *********************************************************************** // // *********************************************************************** Shader "MY/PBS/Skin" { 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 // BRDF Lookup texture, light direction on x and curvature on y. _BRDFTex("BRDF Lookup (RGB)", 2D) = "gray" {} _SSSTex("Curvature(R) thickness(G)", 2D) = "gray" {} _CurvatureScale("Curvature Scale", Range(0,1)) = 1 _ThicknessScale("Subsurface Scale", Range(0,1)) = 0.5 _SubColor("Subsurface Color", Color) = (1, .4, .25, 1) _Power("Subsurface Power", Range(0,100)) = 100 _Distortion("Subsurface Distortion", Range(0,1)) = 0 } SubShader { Tags { "RenderType" = "Opaque" } LOD 200 CGINCLUDE //#include "UnityStandardBRDF.cginc" ENDCG CGPROGRAM // Physically based Standard lighting model, and enable shadows on all light types #pragma surface surf MYStandard fullforwardshadows exclude_path:deferred exclude_path:prepass nometa nolightmap nofog noambient nolppv noinstancing // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 sampler2D _MainTex; sampler2D _BRDFTex; half4 _BRDFTex_ST; sampler2D _SSSTex; half4 _SSSTex_ST; half _CurvatureScale; half _ThicknessScale; half3 _SubColor; half _Power; half _Distortion; struct Input { float2 uv_MainTex; }; half _Glossiness; half _Metallic; fixed4 _Color; struct SurfaceOutputStandard { fixed3 Albedo; // base (diffuse or specular) color float3 Normal; // tangent space normal, if written half3 Emission; half Metallic; // 0=non-metal, 1=metal // Smoothness is the user facing name, it should be perceptual smoothness but user should not have to deal with it. // Everywhere in the code you meet smoothness it is perceptual smoothness half Smoothness; // 0=rough, 1=smooth half Occlusion; // occlusion (default 1) fixed Alpha; // alpha for transparencies fixed4 sssTex; }; #define _SKIN // Skin #ifdef _SKIN inline fixed4 SKIN_BRDF_PBS(half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness, float3 normal, float3 viewDir, UnityLight light, UnityIndirect gi, half4 sssTex) { half curvature = sssTex.r*_CurvatureScale; half thickness = 1 - sssTex.g; #define OneOnLN2_x6 8.656170 half dotNL = max(0, dot(normal, light.dir)); half dotNV = max(0, dot(normal, viewDir)); // UNITY BRDF does not normalize(viewDir) ) ); half3 halfDir = normalize(light.dir + viewDir); half dotNH = max(0, dot(normal, halfDir)); half dotLH = max(0, dot(light.dir, halfDir)); // //////////////////////////////////////////////////////////// // Cook Torrrance // from The Order 1886 // http://blog.selfshadow.com/publications/s2013-shading-course/rad/s2013_pbs_rad_notes.pdf half alpha = 1 - smoothness; // alpha is roughness alpha *= alpha; half alpha2 = alpha * alpha; // Specular Normal Distribution Function: GGX Trowbridge Reitz half denominator = (dotNH * dotNH) * (alpha2 - 1.f) + 1.f; half D = alpha2 / (UNITY_PI * denominator * denominator); // Geometric Shadowing: Smith // B. Karis, http://graphicrants.blogspot.se/2013/08/specular-brdf-reference.html half G_L = dotNL + sqrt((dotNL - dotNL * alpha) * dotNL + alpha); half G_V = dotNV + sqrt((dotNV - dotNV * alpha) * dotNV + alpha); half G = 1.0 / (G_V * G_L); // Fresnel: Schlick / fast fresnel approximation half F = 1 - oneMinusReflectivity + (oneMinusReflectivity)* exp2(-OneOnLN2_x6 * dotNH); // half3 FresnelSchlickWithRoughness = s.Specular + ( max(s.Specular, oneMinusRoughness) - s.Specular) * exp2(-OneOnLN2_x6 * dotNV ); // Lazarov 2013, "Getting More Physical in Call of Duty: Black Ops II", changed by EPIC const half4 c0 = { -1, -0.0275, -0.572, 0.022 }; const half4 c1 = { 1, 0.0425, 1.04, -0.04 }; half4 r = (1 - smoothness) * c0 + c1; half a004 = min(r.x * r.x, exp2(-9.28 * dotNV)) * r.x + r.y; half2 AB = half2(-1.04, 1.04) * a004 + r.zw; half3 F_L = specColor * AB.x + AB.y; // Skin Lighting float2 brdfUV; // Half-Lambert lighting value based on blurred normals. brdfUV.x = dotNL * 0.5 + 0.5; // Curvature amount. Multiplied by light's luminosity so brighter light = more scattering. // Pleae note: gi.light.color already contains light attenuation brdfUV.y = curvature * dot(light.color, fixed3(0.22, 0.707, 0.071)); half3 brdf = tex2D(_BRDFTex, brdfUV).rgb; // Translucency // #if defined (DIRECTIONAL) && defined (LUX_DIRECTIONAL_SSS) || defined (DIRECTIONAL_COOKIE) && defined (LUX_DIRECTIONAL_SSS) || defined (POINT) && defined (LUX_POINT_SSS) || defined (POINT_COOKIE) && defined (LUX_POINT_SSS) || defined (SPOT) && defined (LUX_SPOT_SSS) float3 H = normalize(light.dir + normal * _Distortion); float transDot = pow(saturate(dot(viewDir, -H)), _Power) * thickness * _ThicknessScale; half3 lightScattering = transDot * _SubColor; // #endif // Final composition half4 c = 0; c.rgb = diffColor * light.color * lerp(dotNL.xxx, brdf, thickness) // diffuse + gi.diffuse * diffColor // #if defined (DIRECTIONAL) && defined (LUX_DIRECTIONAL_SSS) || defined (DIRECTIONAL_COOKIE) && defined (LUX_DIRECTIONAL_SSS) || defined (POINT) && defined (LUX_POINT_SSS) || defined (POINT_COOKIE) && defined (LUX_POINT_SSS) || defined (SPOT) && defined (LUX_SPOT_SSS) + lightScattering // #endif // translucency + D * G * F * light.color * dotNL // direct specular + gi.specular * F_L; // * FresnelSchlickWithRoughness; // indirect specular return c; } #endif inline half4 LightingMYStandard(SurfaceOutputStandard s, float3 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 = SKIN_BRDF_PBS(s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect, s.sssTex); c.a = outputAlpha; return c; } inline void LightingMYStandard_GI( SurfaceOutputStandard s, UnityGIInput data, inout UnityGI gi) { #if defined(UNITY_PASS_DEFERRED) && UNITY_ENABLE_REFLECTION_BUFFERS gi = UnityGlobalIllumination(data, s.Occlusion, s.Normal); #else Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup(s.Smoothness, data.worldViewDir, s.Normal, lerp(unity_ColorSpaceDielectricSpec.rgb, s.Albedo, s.Metallic)); gi = UnityGlobalIllumination(data, s.Occlusion, s.Normal, g); #endif } 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; half4 sssTex = tex2D(_SSSTex, TRANSFORM_TEX(IN.uv_MainTex, _SSSTex)); o.sssTex = sssTex; } ENDCG } FallBack "Diffuse" }