您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

952 行
38 KiB

Shader "Character/Subsurface"
{
Properties
{
Texture_182faa0c_4b84_44f9_8526_6a2b5d1bfceb_Uniform("Albedo", 2D) = "white" {}
Color_14397097_d99f_4fb0_84c5_307d9e0d6ea9_Uniform("Color", Color) = (1,1,1,0)
Texture_fa598f24_b328_4d21_a9aa_ded3cd2600dd_Uniform("Normal", 2D) = "bump" {}
Texture_11a92303_cad4_4ed7_b9a2_01fe39187cce_Uniform("Metallic Tex", 2D) = "white" {}
Vector1_66d312ef_3451_4b07_9f27_d37785582eb7_Uniform("Metallic", Range(0, 1)) = 1
Vector1_d429c42e_84f9_4cd9_aeff_2b5531f4227d_Uniform("Smoothness", Range(0, 1)) = 1
Vector1_078dba25_d724_4a74_99fe_078c8dc7ebf6_Uniform("Anisotropy", Range(0, 1)) = 0.5
Texture_6bba204c_5a19_44ba_9609_fc2dce308020_Uniform("Thickness", 2D) = "white" {}
Color_edaba26b_8c62_4e4c_8e17_5626c4a01b5c_Uniform("Subsurface Color", Color) = (0.5808823,0.3391033,0.1195934,0)
}
SubShader
{
Tags
{
"RenderType" = "Opaque"
"Queue" = "Geometry"
}
Blend One Zero
Cull Back
ZTest LEqual
ZWrite On
LOD 200
CGPROGRAM
#include "UnityCG.cginc"
//#include "AdvancedBRDF.cginc"
//#include "AdvancedShading.cginc"
//#include "AdvancedLighting.cginc"
#define SHADINGMODELID_SUBSURFACE
// ------------------------------------------------------------------
// Diffuse
// From UE4 - Used for Cloth (Deprecated)
float3 Diffuse_Lambert(float3 DiffuseColor)
{
return DiffuseColor * (1 / UNITY_PI);
}
// ------------------------------------------------------------------
// Fresnel
// From UE4 - Used for Cloth
// [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"]
float3 F_Schlick(float3 SpecularColor, float VoH)
{
float Fc = Pow5(1 - VoH); // 1 sub, 3 mul
//return Fc + (1 - Fc) * SpecularColor; // 1 add, 3 mad
// Anything less than 2% is physically impossible and is instead considered to be shadowing
return saturate(50.0 * SpecularColor.g) * Fc + (1 - Fc) * SpecularColor;
}
// ------------------------------------------------------------------
// Distribution
// From UE4 - USed for Cloth
// GGX / Trowbridge-Reitz
// [Walter et al. 2007, "Microfacet models for refraction through rough surfaces"]
float D_GGX(float roughness, float NdotH)
{
float a = roughness * roughness;
float a2 = a * a;
float d = (NdotH * a2 - NdotH) * NdotH + 1; // 2 mad
return a2 / (UNITY_PI*d*d); // 4 mul, 1 rcp
}
// Anisotropic GGX
// Taken from HDRenderPipeline
float D_GGXAnisotropic(float TdotH, float BdotH, float NdotH, float roughnessT, float roughnessB)
{
float f = TdotH * TdotH / (roughnessT * roughnessT) + BdotH * BdotH / (roughnessB * roughnessB) + NdotH * NdotH;
return 1.0 / (roughnessT * roughnessB * f * f);
}
// From UE4 - Used for Cloth
float D_InvGGX(float roughness, float NdotH)
{
float a = roughness * roughness;
float a2 = a * a;
float A = 4;
float d = (NdotH - a2 * NdotH) * NdotH + a2;
return 1 / (UNITY_PI * (1 + A*a2)) * (1 + 4 * a2*a2 / (d*d)); //RCP
}
// ------------------------------------------------------------------
// Visibility
// From UE4 - Used for Cloth
// Appoximation of joint Smith term for GGX
// [Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs"]
float Vis_SmithJointApprox(float Roughness, float NoV, float NoL)
{
float a = (Roughness*Roughness);
float Vis_SmithV = NoL * (NoV * (1 - a) + a);
float Vis_SmithL = NoV * (NoL * (1 - a) + a);
// Note: will generate NaNs with Roughness = 0. MinRoughness is used to prevent this
return 0.5 * 1 / (Vis_SmithV + Vis_SmithL); //RCP
}
// From UE4 - Used for Cloth
float Vis_Cloth(float NoV, float NoL)
{
return 1 / (4 * (NoL + NoV - NoL * NoV)); //RCP
}
// ------------------------------------------------------------------
// SORT THESE
// Smith Joint GGX Anisotropic Visibility
// Taken from https://cedec.cesa.or.jp/2015/session/ENG/14698.html
float SmithJointGGXAnisotropic(float TdotV, float BdotV, float NdotV, float TdotL, float BdotL, float NdotL, float roughnessT, float roughnessB)
{
float aT = roughnessT;
float aT2 = aT * aT;
float aB = roughnessB;
float aB2 = aB * aB;
float lambdaV = NdotL * sqrt(aT2 * TdotV * TdotV + aB2 * BdotV * BdotV + NdotV * NdotV);
float lambdaL = NdotV * sqrt(aT2 * TdotL * TdotL + aB2 * BdotL * BdotL + NdotL * NdotL);
return 0.5 / (lambdaV + lambdaL);
}
// Convert Anistropy to roughness
void ConvertAnisotropyToRoughness(float roughness, float anisotropy, out float roughnessT, out float roughnessB)
{
// (0 <= anisotropy <= 1), therefore (0 <= anisoAspect <= 1)
// The 0.9 factor limits the aspect ratio to 10:1.
float anisoAspect = sqrt(1.0 - 0.9 * anisotropy);
roughnessT = roughness / anisoAspect; // Distort along tangent (rougher)
roughnessB = roughness * anisoAspect; // Straighten along bitangent (smoother)
}
// Schlick Fresnel
float FresnelSchlick(float f0, float f90, float u)
{
float x = 1.0 - u;
float x5 = x * x;
x5 = x5 * x5 * x;
return (f90 - f0) * x5 + f0; // sub mul mul mul sub mad
}
//Clamp roughness
float ClampRoughnessForAnalyticalLights(float roughness)
{
return max(roughness, 0.000001);
}
//Calculate tangent warp for IBL (Reference Version - not used)
float3 SpecularGGXIBLRef(float3 viewDir, float3 normalDir, float3 tangentDir, float3 bitangentDir, float roughnessT, float roughnessB)
{
return float3(1, 1, 1);
//Hidden in UnityAnisotropicLighting.cginc
}
// Sample Anisotropic Direction for IBL (Reference Version - not used)
void SampleAnisoGGXDir(float2 u, float3 viewDir, float3 normalDir, float3 tangent, float3 bitangent, float roughnessT, float roughnessB, out float3 halfDir, out float3 lightDir)
{
// AnisoGGX NDF sampling
halfDir = sqrt(u.x / (1.0 - u.x)) * (roughnessT * cos((UNITY_PI * 2) * u.y) * tangent + roughnessB * sin((UNITY_PI * 2) * u.y) * bitangent) + normalDir;
halfDir = normalize(halfDir);
// Convert sample from half angle to incident angle
lightDir = 2.0 * saturate(dot(viewDir, halfDir)) * halfDir - viewDir;
}
// Ref: Donald Revie - Implementing Fur Using Deferred Shading (GPU Pro 2)
// The grain direction (e.g. hair or brush direction) is assumed to be orthogonal to the normal.
// The returned normal is NOT normalized.
float3 ComputeGrainNormal(float3 grainDir, float3 V)
{
float3 B = cross(-V, grainDir);
return cross(B, grainDir);
}
//Modify Normal for Anisotropic IBL (Realtime version)
// Fake anisotropic by distorting the normal.
// The grain direction (e.g. hair or brush direction) is assumed to be orthogonal to N.
// Anisotropic ratio (0->no isotropic; 1->full anisotropy in tangent direction)
float3 GetAnisotropicModifiedNormal(float3 grainDir, float3 N, float3 V, float anisotropy)
{
float3 grainNormal = ComputeGrainNormal(grainDir, V);
// TODO: test whether normalizing 'grainNormal' is worth it.
return normalize(lerp(N, grainNormal, anisotropy));
}
/// REGION END - ANISOTROPY
/// REGION START - SUBSURFACE SCATTERING
half Fresnel(half3 H, half3 V, half F0)
{
half base = 1.0 - dot(V, H);
half exponential = pow(base, 5.0);
return exponential + F0 * (1.0 - exponential);
}
/*
inline half3 KelemenSzirmayKalosSpecular(half3 normal, half3 lightDir, half3 viewDir, float roughness, float rho_s)
{
half3 result = half3(0, 0, 0);
half NdotL = dot(normal, lightDir);
if (NdotL > 0.0)
{
half3 h = lightDir + viewDir;
half3 H = normalize(h);
half NdotH = dot(normal, H);
half PH = pow(2.0 * tex2D(_BeckmannPrecomputedTex, half2(NdotH, roughness)).r, 10.0);
half F = Fresnel(H, viewDir, 0.028);
half frSpec = max(PH * F / dot(h, h), 0);
half term = NdotL * rho_s * frSpec;
result = half3(term, term, term);
}
return result;
}*/
/*
half3 SkinDiffuse(float curv, float3 NdotL)
{
float3 lookup = NdotL * 0.5 + 0.5;
float3 diffuse;
diffuse.r = tex2D(_DiffusionProfileTexture, float2(lookup.r, curv)).r;
diffuse.g = tex2D(_DiffusionProfileTexture, float2(lookup.g, curv)).g;
diffuse.b = tex2D(_DiffusionProfileTexture, float2(lookup.b, curv)).b;
return diffuse;
}*/
/// REGION END - SUBSURFACE SCATTERING
// Upgrade NOTE: replaced 'defined SHADINGMODELID_CLEARCOAT' with 'defined (SHADINGMODELID_CLEARCOAT)'
// Upgrade NOTE: replaced 'defined SHADINGMODELID_CLOTH' with 'defined (SHADINGMODELID_CLOTH)'
// Upgrade NOTE: replaced 'defined SHADINGMODELID_EYE' with 'defined (SHADINGMODELID_EYE)'
// Upgrade NOTE: replaced 'defined SHADINGMODELID_FOLIAGE' with 'defined (SHADINGMODELID_FOLIAGE)'
// Upgrade NOTE: replaced 'defined SHADINGMODELID_HAIR' with 'defined (SHADINGMODELID_HAIR)'
// Upgrade NOTE: replaced 'defined SHADINGMODELID_SKIN' with 'defined (SHADINGMODELID_SKIN)'
// Upgrade NOTE: replaced 'defined SHADINGMODELID_SUBSURFACE' with 'defined (SHADINGMODELID_SUBSURFACE)'
// ------------------------------------------------------------------
// Shading models
//#pragma multi_compile SHADINGMODELID_UNLIT SHADINGMODELID_STANDARD SHADINGMODELID_SUBSURFACE SHADINGMODELID_SKIN SHADINGMODELID_FOLIAGE SHADINGMODELID_CLEARCOAT SHADINGMODELID_CLOTH SHADINGMODELID_EYE
// ------------------------------------------------------------------
// Input
half _ShadingModel;
sampler2D _AnisotropyMap;
half _Anisotropy;
sampler2D _TangentMap;
half4 _TranslucentColor;
sampler2D _TranslucencyMap;
sampler2D _FuzzTex;
half3 _FuzzColor;
half _Cloth;
sampler2D _IrisNormal;
sampler2D _IrisMask;
half _IrisDistance;
half _TDistortion;
half _TScale;
half _TAmbient;
half _TPower;
half _TAttenuation;
half _TransmissionOverallStrength;
// ------------------------------------------------------------------
// Maths helpers
// Octahedron Normal Vectors
// [Cigolle 2014, "A Survey of Efficient Representations for Independent Unit Vectors"]
// Mean Max
// oct 8:8 0.33709 0.94424
// snorm 8:8:8 0.17015 0.38588
// oct 10:10 0.08380 0.23467
// snorm 10:10:10 0.04228 0.09598
// oct 12:12 0.02091 0.05874
float2 UnitVectorToOctahedron(float3 N)
{
N.xy /= dot(float3(1,1,1), abs(N));
if (N.z <= 0)
{
N.xy = (1 - abs(N.yx)) * (N.xy >= 0 ? float2(1, 1) : float2(-1, -1));
}
return N.xy;
}
float3 OctahedronToUnitVector(float2 Oct)
{
float3 N = float3(Oct, 1 - dot(float2(1,1), abs(Oct)));
if (N.z < 0)
{
N.xy = (1 - abs(N.yx)) * (N.xy >= 0 ? float2(1, 1) : float2(-1, -1));
}
return float3(1, 1, 1);
return normalize(N);
}
// ------------------------------------------------------------------
// Surface helpers
half Anisotropy(float2 uv)
{
return tex2D(_AnisotropyMap, uv) * _Anisotropy;
}
half3 Fuzz(float2 uv)
{
return tex2D(_FuzzTex, uv) * _FuzzColor;
}
half Cloth()
{
return _Cloth;
}
half4 Iris(float2 uv)
{
float2 n = UnitVectorToOctahedron(normalize(UnpackNormal(tex2D(_IrisNormal, uv)).rgb)) * 0.5 + 0.5;
float m = saturate(tex2D(_IrisMask, uv).r); // Iris Mask
float d = saturate(_IrisDistance); // Iris Distance
return float4(n.x, n.y, m, d);
}
half3 Translucency(float2 uv)
{
return tex2D(_TranslucencyMap, uv).rgb * _TranslucentColor.rgb;
}
// ------------------------------------------------------------------
// Unlit Shading Function
float4 UnlitShading(float3 diffColor)
{
return half4(diffColor, 1);
}
// ------------------------------------------------------------------
// Standard Shading Function
float4 StandardShading(float3 diffColor, float3 specColor, float oneMinusReflectivity, float smoothness, float3 normal, float3x3 worldVectors,
float anisotropy, float metallic, float3 viewDir, UnityLight light, UnityIndirect gi)
{
//Unpack world vectors
float3 tangent = worldVectors[0];
float3 bitangent = worldVectors[1];
//Normal shift
float shiftAmount = dot(normal, viewDir);
normal = shiftAmount < 0.0f ? normal + viewDir * (-shiftAmount + 1e-5f) : normal;
//Regular vectors
float NdotL = saturate(dot(normal, light.dir)); //sat?
float NdotV = abs(dot(normal, viewDir)); //abs?
float LdotV = dot(light.dir, viewDir);
float3 H = Unity_SafeNormalize(light.dir + viewDir);
float invLenLV = rsqrt(abs(2 + 2 * normalize(LdotV)));
//float invLenLV = rsqrt(abs(2 + 2 * LdotV));
//float NdotH = (NdotL + normalize(NdotV)) * invLenLV;
float NdotH = saturate(dot(normal, H));
//float NdotH = saturate((NdotL + normalize(NdotV)) * invLenLV);
//float H = (light.dir + viewDir) * invLenLV;
float LdotH = saturate(dot(light.dir, H));
//Tangent vectors
float TdotH = dot(tangent, H);
float TdotL = dot(tangent, light.dir);
float BdotH = dot(bitangent, H);
float BdotL = dot(bitangent, light.dir);
float TdotV = dot(viewDir, tangent);
float BdotV = dot(viewDir, bitangent);
//Fresnels
half grazingTerm = saturate(smoothness + (1 - oneMinusReflectivity));
float3 F = FresnelLerp(specColor, grazingTerm, NdotV); //Original Schlick - Replace from SRP?
//float3 fresnel0 = lerp(specColor, diffColor, metallic);
//float3 F = FresnelSchlick(fresnel0, 1.0, LdotH);
//Calculate roughness
float roughnessT;
float roughnessB;
float perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness);
float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
ConvertAnisotropyToRoughness(roughness, anisotropy, roughnessT, roughnessB);
//Clamp roughness
//roughness = ClampRoughnessForAnalyticalLights(roughness);
roughnessT = ClampRoughnessForAnalyticalLights(roughnessT);
roughnessB = ClampRoughnessForAnalyticalLights(roughnessB);
//Visibility & Distribution terms
float V = SmithJointGGXAnisotropic(TdotV, BdotV, NdotV, TdotL, BdotL, NdotL, roughnessT, roughnessB);
float D = D_GGXAnisotropic(TdotH, BdotH, NdotH, roughnessT, roughnessB);
//Specular term
float3 specularTerm = V * D; //*UNITY_PI;
# 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 * NdotL);
#if defined(_SPECULARHIGHLIGHTS_OFF)
specularTerm = 0.0;
#endif
//Diffuse term
float diffuseTerm = DisneyDiffuse(NdotV, NdotL, LdotH, perceptualRoughness) * NdotL;// - Need this NdotL multiply?
//Reduction
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
//Final
half3 color = (diffColor * (gi.diffuse + light.color * diffuseTerm))
+ specularTerm * light.color * FresnelTerm(specColor, LdotH)
+ surfaceReduction * gi.specular * FresnelLerp(specColor, grazingTerm, NdotV);
return half4(color, 1);
}
// ------------------------------------------------------------------
// Cloth Shading Function
//float3 ClothShading(FGBufferData GBuffer, float3 LobeRoughness, float3 LobeEnergy, float3 L, float3 V, half3 N)
float4 ClothShading(float3 diffColor, float3 specColor, float3 fuzzColor, float cloth, float oneMinusReflectivity, float smoothness, float3 normal, float3 viewDir, UnityLight light, UnityIndirect gi, float3x3 worldVectors, float anisotropy)
{
const float3 FuzzColor = saturate(fuzzColor);
const float Cloth = saturate(cloth);
//Regular vectors
float NdotL = saturate(dot(normal, light.dir)); //sat?
float NdotV = abs(dot(normal, viewDir)); //abs?
float LdotV = dot(light.dir, viewDir);
//float invLenLV = rsqrt(abs(2 + 2 * normalize(LdotV)));
////float invLenLV = rsqrt(abs(2 + 2 * LdotV));
//float NdotH = (NdotL + normalize(NdotV)) * invLenLV;
//float NdotH = saturate((NdotL + normalize(NdotV)) * invLenLV);
float3 H = Unity_SafeNormalize(light.dir + viewDir);
//float H = (light.dir + viewDir) * invLenLV;
float LdotH = saturate(dot(light.dir, H));
//float3 H = normalize(viewDir + light.dir);
//float NdotL = saturate(dot(normal, light.dir));
//float NdotV = saturate(abs(dot(normal, viewDir)) + 1e-5);
float NdotH = saturate(dot(normal, H));
float VdotH = saturate(dot(viewDir, H));
//float LdotH = saturate(dot(light.dir, H));
half grazingTerm = saturate(smoothness + (1 - oneMinusReflectivity));
// Diffuse
float perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness);
float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
float diffuseTerm = DisneyDiffuse(NdotV, NdotL, LdotH, perceptualRoughness) * NdotL;// - Need this NdotL multiply?
// Cloth - Asperity Scattering - Inverse Beckmann Layer
float3 F1 = FresnelTerm(fuzzColor, LdotH);// FresnelLerp(fuzzColor, grazingTerm, NdotV);// FresnelTerm(FuzzColor, LdotH);// F_Schlick(FuzzColor, VdotH);
float D1 = D_InvGGX(roughness, NdotH);
float V1 = Vis_Cloth(NdotV, NdotL);
//Specular term
float3 specularTerm1 = V1 * D1; //*UNITY_PI;
# ifdef UNITY_COLORSPACE_GAMMA
specularTerm1 = sqrt(max(1e-4h, specularTerm1));
# endif
// specularTerm * nl can be NaN on Metal in some cases, use max() to make sure it's a sane value
// specularTerm1 = max(0, specularTerm1 * NdotL);
#if defined(_SPECULARHIGHLIGHTS_OFF)
specularTerm1 = 0.0;
#endif
float3 Spec1 = specularTerm1 * light.color * FresnelTerm(fuzzColor, LdotH);
// Generalized microfacet specular
/*float3 F2 = F_Schlick(specColor, VdotH);
float D2 = D_GGX(roughness, NdotH);
float V2 = Vis_SmithJointApprox(roughness, NdotV, NdotL);
float3 Spec2 = D2 * V2 * F2 * light.color;*/
//Unpack world vectors
float3 tangent = worldVectors[0];
float3 bitangent = worldVectors[1];
//Tangent vectors
float TdotH = dot(tangent, H);
float TdotL = dot(tangent, light.dir);
float BdotH = dot(bitangent, H);
float BdotL = dot(bitangent, light.dir);
float TdotV = dot(viewDir, tangent);
float BdotV = dot(viewDir, bitangent);
//Fresnels
float3 F2 = FresnelLerp(specColor, grazingTerm, NdotV);// FresnelTerm(specColor, LdotH);// FresnelLerp(specColor, grazingTerm, NdotV); //Original Schlick - Replace from SRP?
float roughnessT;
float roughnessB;
//float perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness);
//float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
ConvertAnisotropyToRoughness(roughness, anisotropy, roughnessT, roughnessB);
//Clamp roughness
//roughness = ClampRoughnessForAnalyticalLights(roughness);
roughnessT = ClampRoughnessForAnalyticalLights(roughnessT);
roughnessB = ClampRoughnessForAnalyticalLights(roughnessB);
//Visibility & Distribution terms
float V2 = SmithJointGGXAnisotropic(TdotV, BdotV, NdotV, TdotL, BdotL, NdotL, roughnessT, roughnessB);
float D2 = D_GGXAnisotropic(TdotH, BdotH, NdotH, roughnessT, roughnessB);
//Specular term
float3 specularTerm2 = V2 * D2; //*UNITY_PI;
# ifdef UNITY_COLORSPACE_GAMMA
specularTerm2 = sqrt(max(1e-4h, specularTerm2));
# endif
// specularTerm * nl can be NaN on Metal in some cases, use max() to make sure it's a sane value
specularTerm2 = max(0, specularTerm2 * NdotL);
#if defined(_SPECULARHIGHLIGHTS_OFF)
specularTerm2 = 0.0;
#endif
float3 Spec2 = specularTerm2 * light.color * FresnelTerm(specColor, LdotH);
float3 Spec = lerp(Spec2, Spec1, Cloth);
//Reduction
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
//Final
//half grazingTerm = saturate(smoothness + (1 - oneMinusReflectivity));
half3 color = (diffColor * (gi.diffuse + light.color * diffuseTerm))
+ Spec
+ surfaceReduction * gi.specular * FresnelLerp(specColor, grazingTerm, NdotV);
return half4(color, 1);
}
// ------------------------------------------------------------------
// Eye Shading Function
//float3 EyeShading(FGBufferData GBuffer, float3 LobeRoughness, float3 LobeEnergy, float3 L, float3 V, half3 N)
float4 EyeShading(float3 diffColor, float3 specColor, float3 viewDir, half3 normal, float smoothness, float oneMinusReflectivity, UnityLight light, UnityIndirect gi)
{
float3 H = normalize(viewDir + light.dir);
float NdotL = saturate(dot(normal, light.dir));
float NdotV = saturate(abs(dot(normal, viewDir)) + 1e-5);
float NdotH = saturate(dot(normal, H));
float VdotH = saturate(dot(viewDir, H));
float LdotH = saturate(dot(light.dir, H));
// Generalized microfacet specular
float perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness);
float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
float D = D_GGX(roughness, NdotH);// *LobeEnergy[1];
float V = Vis_SmithJointApprox(roughness, NdotV, NdotL);
float3 F = F_Schlick(specColor, VdotH);
float3 specularTerm = V * D; //*UNITY_PI;
# 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 * NdotL);
#if defined(_SPECULARHIGHLIGHTS_OFF)
specularTerm = 0.0;
#endif
half grazingTerm = saturate(smoothness + (1 - oneMinusReflectivity));
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
float diffuseTerm = DisneyDiffuse(NdotV, NdotL, LdotH, perceptualRoughness) * NdotL; // TODO - Unreal does not apply diffuse in Shading function
//Final
half3 color = (diffColor * (gi.diffuse + light.color * diffuseTerm))
+ specularTerm * light.color * FresnelTerm(specColor, LdotH)
+ surfaceReduction * gi.specular * FresnelLerp(specColor, grazingTerm, NdotV);
return half4(color, 1);
}
// ------------------------------------------------------------------
// Subsurface Shading Function
float3 SubsurfaceShadingSimple(float3 diffColor, float3 normal, float3 viewDir, float3 thickness, UnityLight light)
{
half3 vLTLight = light.dir + normal * 1;
half fLTDot = pow(saturate(dot(viewDir, -vLTLight)), 3.5) * 1.5;
half3 fLT = 1 * (fLTDot + 2) * (thickness);
return diffColor * ((light.color * fLT) * 0.4);
}
// ------------------------------------------------------------------
// Eye Subsurface Shading Function
//float3 EyeSubsurfaceShading(FGBufferData GBuffer, float3 L, float3 V, half3 N)
float3 EyeSubsurfaceShading(float3 diffColor, float3 specColor, float3 viewDir, half3 normal, float smoothness, float4 iris, UnityLight light)
{
float2 irisNormal = iris.rg;
float irisMask = iris.z;
float irisDistance = iris.w;
float3 H = normalize(viewDir + light.dir);
float VdotH = saturate(dot(viewDir, H));
float NdotV = saturate(abs(dot(normal, viewDir)) + 1e-5);
float LdotH = saturate(dot(light.dir, H));
// F_Schlick
//float F0 = GBuffer.Specular * 0.08;
//float Fc = Pow5(1 - VoH);
//float F = Fc + (1 - Fc) * F0;
float3 fresnel0 = lerp(specColor, diffColor, smoothness);
float3 F = FresnelSchlick(fresnel0, 1.0, LdotH);
//float IrisDistance = GBuffer.CustomData.w;
//float IrisMask = GBuffer.CustomData.z;
float3 IrisNormal;
IrisNormal = OctahedronToUnitVector(irisNormal * 2 - 1);
// Blend in the negative intersection normal to create some concavity
// Not great as it ties the concavity to the convexity of the cornea surface
// No good justification for that. On the other hand, if we're just looking to
// introduce some concavity, this does the job.
float3 CausticNormal = normalize(lerp(IrisNormal, -normal, irisMask*irisDistance));
float NdotL = saturate(dot(IrisNormal, light.dir));
float Power = lerp(12, 1, NdotL);
float Caustic = 0.6 + 0.2 * (Power + 1) * pow(saturate(dot(CausticNormal, light.dir)), Power);
float Iris = NdotL * Caustic;
// http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/
float Wrap = 0.15;
float Sclera = saturate((dot(normal, light.dir) + Wrap) / (1 + Wrap) * (1 + Wrap));
return (1 - F) * lerp(Sclera, Iris, irisMask) * diffColor / UNITY_PI;
}
// ------------------------------------------------------------------
// Shading function selectors
//float3 SurfaceShading(/*FGBufferData GBuffer,*/ float3 LobeRoughness, float3 LobeEnergy, float3 L, float3 V, half3 N, uint2 Random)
float4 SurfaceShading(float3 diffColor, float3 specColor, float oneMinusReflectivity, float smoothness, float3 normal,
float3x3 worldVectors, float anisotropy, float4 customData, float metallic, float3 viewDir, UnityLight light, UnityIndirect gi)
{
#if defined(SHADINGMODELID_UNLIT)
{
return UnlitShading(diffColor);
}
#elif defined(SHADINGMODELID_STANDARD) || defined(SHADINGMODELID_SUBSURFACE) || defined(SHADINGMODELID_SKIN) || defined(SHADINGMODELID_FOLIAGE)
{
return StandardShading(diffColor, specColor, oneMinusReflectivity, smoothness,
normal, worldVectors, anisotropy, metallic, viewDir, light, gi);
}
#elif defined (SHADINGMODELID_CLEARCOAT)
{
return float4(1, 1, 1, 1); //ClearCoatShading(GBuffer, LobeRoughness, LobeEnergy, L, V, N);
}
#elif defined (SHADINGMODELID_CLOTH)
{
return ClothShading(diffColor, specColor, customData.rgb, customData.a, oneMinusReflectivity, smoothness, normal, viewDir, light, gi, worldVectors, anisotropy);
}
#elif defined (SHADINGMODELID_EYE)
{
return EyeShading(diffColor, specColor, viewDir, normal, smoothness, oneMinusReflectivity, light, gi); //EyeShading(GBuffer, LobeRoughness, LobeEnergy, L, V, N);
}
#endif
return float4(0, 0, 0, 0);
}
//float3 SubsurfaceShading(/*FGBufferData GBuffer,*/ float3 L, float3 V, half3 N, float Shadow, uint2 Random)
float3 SubsurfaceShading(float3 diffColor, float3 specColor, float3 normal, float smoothness, float3 viewDir, float4 customData, UnityLight light)
{
#if defined (SHADINGMODELID_SUBSURFACE)
{
return SubsurfaceShadingSimple(diffColor, normal, viewDir, customData.rgb, light);
}
#elif defined (SHADINGMODELID_SKIN)
{
return float3(0, 0, 0); //SubsurfaceShadingPreintegratedSkin(GBuffer, L, V, N);
}
#elif defined (SHADINGMODELID_FOLIAGE)
{
return float3(0, 0, 0); //SubsurfaceShadingTwoSided(SubsurfaceColor, L, V, N);
}
#elif defined (SHADINGMODELID_HAIR)
{
return float3(0, 0, 0); //HairShading(GBuffer, L, V, N, Shadow, 1, 0, Random);
}
#elif defined (SHADINGMODELID_EYE)
{
return EyeSubsurfaceShading(diffColor, specColor, viewDir, normal, smoothness, customData, light); //EyeSubsurfaceShading(GBuffer, L, V, N);
}
#endif
return float3(0, 0, 0);
}
//#endif UNITY_ADVANCED_SHADINGMODELS_INCLUDED
//-------------------------------------------------------------------------------------
// Lighting Helpers
// Glossy Environment
half3 Unity_AnisotropicGlossyEnvironment(UNITY_ARGS_TEXCUBE(tex), half4 hdr, Unity_GlossyEnvironmentData glossIn, half anisotropy) //Reference IBL from HD Pipe (Add half3 L input and replace R)
{
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
half mip = perceptualRoughnessToMipmapLevel(perceptualRoughness);
half3 R = glossIn.reflUVW;// -half3(anisotropy, 0, 0);
half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(tex, R, mip);
return DecodeHDR(rgbm, hdr);
}
// Indirect Specular
inline half3 UnityGI_AnisotropicIndirectSpecular(UnityGIInput data, half occlusion, Unity_GlossyEnvironmentData glossIn, half anisotropy, half3x3 worldVectors)
{
half3 specular;
float3 tangentX = worldVectors[0];
float3 tangentY = worldVectors[1];
float3 N = worldVectors[2];
float3 V = data.worldViewDir;
float3 iblNormalWS = GetAnisotropicModifiedNormal(tangentY, N, V, anisotropy);
float3 iblR = reflect(-V, iblNormalWS);
#ifdef UNITY_SPECCUBE_BOX_PROJECTION
// we will tweak reflUVW in glossIn directly (as we pass it to Unity_GlossyEnvironment twice for probe0 and probe1), so keep original to pass into BoxProjectedCubemapDirection
half3 originalReflUVW = glossIn.reflUVW;
glossIn.reflUVW = BoxProjectedCubemapDirection(iblR, data.worldPos, data.probePosition[0], data.boxMin[0], data.boxMax[0]);
#endif
#ifdef _GLOSSYREFLECTIONS_OFF
specular = unity_IndirectSpecColor.rgb;
#else
half3 env0 = Unity_AnisotropicGlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), data.probeHDR[0], glossIn, anisotropy);
//half3 env0 = Unity_AnisotropicGlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), data.probeHDR[0], glossIn, anisotropy, L); //Reference IBL from HD Pipe
#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(iblR, data.worldPos, data.probePosition[1], data.boxMin[1], data.boxMax[1]);
#endif
half3 env1 = Unity_AnisotropicGlossyEnvironment(UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0), data.probeHDR[1], glossIn, anisotropy);
//half3 env1 = Unity_AnisotropicGlossyEnvironment(UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0), data.probeHDR[1], glossIn, anisotropy, L); //Reference IBL from HD Pipe
specular = lerp(env1, env0, blendLerp);
}
else
{
specular = env0;
}
#else
specular = env0;
#endif
#endif
return specular * occlusion;// *weightOverPdf; //Reference IBL from HD Pipe
//return specular * occlusion * weightOverPdf; //Reference IBL from HD Pipe
}
// Global Illumination
inline UnityGI UnityAnisotropicGlobalIllumination(UnityGIInput data, half occlusion, half3 normalWorld, Unity_GlossyEnvironmentData glossIn, half anisotropy, half3x3 worldVectors)
{
UnityGI o_gi = UnityGI_Base(data, occlusion, normalWorld);
o_gi.indirect.specular = UnityGI_AnisotropicIndirectSpecular(data, occlusion, glossIn, anisotropy, worldVectors);
return o_gi;
}
//-------------------------------------------------------------------------------------
// Lighting Functions
//Surface Description
struct SurfaceOutputAdvanced
{
fixed3 Albedo; // base (diffuse or specular) color
fixed3 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
half3 Tangent;
half Anisotropy;
half4 CustomData;
float3x3 WorldVectors;
//half ShadingModel;
};
inline half4 LightingAdvanced(SurfaceOutputAdvanced 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 = SurfaceShading(s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, s.WorldVectors, s.Anisotropy, s.CustomData, s.Metallic, viewDir, gi.light, gi.indirect);
c.rgb += SubsurfaceShading(s.Albedo, specColor, s.Normal, s.Smoothness, viewDir, s.CustomData, gi.light);
//c.rgb += UNITY_BRDF_GI(s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, s.Occlusion, gi);
c.a = outputAlpha;
return c;
}
//This is pointless as always forward?
inline half4 LightingAdvanced_Deferred(SurfaceOutputAdvanced s, half3 viewDir, UnityGI gi, out half4 outGBuffer0, out half4 outGBuffer1, out half4 outGBuffer2)
{
half oneMinusReflectivity;
half3 specColor;
s.Albedo = DiffuseAndSpecularFromMetallic(s.Albedo, s.Metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity);
half4 c = SurfaceShading(s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, s.WorldVectors, s.Anisotropy, s.CustomData, s.Metallic, viewDir, gi.light, gi.indirect);
c.rgb += SubsurfaceShading(s.Albedo, specColor, s.Normal, s.Smoothness, viewDir, s.CustomData, gi.light);
UnityStandardData data;
data.diffuseColor = s.Albedo;
data.occlusion = s.Occlusion;
data.specularColor = specColor;
data.smoothness = s.Smoothness;
data.normalWorld = s.Normal;
UnityStandardDataToGbuffer(data, outGBuffer0, outGBuffer1, outGBuffer2);
half4 emission = half4(s.Emission + c.rgb, 1);
return emission;
}
inline void LightingAdvanced_GI(SurfaceOutputAdvanced 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 = UnityAnisotropicGlobalIllumination(data, s.Occlusion, s.Normal, g, s.Anisotropy, s.WorldVectors);
#endif
}
///END
//#pragma target 5.0
#pragma surface surf Advanced vertex:vert
#pragma glsl
#pragma debug
inline float4 unity_multiply_float(float4 arg1, float4 arg2)
{
return arg1 * arg2;
}
inline float unity_multiply_float(float arg1, float arg2)
{
return arg1 * arg2;
}
inline float4 unity_remap_float(float4 arg1, float2 arg2, float2 arg3)
{
return arg3.x + (arg1 - arg2.x) * (arg3.y - arg3.x) / (arg2.y - arg2.x);
}
sampler2D Texture_182faa0c_4b84_44f9_8526_6a2b5d1bfceb_Uniform;
float4 Color_14397097_d99f_4fb0_84c5_307d9e0d6ea9_Uniform;
sampler2D Texture_fa598f24_b328_4d21_a9aa_ded3cd2600dd_Uniform;
sampler2D Texture_11a92303_cad4_4ed7_b9a2_01fe39187cce_Uniform;
float Vector1_66d312ef_3451_4b07_9f27_d37785582eb7_Uniform;
float Vector1_d429c42e_84f9_4cd9_aeff_2b5531f4227d_Uniform;
float Vector1_078dba25_d724_4a74_99fe_078c8dc7ebf6_Uniform;
sampler2D Texture_6bba204c_5a19_44ba_9609_fc2dce308020_Uniform;
float4 Color_edaba26b_8c62_4e4c_8e17_5626c4a01b5c_Uniform;
struct Input
{
float4 color : COLOR;
half4 meshUV0;
float4 worldTangent;
float3 worldNormal;
INTERNAL_DATA
};
void vert(inout appdata_full v, out Input o)
{
UNITY_INITIALIZE_OUTPUT(Input,o);
o.meshUV0 = v.texcoord;
o.worldTangent = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
}
void surf(Input IN, inout SurfaceOutputAdvanced o)
{
half4 uv0 = IN.meshUV0;
float3 worldSpaceTangent = normalize(IN.worldTangent.xyz);
float3 worldSpaceNormal = normalize(IN.worldNormal);
float3 worldSpaceBitangent = cross(worldSpaceNormal, worldSpaceTangent) * IN.worldTangent.w;
float4 UV_2d892868_f0a3_42b8_a8aa_131ecb6b3b88_UV = uv0;
float4 Texture_182faa0c_4b84_44f9_8526_6a2b5d1bfceb = tex2D(Texture_182faa0c_4b84_44f9_8526_6a2b5d1bfceb_Uniform, (UV_2d892868_f0a3_42b8_a8aa_131ecb6b3b88_UV.xy));
float4 Multiply_24b106c6_e725_4e76_b49d_7e16a5f8b4cd_Output = unity_multiply_float(Texture_182faa0c_4b84_44f9_8526_6a2b5d1bfceb, Color_14397097_d99f_4fb0_84c5_307d9e0d6ea9_Uniform);
float4 Texture_fa598f24_b328_4d21_a9aa_ded3cd2600dd = float4(UnpackNormal(tex2D(Texture_fa598f24_b328_4d21_a9aa_ded3cd2600dd_Uniform, uv0.xy)), 0);
float4 Texture_11a92303_cad4_4ed7_b9a2_01fe39187cce = tex2D(Texture_11a92303_cad4_4ed7_b9a2_01fe39187cce_Uniform, uv0.xy);
float Multiply_a6852a24_0a26_4dc5_a5dd_d9ebca72d7f7_Output = unity_multiply_float(Texture_11a92303_cad4_4ed7_b9a2_01fe39187cce.r, Vector1_66d312ef_3451_4b07_9f27_d37785582eb7_Uniform);
float Multiply_3b598945_371c_42f0_a475_8734e4082bcd_Output = unity_multiply_float(Texture_11a92303_cad4_4ed7_b9a2_01fe39187cce.a, Vector1_d429c42e_84f9_4cd9_aeff_2b5531f4227d_Uniform);
float4 Texture_6bba204c_5a19_44ba_9609_fc2dce308020 = tex2D(Texture_6bba204c_5a19_44ba_9609_fc2dce308020_Uniform, uv0.xy);
float4 Remap_131b45c5_4f35_4053_9b66_6a0ad4d4feca_Output = unity_remap_float(Texture_6bba204c_5a19_44ba_9609_fc2dce308020, float2 (0,1), float2 (0.05,1));
float4 Multiply_0b13da15_eda7_44aa_a517_e6fc77a51419_Output = unity_multiply_float(Remap_131b45c5_4f35_4053_9b66_6a0ad4d4feca_Output, Color_edaba26b_8c62_4e4c_8e17_5626c4a01b5c_Uniform);
o.Albedo = Multiply_24b106c6_e725_4e76_b49d_7e16a5f8b4cd_Output;
o.Normal = Texture_fa598f24_b328_4d21_a9aa_ded3cd2600dd;
o.Normal += 1e-6;
o.Metallic = Multiply_a6852a24_0a26_4dc5_a5dd_d9ebca72d7f7_Output;
o.Smoothness = Multiply_3b598945_371c_42f0_a475_8734e4082bcd_Output;
o.WorldVectors = float3x3(worldSpaceTangent, worldSpaceBitangent, worldSpaceNormal);
o.Anisotropy = Vector1_078dba25_d724_4a74_99fe_078c8dc7ebf6_Uniform;
o.CustomData = float4(Multiply_0b13da15_eda7_44aa_a517_e6fc77a51419_Output.rgb, 0);
}
ENDCG
}
FallBack "Diffuse"
CustomEditor "LegacyIlluminShaderGUI"
}