// SPDX-License-Identifier: (Not available for this version, you are only allowed to use this software if you have express permission from the copyright holder and agreed to the latest NiloToonURP EULA) // Copyright (c) 2021 Kuroneko ShaderLab Limited #pragma once #if _GENERIC_REFLECTION half3 BlendGenericReflectionColor(half3 dstCol, half3 srcCol, half3 srcA, uint blendMode) { half3 add = dstCol + srcCol; half3 mul = dstCol * srcCol; half3 outCol = dstCol; if (blendMode == 0) outCol = srcCol; else if (blendMode == 1) outCol = add; else if (blendMode == 2) outCol = max(add - mul, dstCol); else if (blendMode == 3) outCol = mul; return lerp(dstCol, outCol, srcA); } half GenericReflectionTooningScale(half value, half border, half blur) { half borderMin = saturate(border - blur * 0.5h); half borderMax = saturate(border + blur * 0.5h); return saturate((value - borderMin) / saturate(borderMax - borderMin + fwidth(value) * _lilAAStrength)); } void GenericReflectionGSAAForSmoothness(inout half smoothness, half3 normalWS, half strength) { float3 dx = abs(ddx(normalWS)); float3 dy = abs(ddy(normalWS)); float dxy = max(dot(dx, dx), dot(dy, dy)); float roughnessGSAA = dxy / (dxy * 5.0 + 0.002) * strength; smoothness = min(smoothness, saturate(1.0h - roughnessGSAA)); } half3 GenericReflectionFresnelTerm(half3 f0, half cosA) { half a = 1.0h - cosA; half a5 = a * a * a * a * a; return f0 + (1.0h - f0) * a5; } half3 GenericReflectionFresnelLerp(half3 f0, half3 f90, half cosA) { half a = 1.0h - cosA; half a5 = a * a * a * a * a; return lerp(f0, f90, a5); } half3 DecodeGenericReflectionCubemap(half4 data) { half alpha = _GenericReflectionCubemap_HDR.w * (data.a - 1.0h) + 1.0h; #if defined(UNITY_COLORSPACE_GAMMA) return (_GenericReflectionCubemap_HDR.x * alpha) * data.rgb; #elif defined(UNITY_USE_NATIVE_HDR) return _GenericReflectionCubemap_HDR.x * data.rgb; #else return (_GenericReflectionCubemap_HDR.x * pow(abs(alpha), _GenericReflectionCubemap_HDR.y)) * data.rgb; #endif } half3 SampleGenericReflectionCubemap(half3 reflectVector, half perceptualRoughness) { half mip = perceptualRoughness * (10.2h - 4.2h * perceptualRoughness); half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD( _GenericReflectionCubemap, sampler_linear_repeat, reflectVector, mip)); return DecodeGenericReflectionCubemap(encodedIrradiance); } half3 SampleGenericReflectionEnvironment(half3 reflectVector, half perceptualRoughness, ToonSurfaceData surfaceData, ToonLightingData lightingData) { if (_GenericReflectionCubeOverride > 0.5h) { half3 cubemapColor = SampleGenericReflectionCubemap(reflectVector, perceptualRoughness); cubemapColor *= _GenericReflectionCubeColor.rgb; cubemapColor *= lerp(1.0h.xxx, saturate(lightingData.mainLight.color), _GenericReflectionCubeEnableLighting); return cubemapColor; } #if UNITY_VERSION > 202220 return GlossyEnvironmentReflection(reflectVector, lightingData.positionWS, perceptualRoughness, surfaceData.occlusion, lightingData.normalizedScreenSpaceUV); #else return GlossyEnvironmentReflection(reflectVector, lightingData.positionWS, perceptualRoughness, surfaceData.occlusion); #endif } half3 ApplyGenericReflectionSpecular(half3 normalWS, half smoothnessRoughness, half3 specular, ToonLightingData lightingData) { half3 viewDirWS = normalize(lightingData.viewDirectionWS); half3 lightDirWS = normalize(lightingData.mainLight.direction); half3 halfDirWS = normalize(viewDirWS + lightDirWS); half NdotH = saturate(dot(normalWS, halfDirWS)); if (_GenericReflectionSpecularToon > 0.5h) { half specularArea = pow(NdotH, rcp(max(smoothnessRoughness, 0.002h))); return GenericReflectionTooningScale(specularArea, _GenericReflectionSpecularBorder, _GenericReflectionSpecularBlur).xxx; } half NdotV = saturate(dot(normalWS, viewDirWS)); half NdotL = saturate(dot(normalWS, lightDirWS)); half LdotH = saturate(dot(lightDirWS, halfDirWS)); half roughness = max(smoothnessRoughness, 0.002h); half lambdaV = NdotL * (NdotV * (1.0h - roughness) + roughness); half lambdaL = NdotV * (NdotL * (1.0h - roughness) + roughness); half roughness2 = roughness * roughness; half d = (NdotH * roughness2 - NdotH) * NdotH + 1.0h; half ggx = roughness2 / (d * d + 1e-7h); #if defined(SHADER_API_MOBILE) || defined(SHADER_API_SWITCH) half smithJointGGX = 0.5h / (lambdaV + lambdaL + 1e-4h); #else half smithJointGGX = 0.5h / (lambdaV + lambdaL + 1e-5h); #endif half specularTerm = smithJointGGX * ggx; #if defined(UNITY_COLORSPACE_GAMMA) specularTerm = sqrt(max(1e-4h, specularTerm)); #endif specularTerm *= NdotL; return specularTerm * GenericReflectionFresnelTerm(specular, LdotH); } #endif void ApplyGenericReflection(inout half3 color, ToonSurfaceData surfaceData, Varyings varyings, ToonLightingData lightingData) { #if _GENERIC_REFLECTION && NiloToonForwardLitPass half3 baseNormalWS = normalize(lightingData.normalWS); half smoothness = saturate(_GenericReflectionSmoothness * SAMPLE_TEXTURE2D( _GenericReflectionSmoothnessMap, sampler_linear_repeat, CalcUV(GetUV(varyings), _GenericReflectionSmoothnessMap_ST)).r); GenericReflectionGSAAForSmoothness(smoothness, baseNormalWS, _GenericReflectionGSAAStrength); half perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness); half roughness = perceptualRoughness * perceptualRoughness; half4 colorMask = SAMPLE_TEXTURE2D( _GenericReflectionColorMaskMap, sampler_linear_repeat, CalcUV(GetUV(varyings), _GenericReflectionColorMaskMap_ST)); half4 reflectionColor = _GenericReflectionColor * colorMask; half reflectionAlpha = _GenericReflectionBlend * reflectionColor.a; if (_GenericReflectionApplyTransparency > 0.5h) { reflectionAlpha *= surfaceData.alpha; } half metallicMask = SAMPLE_TEXTURE2D( _GenericReflectionMetallicMap, sampler_linear_repeat, CalcUV(GetUV(varyings), _GenericReflectionMetallicMap_ST)).r; half metallic = saturate(_GenericReflectionMetallic * metallicMask); color -= metallic * color; half3 specular = lerp(_GenericReflectionReflectance.xxx, surfaceData.albedo, metallic); if (_GenericReflectionApplySpecular > 0.5h) { half3 specularNormalWS = normalize(lerp(lightingData.normalWS_NoNormalMap, lightingData.normalWS, _GenericReflectionSpecularNormalStrength)); half3 specularReflection = ApplyGenericReflectionSpecular(specularNormalWS, roughness, specular, lightingData); color = BlendGenericReflectionColor( color, reflectionColor.rgb * saturate(lightingData.mainLight.color), specularReflection * reflectionAlpha, _GenericReflectionBlendMode); } if (_GenericReflectionApplyReflection <= 0.5h) { return; } half3 normalWS = normalize(lerp(lightingData.normalWS_NoNormalMap, lightingData.normalWS, _GenericReflectionNormalStrength)); half3 reflectionVectorWS = reflect(-lightingData.viewDirectionWS, normalWS); half3 envReflectionColor = SampleGenericReflectionEnvironment(reflectionVectorWS, perceptualRoughness, surfaceData, lightingData); half oneMinusReflectivity = 0.96h * (1.0h - metallic); half grazingTerm = saturate(smoothness + (1.0h - oneMinusReflectivity)); half surfaceReduction = 1.0h / (roughness * roughness + 1.0h); half normalNdotV = saturate(dot(normalWS, lightingData.viewDirectionWS)); half3 reflectCol = surfaceReduction * envReflectionColor * GenericReflectionFresnelLerp(specular, grazingTerm.xxx, normalNdotV); color = BlendGenericReflectionColor( color, reflectionColor.rgb, reflectCol * reflectionAlpha, _GenericReflectionBlendMode); #endif }