Files

389 lines
16 KiB
HLSL
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//修改说明
//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