//修改说明 //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