Files

408 lines
17 KiB
HLSL

#ifndef CHARACTER_CORE_INCLUDED
#define CHARACTER_CORE_INCLUDED
#include "CharacterPBR_Inputs.hlsl"
////INPUTS////////////////////////////////////////////////////////////
///////////////////////////////////
#if defined(_EMISSION_ON) || defined(_ANISO_GGX_ON) || defined(ANISO_KAJIYA_KAY)
TEXTURE2D(_MaskMap2); SAMPLER(sampler_MaskMap2);
#endif
CBUFFER_START(UnityPerMaterial)
half4 _MainTex_ST; half4 _NormalMap_ST;
half _CutoffThres;
half _HighLightLerp; half4 _HighLightLerpColor; half _OriColorAdd; half4 _Color;
half _NormalMapScale;half _ColorLerpMask; half4 _LerpMaskColor; half4 _AmbientColor;
half4 _MaskMap_ST; half4 _MaskMap2_ST;
half4 _EmissionColor; half _EmissionStrength;
half _SmoothnessScale; half _MetallicScale; half _Occlusion; half _DiffuseWrap;
half _CameraLightIntensityMin; half _CameraLightIntensityMax;
half _SkinNormalBias; half _SkinBlurStrength; half _SkinCurvature; half _SkinAmbientIntensity;
half4 _SSSLut_ST; half _ReflectionCubeLod; half _ReflectionYOffset;
#if defined(TRANSLUCENCY_ON)
half3 _SkinTranslucencyColor;
#endif
#if defined(_ANISO_GGX_ON)
half _AnisoSmoothnessScale;
half _AnisoMetallicScale;
half _AnisoSpecAlbedoScale;
half _AmbientReflectionStrength;
#endif
CBUFFER_END
/////////////////////////////////////////////////////////////////////////////////////////////////////////
TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex);
TEXTURE2D(_MaskMap); SAMPLER(sampler_MaskMap);
TEXTURE2D(_SSSLut); SAMPLER(sampler_SSSLut);
TEXTURE2D(_NormalMap); SAMPLER(sampler_NormalMap);
TEXTURECUBE(_ReflectionCube); SAMPLER(sampler_ReflectionCube);
struct SurfaceOutputStandardCustom
{
half3 Albedo; half3 Normal; half3 Emission;
half Metallic; half Smoothness; half Occlusion; half Alpha;
half IsSkin; half3 SkinNormal; half SkinCurvature;
half3 TranslucencyColor; half Anisotropy; half3 WorldTangent; half3 WorldBitangent;
half3 HighlightColor; half3 AnisoSpecColor;
half MainShift; half MainExponent; half SubShift; half SubExponent;
};
struct VertexInput
{
half4 vertex : POSITION;
half4 normal : NORMAL;
half4 tangent: TANGENT;
half2 texcoord : TEXCOORD0;
half2 lightmapUV : TEXCOORD1;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct VertexOutput
{
half4 pos : SV_POSITION;
half2 texcoord : TEXCOORD0;
half4 tSpace0 : TEXCOORD1;
half4 tSpace1 : TEXCOORD2;
half4 tSpace2 : TEXCOORD3;
half3 normal : TEXCOORD4;
float4 shadowCoord : TEXCOORD5;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
#define WorldNormalVector(i, normal) normalize(half3(dot(i.tSpace0.xyz,normal), dot(i.tSpace1.xyz,normal), dot(i.tSpace2.xyz,normal)))
////BRDF/////////////////////////////////////////////////////////////////////////////////////////////////
half3 Unity_GlossyEnvironment (half4 hdr, Unity_GlossyEnvironmentData glossIn)
{
half perceptualRoughness = glossIn.roughness /* perceptualRoughness */ ;
#if 0
float m = PerceptualRoughnessToRoughness(perceptualRoughness);
const float fEps = 1.192092896e-07F;
float n = (2.0/max(fEps, m*m))-2.0;
n /= 4;
perceptualRoughness = pow( 2/(n+2), 0.25);
#else
perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness);
#endif
half3 R = glossIn.reflUVW;
half4 rgbm = SAMPLE_TEXTURECUBE_LOD(_ReflectionCube, sampler_ReflectionCube, R, 3);
return DecodeHDR(rgbm, hdr);
}
inline half GGXSpecularTerm(half roughness, half nh, half lh)
{
half a = roughness;
float a2 = a * a;
float d = nh * nh * (a2 - 1.f) + 1.00001f;
float specularTerm = a2 / (max(0.1f, lh * lh) * (roughness + 0.5f) * (d * d) * 4);
#if defined (SHADER_API_MOBILE)
specularTerm = clamp(specularTerm - 1e-4f, 0.0, 100.0); // Prevent FP16 overflow on mobiles
#endif
return specularTerm;
}
#if defined(_SKIN_ON)
inline half3 SkinDiffuseTerm(half3 normal, half3 lightDir, half skinCurvature)
{
half NoL = dot(normal, lightDir);
NoL = NoL * 0.5 + 0.5;
half3 diffuseTerm = SAMPLE_TEXTURE2D(_SSSLut, sampler_SSSLut, half2(NoL, skinCurvature));
return diffuseTerm;
}
#endif
#if defined(_ANISO_GGX_ON)
inline half D_GGXAniso_SGame(half TdotH, half BdotH, half mt, half mb, half nh)
{
half d = TdotH * TdotH / (mt * mt) + BdotH * BdotH / (mb * mb) + nh * nh;
return (1.0 / (3.14 * mt * mb * d * d));
}
inline half V_SmithJointGGXAniso_SGame(half TdotV, half BdotV, half NdotV, half TdotL, half BdotL, half NdotL, half roughnessT, half roughnessB)
{
half lambdaV = NdotL * sqrt(roughnessT * TdotV * TdotV + roughnessB * BdotV * BdotV + NdotV * NdotV);
half lambdaL = NdotV * sqrt(roughnessT * TdotL * TdotL + roughnessB * BdotL * BdotL + NdotL * NdotL);
return 0.5 / max(1e-5f, (lambdaV + lambdaL));
}
inline half GGXSpecularTermAniso_SGame(half3 worldTangent, half3 worldBiTangent, half roughnessT, half roughnessB, half3 halfDir, half3 lightDir, half3 viewDir
, half nl, half nh, half nv)
{
half mt = roughnessT;
half mb = roughnessB;
half TdotH = dot(worldTangent, halfDir);
half BdotH = dot(worldBiTangent, halfDir);
half TdotV = dot(worldTangent, viewDir);
half BdotV = dot(worldBiTangent, viewDir);
half TdotL = dot(worldTangent, lightDir);
half BdotL = dot(worldBiTangent, lightDir);
half D = D_GGXAniso_SGame(TdotH, BdotH, mt, mb, nh);
half V = V_SmithJointGGXAniso_SGame(TdotV, BdotV, nv, TdotL, BdotL, nl, mt, mb);
half specularTerm = (V * D) * 3.14;
return clamp(specularTerm, 0, 5);
}
#endif
half3 DirectDiffuse(SurfaceOutputStandardCustom s, half nl, half3 lightDir, half3 viewDir)
{
half3 diffColor = s.Albedo;
half3 diffuseTerm = half3(nl, nl, nl);
#if defined(_SKIN_ON)
half3 skinDiffuseTerm = SkinDiffuseTerm(s.SkinNormal, lightDir, s.SkinCurvature);
diffuseTerm = lerp(diffuseTerm, skinDiffuseTerm, s.IsSkin);
#endif
return diffColor * diffuseTerm;
}
half3 DirectSpecular(SurfaceOutputStandardCustom s, half nl, half3 lightDir, half smoothness, half roughness, half3 specColor, half3 viewDir)
{
half3 normal = s.Normal;
#if defined(_ANISO_GGX_ON)
half3 worldTangent = s.WorldTangent;
half3 worldBitangent = s.WorldBitangent;
#endif
half3 halfDir = normalize(lightDir + viewDir);
half nh = saturate(dot(normal, halfDir));
half nv = abs(dot(normal, viewDir));
half lh = saturate(dot(lightDir, halfDir));
half specularTerm = GGXSpecularTerm(roughness, nh, lh);
#if defined(_ANISO_GGX_ON)
half roughnessT = roughness;
half roughnessB = 1.0;
half anisoSpecularTerm = GGXSpecularTermAniso_SGame(worldTangent, worldBitangent, roughnessT, roughnessB, halfDir, lightDir, viewDir, nl, nh, nv);
specularTerm = lerp(specularTerm, anisoSpecularTerm, s.Anisotropy);
#endif
specularTerm = max(0, specularTerm * nl);
return specularTerm * specColor;
}
half3 DirectSpecular(SurfaceOutputStandardCustom s, half nl, half3 lightDir, half3 specColor, half3 viewDir) {
half smoothness = s.Smoothness;
half perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness);
half roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
return DirectSpecular(s, nl, lightDir, smoothness, roughness, specColor, viewDir);
}
inline half4 Character_BRDF2_PBS(SurfaceOutputStandardCustom s, half3 specColor, half oneMinusReflectivity, half3 viewDir, UnityLight light) {
half3 normal = s.Normal;
half nl = saturate((dot(normal, light.dir) + _DiffuseWrap) / ((1 + _DiffuseWrap) * (1 + _DiffuseWrap)));
half3 directDiffuse = DirectDiffuse(s, nl, light.dir, viewDir);
half3 directSpecular = DirectSpecular(s, nl, light.dir, specColor, viewDir);
half3 color = directDiffuse * light.color + directSpecular * light.color;
return half4(color, 1);
}
half3 IndirectSpecular(half roughness, half3 specColor)
{
half surfaceReduction;
surfaceReduction = 1.0 / (roughness * roughness + 1.0);
return surfaceReduction * specColor;
}
inline half4 Character_BRDF2_PBS(SurfaceOutputStandardCustom s, half3 specColor, half oneMinusReflectivity,
half3 viewDir, UnityLight light, UnityIndirect gi) {
half3 diffColor = s.Albedo;
half3 normal = s.Normal;
half smoothness = s.Smoothness;
half perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness);
half roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
half nl = saturate((dot(normal, light.dir) + _DiffuseWrap) / ((1 + _DiffuseWrap) * (1 + _DiffuseWrap)));
half3 directDiffuse = DirectDiffuse(s, nl, light.dir, viewDir);
half3 directSpecular = DirectSpecular(s, nl, light.dir, smoothness, roughness, specColor, viewDir);
half3 directColor = directDiffuse * light.color + directSpecular * light.color;
half3 indirectSpecular = IndirectSpecular(roughness, specColor) * gi.specular;
half3 indirectColor = diffColor * gi.diffuse + indirectSpecular;
half3 finalColor = directColor + indirectColor;
return half4(finalColor, 1);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////LIGHTING////////////////////////////////////////////////////////////////////////////////////////////
inline half4 LightingCharacter(SurfaceOutputStandardCustom s, half3 viewDir, UnityGI gi)
{
half3 mainLightDir = gi.light.dir;
half3 normalizeLightDir = normalize(half3(mainLightDir.x, 0.0, mainLightDir.z));
half3 normalizeViewDir = normalize(half3(viewDir.x, 0.0, viewDir.z));
half3 dirFactor = dot(normalizeLightDir, normalizeViewDir) * 0.5 + 0.5;
half cameraLightAtten = lerp(_CameraLightIntensityMax, _CameraLightIntensityMin, dirFactor);
#if defined(TRANSLUCENCY_ON)
half translucencyAtten = lerp(_CameraLightIntensityMin, _CameraLightIntensityMax, dirFactor);
s.Albedo += s.TranslucencyColor * (saturate(dot(s.Normal, -mainLightDir)) + saturate(dot(s.Normal, viewDir)) * translucencyAtten);
#endif
half oneMinusReflectivity;
half3 specColor;
half outputAlpha;
half3 albedo = DiffuseAndSpecularFromMetallic(s.Albedo, s.Metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity);
#if defined(_ANISO_GGX_ON)
specColor = lerp(specColor, lerp(half4(0.04, 0.04, 0.04, 0.06), s.Albedo, _AnisoSpecAlbedoScale), s.Anisotropy);
#endif
half nv = dot(s.Normal, viewDir);
// s.Albedo = PreMultiplyAlpha(albedo, s.Alpha, oneMinusReflectivity, /*out*/ outputAlpha);
half4 c = Character_BRDF2_PBS(s, specColor, oneMinusReflectivity, viewDir, gi.light, gi.indirect);
UnityGI gi2 = gi;
// HSV Color Alter
half3 hsvLightCol = RgbToHsv_SGame(GetMainLight().color.rgb);
hsvLightCol.b = 1;
hsvLightCol = HsvToRgb_SGame(hsvLightCol);
gi2.light.color = hsvLightCol * cameraLightAtten;
gi2.light.dir = viewDir;
c.rgb += Character_BRDF2_PBS(s, specColor, oneMinusReflectivity, viewDir, gi2.light);
c.a = outputAlpha;
return c;
}
inline half3 CharacterGI_IndirectSpecular(UnityGIInput data, half occlusion, Unity_GlossyEnvironmentData glossIn)
{
half4 hdr = data.probeHDR[0];
hdr.x = 1;
glossIn.reflUVW = RotationY(glossIn.reflUVW, _ReflectionYOffset);
half3 env0 = Unity_GlossyEnvironment(hdr, glossIn);
return env0 * occlusion;
}
inline UnityGI CharacterGI_Base(UnityGIInput data, half occlusion, half3 normalWorld)
{
UnityGI o_gi;
ResetUnityGI(o_gi);
o_gi.light = data.light;
half3 hsvLightCol = RgbToHsv_SGame(GetMainLight().color.rgb);
hsvLightCol.b = 1;
hsvLightCol = HsvToRgb_SGame(hsvLightCol);
o_gi.light.color = hsvLightCol * data.atten;
o_gi.indirect.diffuse = data.ambient;
o_gi.indirect.diffuse *= occlusion;
return o_gi;
}
inline UnityGI CharacterGlobalIllumination(UnityGIInput data, half occlusion, half3 normalWorld, Unity_GlossyEnvironmentData glossIn)
{
UnityGI o_gi = CharacterGI_Base(data, occlusion, normalWorld);
o_gi.indirect.specular = CharacterGI_IndirectSpecular(data, occlusion, glossIn);
return o_gi;
}
inline void LightingCharacter_GI(SurfaceOutputStandardCustom s, UnityGIInput data, inout UnityGI gi)
{
// Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup(_ReflectionCubeLod, data.worldViewDir, s.Normal, half3(0, 0, 0));
Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup(s.Smoothness, data.worldViewDir, s.Normal, half3(0, 0, 0));
gi = CharacterGlobalIllumination(data, s.Occlusion, s.Normal, g);
#if defined(_SKIN_ON)
gi.indirect.diffuse *= lerp(1, _SkinAmbientIntensity, s.IsSkin);
#endif
#if defined(_ANISO_GGX_ON)
gi.indirect.specular *= lerp(1, _AmbientReflectionStrength, s.Anisotropy);
#endif
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
VertexOutput VertBaseCore(VertexInput v)
{
VertexOutput o;
VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
VertexNormalInputs normalInput = GetVertexNormalInputs(v.normal, v.tangent);
o.pos = vertexInput.positionCS;
half3 worldPos = vertexInput.positionWS;
float3 worldNormal = normalInput.normalWS;
half3 worldViewDir = GetCameraPositionWS() - worldPos;
o.tSpace0 = half4(normalInput.tangentWS.x, normalInput.bitangentWS.x, normalInput.normalWS.x, worldPos.x);
o.tSpace1 = half4(normalInput.tangentWS.y, normalInput.bitangentWS.y, normalInput.normalWS.y, worldPos.y);
o.tSpace2 = half4(normalInput.tangentWS.z, normalInput.bitangentWS.z, normalInput.normalWS.z, worldPos.z);
o.texcoord = v.texcoord.xy;
o.normal = worldNormal;
o.shadowCoord = GetShadowCoord(vertexInput);
return o;
}
half4 FragBaseCore(VertexOutput i, half3 worldPos, half3 worldViewDir, half3 worldTangent = half3(0, 0, 0))
{
half2 uv_MainTex = TRANSFORM_TEX(i.texcoord, _MainTex);
half2 uv_NrmTex = TRANSFORM_TEX(i.texcoord, _NormalMap);
half2 uv_mskTex = TRANSFORM_TEX(i.texcoord, _MaskMap);
half4 albedoColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv_MainTex);
half4 normalColor = SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, uv_NrmTex);
half4 mask = SAMPLE_TEXTURE2D(_MaskMap, sampler_MaskMap, uv_mskTex);
#if defined(_CUTOFF_ON)
clip(albedoColor.a - _CutoffThres / 255);
#endif
SurfaceOutputStandardCustom o = (SurfaceOutputStandardCustom)0;
o.Occlusion = 1.0;
half3 colorAddLerp = lerp(_Color.rgb * _OriColorAdd, _LerpMaskColor.rgb * 0.8, _ColorLerpMask * albedoColor.a);
#if defined(_ANISO_GGX_ON)
half4 mask2 = SAMPLE_TEXTURE2D(_MaskMap2, sampler_MaskMap2, TRANSFORM_TEX(i.texcoord, _MaskMap2));
o.Albedo = albedoColor.rgb * colorAddLerp * step(0.5, mask2.g) + albedoColor.rgb * step(mask2.g, 0.5);
#else
o.Albedo = albedoColor.rgb * colorAddLerp;
#endif
o.Alpha = albedoColor.a * _Color.a;
half4 c = 0;
#if defined(_USENORMALMAP_OFF)
o.Normal = i.normal;
#else
o.Normal = lerp(half3(0, 0, 1), normalColor.rgb * 2 - 1, _NormalMapScale);
#endif
o.Normal = WorldNormalVector(i, o.Normal);
o.Metallic = mask.r * (_MetallicScale + 1);
o.Emission = normalColor.a * _EmissionColor.rgb * _EmissionStrength;
o.Occlusion = lerp(mask.b, 1, _Occlusion);
o.Smoothness = (1 - mask.a) * (_SmoothnessScale + 1);
#if defined(_ANISO_GGX_ON)
o.Anisotropy = mask2.g;
half anisoMetallic = _AnisoMetallicScale;
half anisoSmoothness = _AnisoSmoothnessScale;
o.Metallic = lerp(o.Metallic, anisoMetallic, o.Anisotropy);
o.Smoothness = lerp(o.Smoothness, anisoSmoothness, o.Anisotropy);
o.WorldTangent = worldTangent;
o.WorldBitangent = cross(o.Normal, o.WorldTangent);
o.WorldTangent = cross(o.WorldBitangent, o.Normal);
#endif
o.IsSkin = 0;
#if defined(_SKIN_ON)
o.IsSkin = mask.g;
half3 skinNormal = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, uv_NrmTex));
o.SkinNormal = normalize(lerp(o.Normal, skinNormal, _SkinBlurStrength));
o.SkinCurvature = _SkinCurvature;
o.SkinNormal = WorldNormalVector(i, o.SkinNormal);
#endif
half atten = 1;
UnityGI gi = (UnityGI)0;
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;
gi.light.color = GetMainLight().color.rgb;
gi.light.dir = GetMainLight().direction;
UnityGIInput giInput = (UnityGIInput)0;
giInput.light = gi.light;
giInput.worldPos = worldPos;
giInput.worldViewDir = worldViewDir;
giInput.atten = atten;
giInput.ambient.rgb = _AmbientColor;
giInput.probeHDR[0] = unity_SpecCube0_HDR;
LightingCharacter_GI(o, giInput, gi);
c += LightingCharacter(o, worldViewDir, gi);
c.rgb += o.Emission;
c.rgb = clamp(c.rgb, 0, 3);
c.rgb = lerp(c.rgb, c.rgb + pow(1 - saturate(dot(o.Normal, worldViewDir)), 2.5) * _HighLightLerpColor * 4, _HighLightLerp);
c.a = albedoColor.a;
return c;
}
half4 FragBaseCore(VertexOutput i)
{
half3 worldPos = half3(i.tSpace0.w, i.tSpace1.w, i.tSpace2.w);
half3 worldViewDir = normalize(GetCameraPositionWS() - worldPos);
#if defined(_ANISO_GGX_ON)
half3 worldTangent = normalize(half3(i.tSpace0.x, i.tSpace1.x, i.tSpace2.x));
#else
half3 worldTangent = half3(0, 0, 0);
#endif
return FragBaseCore(i, worldPos, worldViewDir, worldTangent);
}
VertexOutput VertBase(VertexInput v)
{
return VertBaseCore(v);
}
half4 FragBase(VertexOutput i) : SV_Target
{
half4 finalColor = FragBaseCore(i);
return finalColor;
}
#endif