Lux URP Toon Lighting.hlsl 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. // NOTE: Based on URP Lighting.hlsl which replaced some half3 with floats to avoid lighting artifacts on mobile
  2. #ifndef UNIVERSAL_TOONLIGHTING_INCLUDED
  3. #define UNIVERSAL_TOONLIGHTING_INCLUDED
  4. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
  5. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"
  6. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl"
  7. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
  8. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
  9. // Toon
  10. TEXTURE2D(_GradientMap); float4 _GradientMap_TexelSize;
  11. SAMPLER(s_point_clamp_sampler);
  12. SAMPLER(s_linear_clamp_sampler);
  13. // ///////////////////////////////////////////////////////////
  14. //
  15. // Custom functions
  16. half3 LightingSpecular_Toon (Light light, half lightingRemap, half3 normalWS, half3 viewDirectionWS, half3 specular, half specularSmoothness, half smoothness, half specularStep, half specularUpper, bool energyConservation){
  17. float3 halfVec = SafeNormalize( float3(light.direction) + float3(viewDirectionWS));
  18. half NdotH = saturate(dot(normalWS, halfVec));
  19. half modifier = pow(NdotH /* lightingRemap*/, specularSmoothness);
  20. // Normalization? Na, we just multiply by smoothness in the return statement.
  21. // #define ONEOVERTWOPI 0.159155h
  22. // half normalization = (specularSmoothness + 1) * ONEOVERTWOPI;
  23. // Sharpen
  24. half modifierSharpened = smoothstep(specularStep, specularUpper, modifier);
  25. half toonNormalization = (energyConservation == 1.0h) ? smoothness : 1;
  26. return light.color * specular * modifierSharpened * toonNormalization; // * smoothness;
  27. }
  28. half3 LightingSpecularAniso_Toon (Light light, half NdotL, half3 normalWS, half3 viewDirectionWS, half3 tangentWS, half3 bitangentWS, half anisotropy, half3 specular, half specularSmoothness, half smoothness, half specularStep, half specularUpper, bool energyConservation){
  29. // This does not let us fade from isotropic to anisotropic...
  30. // half3 H = SafeNormalize(light.direction + viewDirectionWS);
  31. // half3 T = cross(normalWS, tangent);
  32. // T = lerp(tangent, bitangent, (anisotropy + 1) * 0.5);
  33. // float TdotH = dot(T, H);
  34. // float sinTHSq = saturate(1.0 - TdotH * TdotH);
  35. // float exponent = RoughnessToBlinnPhongSpecularExponent_Lux(1 - smoothness);
  36. // float modifier = dirAttn * pow(sinTHSq, 0.5 * exponent);
  37. // float norm = smoothness; //(exponent + 2) * rcp(2 * PI);
  38. // // Sharpen
  39. // half modifierSharpened = smoothstep(specularStep, specularUpper, modifier);
  40. // half toonNormalization = (energyConservation == 1.0h) ? norm : 1;
  41. // return light.color * specular * modifierSharpened * toonNormalization;
  42. // ///////////////////////////////
  43. //
  44. // GGX "like" distribution in order to be able to fade from isotropic to anisotropic
  45. // We skip visbility here as it is toon lighting.
  46. // NOTE: Further normalization does not help here to fixe the final shape...
  47. float3 H = SafeNormalize(float3(light.direction) + float3(viewDirectionWS));
  48. // TdotH and BdotH should be unclamped here
  49. float TdotH = dot(tangentWS, H);
  50. float BdotH = dot(bitangentWS, H);
  51. float NdotH = dot(normalWS, H);
  52. float roughness = 1.0f - smoothness;
  53. // roughness^2 would be correct here - but in order to get it a bit closer to our blinn phong isotropic specular we go with ^4 instead
  54. roughness *= roughness * roughness * roughness;
  55. float at = roughness * (1.0f + anisotropy);
  56. float ab = roughness * (1.0f - anisotropy);
  57. float a2 = at * ab;
  58. float3 v = float3(ab * TdotH, at * BdotH, a2 * NdotH);
  59. float v2 = dot(v, v);
  60. float w2 = a2 / v2;
  61. half res = half(a2 * w2 * w2 * (1.0f / PI));
  62. // Sharpen
  63. half modifierSharpened = smoothstep(specularStep, specularUpper, res);
  64. half toonNormalization = (energyConservation == 1.0h) ? smoothness : 1.0h;
  65. return light.color * specular * modifierSharpened * toonNormalization;
  66. }
  67. // https://www.ronja-tutorials.com/2019/11/29/fwidth.html
  68. half aaStep(half compValue, half gradient, half softness){
  69. half change = fwidth(gradient) * softness;
  70. // Base the range of the inverse lerp on the change over two pixels
  71. half lowerEdge = compValue - change;
  72. half upperEdge = compValue + change;
  73. // Do the inverse interpolation
  74. half stepped = (gradient - lowerEdge) / (upperEdge - lowerEdge);
  75. stepped = saturate(stepped);
  76. return stepped;
  77. }
  78. half4 LuxURPToonFragmentPBR(InputData inputData,
  79. #if defined(_ANISOTROPIC) && !defined(_SPECULARHIGHLIGHTS_OFF)
  80. half3 tangentWS,
  81. half anisotropy,
  82. #endif
  83. half3 albedo, half3 shadedAlbedo,
  84. half metallic, half3 specular,
  85. half steps, half diffuseStep, half diffuseFalloff,
  86. half energyConservation, half specularStep, half specularFalloff,
  87. half mainLightAttenContribution, half addLightAttenContribution, half lightColorContribution, half addLightFalloff,
  88. half shadowFalloff, half shadowBiasDirectional, half shadowBiasAdditional,
  89. half3 toonRimColor, half toonRimPower, half toonRimFallOff, half toonRimAttenuation,
  90. half smoothness, half occlusion, half3 emission, half alpha
  91. )
  92. {
  93. BRDFData brdfData;
  94. // We can't use our specular here as it can be anything. So we simply use the default dielectric value here.
  95. InitializeBRDFData(albedo, metallic, kDieletricSpec.rgb, smoothness, alpha, brdfData);
  96. // ShadowMask: To ensure backward compatibility we have to avoid using shadowMask input, as it is not present in older shaders
  97. #if defined(SHADOWS_SHADOWMASK) && defined(LIGHTMAP_ON)
  98. half4 shadowMask = inputData.shadowMask;
  99. #elif !defined (LIGHTMAP_ON)
  100. half4 shadowMask = unity_ProbesOcclusion;
  101. #else
  102. half4 shadowMask = half4(1, 1, 1, 1);
  103. #endif
  104. //Light mainLight = GetMainLight(inputData.shadowCoord);
  105. Light mainLight = GetMainLight(inputData.shadowCoord, inputData.positionWS, shadowMask);
  106. // SSAO
  107. #if defined(_SCREEN_SPACE_OCCLUSION)
  108. #if defined(_SSAO_ENABLED)
  109. AmbientOcclusionFactor aoFactor = GetScreenSpaceAmbientOcclusion(inputData.normalizedScreenSpaceUV);
  110. mainLight.color *= aoFactor.directAmbientOcclusion;
  111. occlusion = min(occlusion, aoFactor.indirectAmbientOcclusion);
  112. #endif
  113. #endif
  114. mainLight.shadowAttenuation = smoothstep( (1 - shadowFalloff) * shadowFalloff, shadowFalloff, mainLight.shadowAttenuation);
  115. MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));
  116. // We really do not want any reflections
  117. #if defined(_ENVIRONMENTREFLECTIONS_OFF)
  118. _GlossyEnvironmentColor.rgb = half3(0,0,0);
  119. #endif
  120. // Global Illumination
  121. half3 GI = GlobalIllumination(brdfData, inputData.bakedGI, occlusion, inputData.normalWS, inputData.viewDirectionWS);
  122. // Set up Lighting
  123. half lightIntensity = 0.0h;
  124. half3 specularLighting = 0.0h;
  125. half3 rimLighting = 0.0h;
  126. half3 lightColor = 0.0h;
  127. half luminance;
  128. // Adjust tangent and reconstruct bitangent in case anisotropic specular is active as otherwise normal mapping has no effect
  129. #if defined(_ANISOTROPIC) && !defined(_SPECULARHIGHLIGHTS_OFF)
  130. #if defined(_NORMALMAP)
  131. tangentWS = Orthonormalize(tangentWS, inputData.normalWS);
  132. #endif
  133. half3 bitangentWS = cross(inputData.normalWS, tangentWS);
  134. #endif
  135. // Main Light
  136. // Remap old diffuseStep and diffuseFalloff in order to match new function
  137. diffuseStep = diffuseStep + 1.0h;
  138. diffuseFalloff = diffuseFalloff * 4.0h + 1.0h;
  139. half NdotL = dot(inputData.normalWS, mainLight.direction);
  140. NdotL = saturate((NdotL + 1.0h) - diffuseStep);
  141. #if !defined(_RAMP_SMOOTHSAMPLING) && !defined(_RAMP_POINTSAMPLING)
  142. // We have to use steps - 1 here!
  143. half oneOverSteps = 1.0h / steps;
  144. half quantizedNdotL = floor(NdotL * steps);
  145. // IMPORTANT: no saturate on the 2nd param: NdotL - 0.01. 0.01 is eyballed.
  146. NdotL = (quantizedNdotL + aaStep(saturate(quantizedNdotL * oneOverSteps), NdotL - 0.01h, diffuseFalloff )) * oneOverSteps;
  147. #else
  148. #if defined(_RAMP_SMOOTHSAMPLING)
  149. NdotL = SAMPLE_TEXTURE2D(_GradientMap, s_linear_clamp_sampler, float2 (NdotL, 0.5f)).r;
  150. #else
  151. half NdotL0 = SAMPLE_TEXTURE2D(_GradientMap, s_point_clamp_sampler, float2 (NdotL, 0.5f)).r;
  152. half NdotL1 = SAMPLE_TEXTURE2D(_GradientMap, s_point_clamp_sampler, float2 (NdotL + fwidth(NdotL) * _GradientMap_TexelSize.x, 0.5f)).r;
  153. NdotL = (NdotL0 + NdotL1) * 0.5h;
  154. #endif
  155. #endif
  156. half atten = NdotL * mainLight.distanceAttenuation * saturate(shadowBiasDirectional + mainLight.shadowAttenuation);
  157. mainLight.color = lerp(Luminance(mainLight.color).xxx, mainLight.color, lightColorContribution.xxx);
  158. // #if defined(_COLORIZEMAIN)
  159. // lightColor = mainLight.color * mainLight.distanceAttenuation;
  160. // #else
  161. // lightColor = mainLight.color * atten;
  162. // #endif
  163. lightColor = mainLight.color * lerp(atten, mainLight.distanceAttenuation, mainLightAttenContribution);
  164. luminance = Luminance(mainLight.color);
  165. lightIntensity += luminance * atten;
  166. // Specular
  167. #if !defined(_SPECULARHIGHLIGHTS_OFF)
  168. half specularSmoothness;
  169. half3 spec;
  170. half specularUpper;
  171. specularSmoothness = exp2(10 * smoothness + 1);
  172. specularUpper = saturate(specularStep + specularFalloff * (1.0h + smoothness));
  173. #if defined(_ANISOTROPIC)
  174. spec = LightingSpecularAniso_Toon (mainLight, NdotL, inputData.normalWS, inputData.viewDirectionWS, tangentWS, bitangentWS, anisotropy, specular, specularSmoothness, smoothness, specularStep, specularUpper, energyConservation);
  175. #else
  176. spec = LightingSpecular_Toon(mainLight, NdotL, inputData.normalWS, inputData.viewDirectionWS, specular, specularSmoothness, smoothness, specularStep, specularUpper, energyConservation);
  177. #endif
  178. specularLighting = spec * atten;
  179. #endif
  180. // Rim
  181. #if defined(_TOONRIM)
  182. half rim = saturate(1.0h - saturate( dot(inputData.normalWS, inputData.viewDirectionWS)) );
  183. //rimLighting = smoothstep(rimPower, rimPower + rimFalloff, rim) * rimColor.rgb;
  184. // Stabilize rim
  185. float delta = fwidth(rim);
  186. rimLighting = smoothstep(toonRimPower - delta, toonRimPower + toonRimFallOff + delta, rim) * toonRimColor.rgb;
  187. #endif
  188. // Additional lights
  189. #ifdef _ADDITIONAL_LIGHTS
  190. uint pixelLightCount = GetAdditionalLightsCount();
  191. for (uint i = 0u; i < pixelLightCount; ++i) {
  192. Light light = GetAdditionalLight(i, inputData.positionWS);
  193. #if defined(_SCREEN_SPACE_OCCLUSION)
  194. #if defined(_SSAO_ENABLED)
  195. light.color *= aoFactor.directAmbientOcclusion;
  196. #endif
  197. #endif
  198. //light.shadowAttenuation = smoothstep(0.0h, shadowFalloff, light.shadowAttenuation);
  199. light.shadowAttenuation = smoothstep( (1.0h - shadowFalloff) * shadowFalloff, shadowFalloff, light.shadowAttenuation);
  200. NdotL = dot(inputData.normalWS, light.direction);
  201. NdotL = saturate((NdotL + 1.0h) - diffuseStep);
  202. #if !defined(_RAMP_SMOOTHSAMPLING) && !defined(_RAMP_POINTSAMPLING)
  203. half quantizedNdotL = floor(NdotL * steps);
  204. // IMPORTANT: no saturate on the 2nd param: NdotL - 0.01. 0.01 is eyballed.
  205. NdotL = (quantizedNdotL + aaStep(saturate(quantizedNdotL * oneOverSteps), NdotL - 0.01h, diffuseFalloff )) * oneOverSteps;
  206. #else
  207. #if defined(_RAMP_SMOOTHSAMPLING)
  208. NdotL = SAMPLE_TEXTURE2D(_GradientMap, s_linear_clamp_sampler, float2 (NdotL, 0.5f)).r;
  209. #else
  210. half NdotL0 = SAMPLE_TEXTURE2D(_GradientMap, s_point_clamp_sampler, float2 (NdotL, 0.5f)).r;
  211. half NdotL1 = SAMPLE_TEXTURE2D(_GradientMap, s_point_clamp_sampler, float2 (NdotL + fwidth(NdotL) * _GradientMap_TexelSize.x, 0.5f)).r;
  212. NdotL = (NdotL0 + NdotL1) * 0.5h;
  213. #endif
  214. #endif
  215. // No smoothstep here! as is totally fucks up the distanceAttenuation: It is not linear!
  216. //half distanceAttenuation = smoothstep(0, addLightFalloff, light.distanceAttenuation);
  217. half distanceAttenuation = (addLightFalloff < 1.0h) ? saturate(light.distanceAttenuation / addLightFalloff) : light.distanceAttenuation;
  218. atten = NdotL * distanceAttenuation * saturate(shadowBiasAdditional + light.shadowAttenuation);
  219. light.color = lerp(Luminance(light.color).xxx, light.color, lightColorContribution.xxx);
  220. // #if defined(_COLORIZEADD)
  221. // lightColor += light.color * light.distanceAttenuation;
  222. // #else
  223. // lightColor += light.color * atten;
  224. // #endif
  225. lightColor += light.color * lerp(atten, distanceAttenuation, addLightAttenContribution);
  226. luminance = Luminance(light.color);
  227. lightIntensity += luminance * atten;
  228. #if !defined(_SPECULARHIGHLIGHTS_OFF)
  229. #if defined(_ANISOTROPIC)
  230. spec = LightingSpecularAniso_Toon (light, NdotL, inputData.normalWS, inputData.viewDirectionWS, tangentWS, bitangentWS, anisotropy, specular, specularSmoothness, smoothness, specularStep, specularUpper, energyConservation);
  231. #else
  232. spec = LightingSpecular_Toon(light, NdotL, inputData.normalWS, inputData.viewDirectionWS, specular, specularSmoothness, smoothness, specularStep, specularUpper, energyConservation);
  233. #endif
  234. specularLighting += spec * atten;
  235. #endif
  236. }
  237. #endif
  238. // Combine Lighting
  239. half3 litAlbedo = lerp(shadedAlbedo, albedo, saturate(lightIntensity.xxx) );
  240. //lightColor = 1;
  241. half3 Lighting =
  242. // ambient diffuse lighting
  243. GI
  244. //inputData.bakedGI * albedo //litAlbedo
  245. // direct diffuse lighting
  246. + litAlbedo * lightColor
  247. // spec lighting
  248. #if !defined(_SPECULARHIGHLIGHTS_OFF)
  249. + (specularLighting * lightIntensity * lightColor)
  250. #endif
  251. // rim lighting
  252. #if defined(_TOONRIM)
  253. + rimLighting * lerp(1.0h, lightIntensity, toonRimAttenuation)
  254. #endif
  255. // old version multiplied rim with lightColor ...
  256. //#if !defined(_SPECULARHIGHLIGHTS_OFF)
  257. // )
  258. //#endif
  259. // * lightColor
  260. ;
  261. #ifdef _ADDITIONAL_LIGHTS_VERTEX
  262. Lighting += inputData.vertexLighting * albedo;
  263. #endif
  264. Lighting += emission;
  265. return half4(Lighting, alpha);
  266. }
  267. #endif