389 lines
16 KiB
HLSL
389 lines
16 KiB
HLSL
//修改说明
|
||
//1)加上StylizedLambert
|
||
//2)加上高光颜色和阴影颜色(HColor和SColor) + SGAME_HS_COLOR_STYLIZED(光照颜色主要影响亮面,不影响暗面)
|
||
//3)加上WrapNL对Skin的处理
|
||
//4)atten改为由BRDF处理,添加SGameShadowAtten(atten);
|
||
//5)添加SGAME_DIRECT_SPECULAR,背光面也有微弱的高光
|
||
//6)添加SGAME_INDIRECT_SPECULAR,间接高光gi.specular改用gi.diffuse计算,由于gi.specular依赖的反射探头/天空盒不会随着光照和天空盒改变而变化
|
||
#ifndef SGAME_STANDARD_BRDF_INCLUDED
|
||
#define SGAME_STANDARD_BRDF_INCLUDED
|
||
|
||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
||
|
||
#include "SGameEnvMapBase.hlsl"
|
||
#include "SGameVLight.hlsl"
|
||
|
||
//一些自定义的函数,对BRDF进行拓展
|
||
//----------------------------------------------------------------------------------------
|
||
/////////////////////////////////////SHADOW ATTEN//////////////////////////////////////////
|
||
inline half3 BlendMode_Add( half3 s, half3 d)
|
||
{
|
||
return s + d;
|
||
}
|
||
inline half3 BlendMode_Screen( half3 s, half3 d)
|
||
{
|
||
return s + d - s*d;
|
||
}
|
||
inline half3 ACESToneMapping( half3 x )
|
||
{
|
||
half tA = 2.51f;
|
||
half tB = 0.03f;
|
||
half tC = 2.43f;
|
||
half tD = 0.59f;
|
||
half tE = 0.14f;
|
||
return saturate((x*(tA*x+tB))/(x*(tC*x+tD)+tE));
|
||
}
|
||
#if defined(SGAME_TONEMAPPING_LIGHT_BOOST)
|
||
inline half3 ApplyToneMappingLightBoost(half3 col, half3 lightColor)
|
||
{
|
||
return col * 1 * lightColor;
|
||
}
|
||
#endif
|
||
|
||
#if defined(SGAME_TONEMAPPING_GI_DIFFUSE_ATTEN)
|
||
inline half3 ApplyToneMappingGIDiffuseAtten(half3 col)
|
||
{
|
||
return col * 1;
|
||
}
|
||
#endif
|
||
|
||
inline half3 SGameOutputTonemapping(half3 col)
|
||
{
|
||
half3 output = col;
|
||
return output;
|
||
}
|
||
inline half SGameShadowAtten(half atten)
|
||
{
|
||
return max(atten, 0.2);
|
||
}
|
||
|
||
inline half SGameStylizedAtten(half atten)
|
||
{
|
||
half stylizedAtten = (atten + 1) * 0.5;
|
||
stylizedAtten = saturate(stylizedAtten);
|
||
return stylizedAtten;
|
||
}
|
||
///////////////////////////////////////////////////////////////////////////////////////////
|
||
inline half3 EnvBRDFApprox(half3 specularColor, half roughness, half NDotV)
|
||
{
|
||
half4 c0 = half4(-1, -0.0275, -0.572, 0.022);
|
||
half4 c1 = half4(1, 0.0425, 1.04, -0.04);
|
||
half4 r = roughness*c0 + c1;
|
||
half a004 = min(r.x * r.x, exp2(-9.28 * NDotV)) * r.x + r.y;
|
||
half2 AB = half2(-1.04,1.04) * a004 + r.zw;
|
||
return specularColor*AB.x + AB.y;
|
||
}
|
||
inline half3 SGameGISpecular(half roughness, half3 normal, half3 viewDir, UnityIndirect gi, half giIntensity = 1, half smoothness = 1)
|
||
{
|
||
return 1;
|
||
}
|
||
inline half3 SGameDiffuseColor( half3 diffColor, half3 specColor )
|
||
{
|
||
half3 diffuseColor = diffColor;
|
||
return diffuseColor;
|
||
}
|
||
|
||
inline half3 SGameSpecularColor( half3 specColor )
|
||
{
|
||
return specColor;
|
||
}
|
||
|
||
inline half3 SGameStylizedSpecularColor( half3 specularColor, half metallic )
|
||
{
|
||
half3 linearSpecularColor = specularColor * specularColor;
|
||
specularColor = lerp( linearSpecularColor, specularColor, metallic );
|
||
return specularColor;
|
||
}
|
||
inline half SGameDirectSpecular(half3 normal, half3 viewDir, half NDotL, half metallic, half nh, half lh)
|
||
{
|
||
half3 backfaceLightDir = viewDir;
|
||
half3 backfaceHalfDir = viewDir;
|
||
half backface_nh = saturate(dot(normal, backfaceHalfDir));
|
||
half backface_lh = saturate(dot(backfaceLightDir, backfaceHalfDir));
|
||
half notBackface = smoothstep(-1,0.5,NDotL); //0背光 -> 1受光
|
||
half isBackface = 1 - smoothstep(-1,0.5,NDotL);
|
||
half ratio = isBackface * lerp(0.3,1,metallic);
|
||
nh = lerp(nh, backface_nh, ratio);
|
||
lh = lerp(lh, backface_lh, ratio);
|
||
return isBackface;
|
||
}
|
||
inline half SGameRoughness(half smoothness, out half perceptualRoughness )
|
||
{
|
||
perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness (smoothness);
|
||
perceptualRoughness = max(0.001, perceptualRoughness);
|
||
half roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
|
||
return roughness;
|
||
}
|
||
|
||
#if defined(_SKIN_CALCULATION)
|
||
inline float FresnelReflectance (float3 H, float3 V, float F0)
|
||
{
|
||
float base = 1.0 - dot(V, H);
|
||
float exponential = pow(base, 5.0);
|
||
return exponential + F0 * saturate(1.0 - exponential);
|
||
}
|
||
inline float SkinSpecular( float3 N, // Bumped surface normal
|
||
float3 L, // Points to light
|
||
float3 V, // Points to eye
|
||
float m, // Roughness
|
||
float rho_s // Specular brightness
|
||
)
|
||
{
|
||
float ndotl = max(dot(N, L), 0);
|
||
|
||
float3 h = L + V; // Unnormalized half-way vector
|
||
float3 H = normalize(h);
|
||
float ndoth = dot(N, H);
|
||
|
||
float4 PH = pow(1.85, 10);
|
||
|
||
float F = FresnelReflectance(H, V, 0.028);
|
||
float frSpec = max(PH.x * F / dot(h, h), 0.0);
|
||
|
||
return ndotl * rho_s * frSpec;
|
||
}
|
||
#endif
|
||
|
||
//-------------------------------------------------------------------------------------
|
||
// Note: BRDF entry points use smoothness and oneMinusReflectivity for optimization
|
||
// purposes, mostly for DX9 SM2.0 level. Most of the math is being done on these (1-x) values, and that saves
|
||
// a few precious ALU slots.
|
||
// Based on Minimalist CookTorrance BRDF
|
||
// Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255
|
||
//
|
||
// * NDF (depending on UNITY_BRDF_GGX):
|
||
// a) BlinnPhong
|
||
// b) [Modified] GGX
|
||
// * Modified Kelemen and Szirmay-Kalos for Visibility term
|
||
// * Fresnel approximated with 1/LdotH
|
||
half4 SGame_BRDF2_Unity_PBS (half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,
|
||
half3 normal, half3 viewDir, UnityLight light, UnityIndirect gi, half atten, half metallic,
|
||
half3 worldTangent = half3(0, 0, 0), half isSkin = 0, half anisotrophic = 0)
|
||
{
|
||
half3 halfDir = normalize (light.dir + viewDir);
|
||
half NDotL = dot(normal,light.dir);
|
||
half nl = saturate((dot(normal, light.dir) + _DiffuseWrap) / ((1 + _DiffuseWrap) * (1 + _DiffuseWrap)));
|
||
half nh = saturate(dot(normal, halfDir));
|
||
half NDotV = dot(normal, viewDir);
|
||
half nv = saturate(NDotV);
|
||
half lh = saturate(dot(light.dir, halfDir));
|
||
|
||
#if defined(_ANISOGGX_ON) && defined(UNITY_PASS_FORWARDBASE)
|
||
smoothness = smoothness + (_AnisotrophicSmooth) * anisotrophic;
|
||
metallic = metallic + (_AnisotrophicMetallic) * anisotrophic;
|
||
#endif
|
||
|
||
half perceptualRoughness = 0;
|
||
half roughness = SGameRoughness(smoothness, /*out*/ perceptualRoughness);
|
||
half isBackface = SGameDirectSpecular(normal, viewDir, NDotL, metallic, /*inout*/ nh, /*inout*/ lh);
|
||
half a = roughness;
|
||
half a2 = a * a;
|
||
half d = nh * nh * (a2 - 1.h) + 1.00001h;
|
||
half specularTerm = a / (max(0.32h, lh) * (1.5h + roughness) * d);
|
||
#if defined(_ANISOGGX_ON) && defined(UNITY_PASS_FORWARDBASE)
|
||
half3 worldBiTangent = cross(normal, worldTangent);
|
||
worldTangent = cross(worldBiTangent, normal);
|
||
half roughnessT = SGameRoughness(smoothness, /*out*/ perceptualRoughness);;
|
||
half roughnessB = 1;
|
||
half anisoSpecularTerm = GGXSpecularTermAniso_SGame(worldTangent, worldBiTangent, roughnessT, roughnessB, halfDir, light.dir, viewDir, nl, nh, nv);
|
||
specularTerm = lerp(specularTerm, anisoSpecularTerm, anisotrophic);
|
||
#endif
|
||
#if defined (SHADER_API_MOBILE)
|
||
specularTerm = specularTerm - 1e-4h;
|
||
#endif
|
||
#if defined (SHADER_API_MOBILE)
|
||
specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
|
||
#endif
|
||
#ifdef UNITY_COLORSPACE_GAMMA
|
||
half surfaceReduction = 0.28;
|
||
#else
|
||
half surfaceReduction = (0.6 - 0.08 * perceptualRoughness);
|
||
#endif
|
||
surfaceReduction = 1.0 - roughness * perceptualRoughness * surfaceReduction;
|
||
|
||
//--------------------------------------------------------------------------------
|
||
//基础
|
||
//--------------------------------------------------------------------------------
|
||
half shadowAtten = SGameShadowAtten(atten);
|
||
half stylizedAtten = SGameStylizedAtten(atten);
|
||
half3 lightColor = light.color;
|
||
lightColor *= shadowAtten;
|
||
half3 lightDir = light.dir; //光照方向
|
||
//--------------------------------------------------------------------------------
|
||
//处理漫反射和高光颜色
|
||
//--------------------------------------------------------------------------------
|
||
half3 diffuseColor = SGameDiffuseColor(diffColor, specColor);
|
||
half3 specularColor = SGameSpecularColor(specColor);
|
||
#if defined(UNITY_PASS_FORWARDBASE)
|
||
half3 stylizedSpecularColor = SGameStylizedSpecularColor(specularColor, metallic);
|
||
#endif
|
||
|
||
//--------------------------------------------------------------------------------
|
||
//直接光照漫反射
|
||
//--------------------------------------------------------------------------------
|
||
half3 diffuseTerm = nl;
|
||
#if defined(_SKIN_CALCULATION)
|
||
diffuseTerm = lerp(diffuseTerm, BeckmannTexCol(half2(nl * 0.5 + 0.5, 1)).rgb * 1.5, isSkin);
|
||
lightColor = lerp(lightColor, lerp(lightColor, 1, 0.5), isSkin);
|
||
#endif
|
||
|
||
//直接光照漫反射
|
||
half3 diffuseLighting = diffuseColor * diffuseTerm * lightColor;
|
||
#if defined(_SKIN_CALCULATION)
|
||
float specularWeight = SkinSpecular(normal, lightDir, viewDir, _SkinRoughness, _SkinSpecIntensity * isSkin);
|
||
#if defined(BACK_FACE_ADD)
|
||
specularColor += lerp(specularColor, specularWeight * lightColor * _Color.rgb, isSkin) * 0.5;
|
||
#else
|
||
specularColor = lerp(specularColor, specularWeight * lightColor * _Color.rgb, isSkin);
|
||
#endif
|
||
#endif
|
||
|
||
//--------------------------------------------------------------------------------
|
||
//直接光照高光
|
||
//--------------------------------------------------------------------------------
|
||
half3 specDiffuseTerm = nl;
|
||
half3 specularLighting = specularTerm * specDiffuseTerm * lightColor;
|
||
#if defined(UNITY_PASS_FORWARDBASE)
|
||
specularLighting *= stylizedSpecularColor;
|
||
#else
|
||
specularLighting *= specularColor;
|
||
#endif
|
||
|
||
//--------------------------------------------------------------------------------
|
||
//间接光照漫反射
|
||
//--------------------------------------------------------------------------------
|
||
#if defined(UNITY_PASS_FORWARDBASE)
|
||
half3 diffuseIndirect = gi.diffuse * diffColor;
|
||
#endif
|
||
|
||
//--------------------------------------------------------------------------------
|
||
//间接光照高光
|
||
//--------------------------------------------------------------------------------
|
||
#if defined(UNITY_PASS_FORWARDBASE)
|
||
half giRoughness = perceptualRoughness;
|
||
half3 giSpec = SGameGISpecular(giRoughness, normal, viewDir, gi, _IBLInensity, smoothness);
|
||
#if defined(_SKIN_CALCULATION)
|
||
giSpec = lerp(giSpec, 1, isSkin);
|
||
#endif
|
||
half3 giSpecularColor = stylizedSpecularColor;
|
||
half3 specularIndirect = surfaceReduction * giSpec * giSpecularColor;
|
||
specularIndirect *= stylizedAtten;
|
||
#endif
|
||
|
||
//--------------------------------------------------------------------------------
|
||
//虚拟光
|
||
//--------------------------------------------------------------------------------
|
||
//VLight, 只有Base Pass计算
|
||
#if defined(UNITY_PASS_FORWARDBASE)
|
||
half3 vDiffuseTerm = SGameVLightDiffuse(normal) * stylizedAtten;
|
||
half3 diffuseVLight = vDiffuseTerm * diffuseColor;
|
||
half3 specularVLight = SGameVLightSpecular(perceptualRoughness, normal, viewDir, specularColor, vDiffuseTerm);
|
||
#if defined(_SKIN_CALCULATION)
|
||
#if defined(BACK_FACE_ADD)
|
||
diffuseVLight += diffuseVLight * isSkin;
|
||
specularVLight += specularVLight * 3 * isSkin;
|
||
#else
|
||
specularVLight += specularVLight * 5 * isSkin;
|
||
#endif
|
||
#endif
|
||
#endif
|
||
|
||
//计算结果颜色
|
||
half3 output = 0;
|
||
//--------------------------------------------------------------------------------
|
||
// Add Pass 直接返回直接光照
|
||
//--------------------------------------------------------------------------------
|
||
#if defined(UNITY_PASS_FORWARDADD)
|
||
output = diffuseLighting + specularLighting;
|
||
return half4(output, 1);
|
||
#endif
|
||
|
||
//--------------------------------------------------------------------------------
|
||
// Base Pass 根据不同风格计算
|
||
//--------------------------------------------------------------------------------
|
||
#if defined(UNITY_PASS_FORWARDBASE)
|
||
diffuseIndirect = ApplyToneMappingGIDiffuseAtten(diffuseIndirect); //对漫反射进行ToneMapping
|
||
half3 outputDiffuse = BlendMode_Screen(saturate(diffuseVLight), saturate(diffuseIndirect)); //补光和环境光
|
||
diffuseLighting = ApplyToneMappingLightBoost(diffuseLighting, lightColor);//主光
|
||
outputDiffuse = outputDiffuse + diffuseLighting;
|
||
outputDiffuse = SGameOutputTonemapping(outputDiffuse); //ToneMaping
|
||
half3 outputSpecular = specularLighting + specularIndirect; //对高光直接相加
|
||
outputSpecular += specularVLight * (1 + _SpecularBloomAdd * metallic);
|
||
output = outputDiffuse + outputSpecular;
|
||
half3 overflow = saturate(outputSpecular - 1);
|
||
output += overflow;
|
||
return half4(output,1);
|
||
#endif
|
||
|
||
//--------------------------------------------------------------------------------
|
||
// 其他 Pass 根据不同风格计算
|
||
//--------------------------------------------------------------------------------
|
||
output = diffuseLighting + specularLighting;
|
||
#if defined(UNITY_PASS_FORWARDBASE)
|
||
output += ( diffuseIndirect + specularIndirect);
|
||
#endif
|
||
return half4(output, 1);
|
||
}
|
||
|
||
inline half3 GetSpecularColorGGX_Smoothness (half ndotH, half ndotL, half ldotH, half3 specularColor, half smoothness, half powFac = 64, half ggxClamp = 3)
|
||
{
|
||
half3 specular = 0;
|
||
#if defined(SGAME_QUALITY_PERFECT)
|
||
half perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness (smoothness);
|
||
perceptualRoughness = max(0.08, perceptualRoughness);
|
||
half roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
|
||
half a = roughness;
|
||
half a2 = a * a;
|
||
half d = ndotH * ndotH * (a2 - 1) + 1.0001;
|
||
half specularTerm = a2 / (max(0.2, ldotH * ldotH) * (roughness + 0.5) * (d * d) * powFac);
|
||
specularTerm = specularTerm - 1e-4h;
|
||
specularTerm = clamp(specularTerm, 0, ggxClamp);
|
||
specular = specularTerm * specularColor.rgb;
|
||
#endif
|
||
return specular;
|
||
}
|
||
|
||
inline half3x3 GetDiffuseColor(half smoothness, half3 specularColor, half3 mainColor,
|
||
half3 worldNormal, half lightAtten, half3 NDotL)
|
||
{
|
||
half3 lightColor = lerp(half3(0,0,0), GetMainLight().color.rgb, lightAtten * NDotL);
|
||
specularColor = lerp(half3(0,0,0), GetMainLight().color.rgb, lightAtten) * specularColor;
|
||
|
||
half3 diffuse = mainColor * lightColor;
|
||
#if defined(SGAME_WET)
|
||
mainColor = lerp(mainColor, mainColor * _SG_WetColor, _SG_WetFactor);
|
||
specularColor = lerp(specularColor, _SG_WetSpecularColor * _SG_WetSpecularStrength, _SG_WetFactor);
|
||
smoothness = lerp(lerp(smoothness, _SG_WetSmoothness, _SG_WetFactor), smoothness, smoothness > _SG_WetSmoothness);
|
||
half thunderNDotL = saturate(dot(worldNormal, _SG_ThunderDirection));
|
||
half3 thunderDiffuse = mainColor * lerp(half3(0, 0, 0), _SG_ThunderColor, max(lightAtten,0.1)) * thunderNDotL * _SG_ThunderStrength;
|
||
diffuse += thunderDiffuse;
|
||
#endif
|
||
|
||
half3x3 matrixColor;
|
||
matrixColor[0] = diffuse;
|
||
matrixColor[1] = specularColor;
|
||
matrixColor[2] = half3(smoothness, 0, 0);
|
||
return matrixColor;
|
||
}
|
||
|
||
inline half3 GetSumLightingColorSpecGGX_Smoothness(half3 mainColor, half3 specularColor, half3 shLight,
|
||
half3 worldNormal, half3 worldPos, half smoothness, half lightAtten, half powFac = 64, half ggxClamp = 3, half intensity = 1)
|
||
{
|
||
half3 worldViewDir = normalize(GetCameraPositionWS() - worldPos);
|
||
half3 worldLightDir = normalize(GetMainLight().direction);
|
||
half3 halfDir = normalize(worldLightDir + worldViewDir);
|
||
half ndotH = max(dot(worldNormal, halfDir), 0);
|
||
half NDotL = max(dot(worldNormal, worldLightDir), 0);
|
||
half ldotH = max(dot(worldLightDir, halfDir), 0);
|
||
|
||
half3x3 colorMatrix = GetDiffuseColor(smoothness, specularColor, mainColor, worldNormal, lightAtten, NDotL);
|
||
specularColor = colorMatrix[1];
|
||
smoothness = colorMatrix[2].x;
|
||
|
||
half3 ambient = mainColor * 0.5;
|
||
half3 diffuse = colorMatrix[0];
|
||
half3 specular = GetSpecularColorGGX_Smoothness(ndotH, NDotL, ldotH, specularColor, smoothness, powFac, ggxClamp);
|
||
return ambient + diffuse + specular * intensity;
|
||
}
|
||
#endif |