// *********************************************************************** // Author : Kimch // Created : 2018-7-1 // Description : 角色Shader // Last Modified By : Kimch // Last Modified On : 2019-7-1 // *********************************************************************** // // *********************************************************************** Shader "MY/PBS/PlayerV1" { 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 _FabricScatterColor("Fabric Scatter Color", Color) = (1,1,1,1) _FabricScatterScale("Fabric Scatter Scale", 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 Standard1 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; half3 _FabricScatterColor; half _FabricScatterScale; 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 }; // Default BRDF to use: //#if !defined (UNITY_BRDF_PBS) // allow to explicitly override BRDF in custom shader // // still add safe net for low shader models, otherwise we might end up with shaders failing to compile //#if SHADER_TARGET < 30 || defined(SHADER_TARGET_SURFACE_ANALYSIS) // only need "something" for surface shader analysis pass; pick the cheap one //#define UNITY_BRDF_PBS BRDF3_Unity_PBS //#elif defined(UNITY_PBS_USE_BRDF3) //#define UNITY_BRDF_PBS BRDF3_Unity_PBS //#elif defined(UNITY_PBS_USE_BRDF2) //#define UNITY_BRDF_PBS BRDF2_Unity_PBS //#elif defined(UNITY_PBS_USE_BRDF1) //#define UNITY_BRDF_PBS BRDF1_Unity_PBS //#else //#error something broke in auto-choosing BRDF //#endif //#endif #define _FABRIC // 面料 inline float FabricD(float NdotH, float roughness) { return 0.96 * pow(1 - NdotH, 2) + 0.057; } inline half FabricScatterFresnelLerp(half nv, half scale) { half t0 = Pow4(1 - nv); half t1 = 0.4 * (1 - nv); return (t1 - t0) * scale + t0; } #ifdef _FABRIC half4 FABRIC_BRDF_PBS(half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness, float3 normal, float3 viewDir, UnityLight light, UnityIndirect gi) { float perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); float3 halfDir = Unity_SafeNormalize(float3(light.dir) + viewDir); // NdotV should not be negative for visible pixels, but it can happen due to perspective projection and normal mapping // In this case normal should be modified to become valid (i.e facing camera) and not cause weird artifacts. // but this operation adds few ALU and users may not want it. Alternative is to simply take the abs of NdotV (less correct but works too). // Following define allow to control this. Set it to 0 if ALU is critical on your platform. // This correction is interesting for GGX with SmithJoint visibility function because artifacts are more visible in this case due to highlight edge of rough surface // Edit: Disable this code by default for now as it is not compatible with two sided lighting used in SpeedTree. #define UNITY_HANDLE_CORRECTLY_NEGATIVE_NDOTV 0 #if UNITY_HANDLE_CORRECTLY_NEGATIVE_NDOTV // The amount we shift the normal toward the view vector is defined by the dot product. half shiftAmount = dot(normal, viewDir); normal = shiftAmount < 0.0f ? normal + viewDir * (-shiftAmount + 1e-5f) : normal; // A re-normalization should be applied here but as the shift is small we don't do it to save ALU. //normal = normalize(normal); half nv = saturate(dot(normal, viewDir)); // TODO: this saturate should no be necessary here #else half nv = abs(dot(normal, viewDir)); // This abs allow to limit artifact #endif half nl = saturate(dot(normal, light.dir)); float nh = saturate(dot(normal, halfDir)); half lv = saturate(dot(light.dir, viewDir)); half lh = saturate(dot(light.dir, halfDir)); // Diffuse term half diffuseTerm = DisneyDiffuse(nv, nl, lh, perceptualRoughness) * nl; // Specular term // HACK: theoretically we should divide diffuseTerm by Pi and not multiply specularTerm! // BUT 1) that will make shader look significantly darker than Legacy ones // and 2) on engine side "Non-important" lights have to be divided by Pi too in cases when they are injected into ambient SH float roughness = PerceptualRoughnessToRoughness(perceptualRoughness); roughness = max(roughness, 0.002); half V = SmithJointGGXVisibilityTerm(nl, nv, roughness); float D = GGXTerm(nh, roughness); float VxD = roughness > 0.99 ? 1 * FabricD(nh, roughness) : V * D; half specularTerm = VxD * UNITY_PI; // Torrance-Sparrow model, Fresnel is applied later #ifdef UNITY_COLORSPACE_GAMMA specularTerm = sqrt(max(1e-4h, specularTerm)); #endif //specularTerm * nl can be NaN on Metal in some cases, use max() to make sure it's a sane value specularTerm = max(0, specularTerm * nl); #if defined(_SPECULARHIGHLIGHTS_OFF) specularTerm = 0.0; #endif //surfaceReduction = Int D(NdotH) * NdotH * Id(NdotL>0) dH = 1/(roughness^2+1) half surfaceReduction; #ifdef UNITY_COLORSPACE_GAMMA surfaceReduction = 1.0 - 0.28*roughness*perceptualRoughness; // 1-0.28*x^3 as approximation for (1/(x^4+1))^(1/2.2) on the domain [0;1] #else surfaceReduction = 1.0 / (roughness*roughness + 1.0); // fade \in [0.5;1] #endif // To provide true Lambert lighting, we need to be able to kill specular completely. specularTerm *= any(specColor) ? 1.0 : 0.0; half grazingTerm = saturate(smoothness + (1 - oneMinusReflectivity)); half3 color = diffColor * (gi.diffuse + light.color * diffuseTerm) + specularTerm * light.color * FresnelTerm(specColor, lh) + _FabricScatterColor * (nl*0.5 + 0.5) * FabricScatterFresnelLerp(nv, _FabricScatterScale); return half4(color, 1); } #endif inline half4 LightingStandard1(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 = FABRIC_BRDF_PBS(s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect); c.a = outputAlpha; return c; } inline void LightingStandard1_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; } ENDCG } FallBack "Diffuse" }