2025-05-18 01:04:31 +08:00

206 lines
8.3 KiB
Plaintext

// ***********************************************************************
// Author : Kimch
// Created : 2018-7-1
// Description : 角色Shader
// Last Modified By : Kimch
// Last Modified On : 2019-7-1
// ***********************************************************************
// <copyright file= "MY_PBS_SkinV2" company="kk"></copyright>
// ***********************************************************************
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"
}