Lux_Lighting_Skin.hlsl 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. #ifndef LIGHTWEIGHT_SKINLIGHTING_INCLUDED
  2. #define LIGHTWEIGHT_SKINLIGHTING_INCLUDED
  3. #if !defined(SHADERGRAPH_PREVIEW) || defined(LIGHTWEIGHT_LIGHTING_INCLUDED)
  4. // As we do not have access to the vertex lights we will make the shader always sample add lights per pixel
  5. #if defined(_ADDITIONAL_LIGHTS_VERTEX)
  6. #undef _ADDITIONAL_LIGHTS_VERTEX
  7. #define _ADDITIONAL_LIGHTS
  8. #endif
  9. #endif
  10. //TEXTURE2D(_SkinLUT); SAMPLER(sampler_SkinLUT); float4 _SkinLUT_TexelSize;
  11. #if !defined(SHADERGRAPH_PREVIEW) || defined(LIGHTWEIGHT_LIGHTING_INCLUDED)
  12. half3 DirectBDRF_Lux(BRDFData brdfData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS)
  13. {
  14. #ifndef _SPECULARHIGHLIGHTS_OFF
  15. float3 halfDir = SafeNormalize(lightDirectionWS + viewDirectionWS);
  16. float NoH = saturate(dot(normalWS, halfDir));
  17. half LoH = saturate(dot(lightDirectionWS, halfDir));
  18. // GGX Distribution multiplied by combined approximation of Visibility and Fresnel
  19. // BRDFspec = (D * V * F) / 4.0
  20. // D = roughness² / ( NoH² * (roughness² - 1) + 1 )²
  21. // V * F = 1.0 / ( LoH² * (roughness + 0.5) )
  22. // See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course
  23. // https://community.arm.com/events/1155
  24. // Final BRDFspec = roughness² / ( NoH² * (roughness² - 1) + 1 )² * (LoH² * (roughness + 0.5) * 4.0)
  25. // We further optimize a few light invariant terms
  26. // brdfData.normalizationTerm = (roughness + 0.5) * 4.0 rewritten as roughness * 4.0 + 2.0 to a fit a MAD.
  27. float d = NoH * NoH * brdfData.roughness2MinusOne + 1.00001f;
  28. half LoH2 = LoH * LoH;
  29. half specularTerm = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm);
  30. // On platforms where half actually means something, the denominator has a risk of overflow
  31. // clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)
  32. // sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))
  33. #if defined (SHADER_API_MOBILE) || defined (SHADER_API_SWITCH)
  34. specularTerm = specularTerm - HALF_MIN;
  35. specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
  36. #endif
  37. half3 color = specularTerm * brdfData.specular; // + brdfData.diffuse;
  38. return color;
  39. #else
  40. return 0; //brdfData.diffuse;
  41. #endif
  42. }
  43. half3 GlobalIllumination_Lux(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS,
  44. half specOccluison)
  45. {
  46. half fresnelTerm = 0;
  47. half3 indirectSpecular = 0;
  48. if(specOccluison > 0) {
  49. half3 reflectVector = reflect(-viewDirectionWS, normalWS);
  50. fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS)));
  51. indirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, occlusion) * specOccluison;
  52. }
  53. half3 indirectDiffuse = bakedGI * occlusion;
  54. return EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
  55. }
  56. half3 LightingPhysicallyBasedSkin(BRDFData brdfData, half3 lightColor, half3 lightDirectionWS, half lightAttenuation, half3 normalWS, half3 viewDirectionWS, half NdotL, half NdotLUnclamped, half curvature, half skinMask)
  57. {
  58. //half3 radiance = lightColor * NdotL;
  59. half3 diffuseLighting = brdfData.diffuse * SAMPLE_TEXTURE2D_LOD(_SkinLUT, sampler_SkinLUT, float2( (NdotLUnclamped * 0.5 + 0.5), curvature), 0).rgb;
  60. diffuseLighting = lerp(brdfData.diffuse * NdotL, diffuseLighting, skinMask);
  61. return ( DirectBDRF_Lux(brdfData, normalWS, lightDirectionWS, viewDirectionWS) * NdotL + diffuseLighting ) * lightColor * lightAttenuation;
  62. }
  63. half3 LightingPhysicallyBasedSkin(BRDFData brdfData, Light light, half3 normalWS, half3 viewDirectionWS, half NdotL, half NdotLUnclamped, half curvature, half skinMask)
  64. {
  65. return LightingPhysicallyBasedSkin(brdfData, light.color, light.direction, light.distanceAttenuation * light.shadowAttenuation, normalWS, viewDirectionWS, NdotL, NdotLUnclamped, curvature, skinMask);
  66. }
  67. #endif
  68. void Lighting_half(
  69. // Base inputs
  70. half3 positionWS,
  71. half3 viewDirectionWS,
  72. // Normal inputs
  73. half3 normalWS,
  74. half3 tangentWS,
  75. half3 bitangentWS,
  76. bool enableNormalMapping,
  77. bool enableDiffuseNormalMapping,
  78. bool enableBackScattering,
  79. bool useVertexNormal,
  80. // Surface description
  81. half3 albedo,
  82. half metallic,
  83. half3 specular,
  84. half smoothness,
  85. half occlusion,
  86. half3 emission,
  87. half alpha,
  88. half4 translucency,
  89. half AmbientReflection,
  90. half3 subsurfaceColor,
  91. half curvature,
  92. half skinMask,
  93. half maskbyshadowstrength,
  94. half backScattering,
  95. Texture2D normalMap,
  96. SamplerState sampler_Normal,
  97. float2 UV,
  98. float bumpScale,
  99. float diffuseBias,
  100. // Lightmapping
  101. float2 lightMapUV,
  102. // Final lit color
  103. out half3 MetaAlbedo,
  104. out half3 FinalLighting,
  105. out half3 MetaSpecular
  106. )
  107. {
  108. #if defined(SHADERGRAPH_PREVIEW) || ( !defined(LIGHTWEIGHT_LIGHTING_INCLUDED) && !defined(UNIVERSAL_LIGHTING_INCLUDED) )
  109. FinalLighting = albedo;
  110. MetaAlbedo = half3(0,0,0);
  111. MetaSpecular = half3(0,0,0);
  112. #else
  113. half3 diffuseNormalWS;
  114. if (enableNormalMapping) {
  115. half3x3 ToW = half3x3(tangentWS.xyz, bitangentWS.xyz, normalWS.xyz);
  116. half4 sampleNormal = SAMPLE_TEXTURE2D(normalMap, sampler_Normal, UV);
  117. half3 normalTS = UnpackNormalScale(sampleNormal, bumpScale);
  118. // Get specular normal
  119. half3 snormalWS = TransformTangentToWorld(normalTS, ToW);
  120. snormalWS = NormalizeNormalPerPixel(snormalWS);
  121. // Get diffuse normal
  122. if(enableDiffuseNormalMapping) {
  123. half4 sampleNormalDiffuse = SAMPLE_TEXTURE2D_BIAS(normalMap, sampler_Normal, UV, diffuseBias);
  124. // Do not manually unpack the normal map as it might use RGB.
  125. half3 diffuseNormalTS = UnpackNormal(sampleNormalDiffuse);
  126. // Get diffuseNormalWS
  127. diffuseNormalWS = TransformTangentToWorld(diffuseNormalTS, ToW);
  128. diffuseNormalWS = NormalizeNormalPerPixel(diffuseNormalWS);
  129. }
  130. else {
  131. diffuseNormalWS = (useVertexNormal) ? normalWS : snormalWS;
  132. }
  133. // Set specular normal
  134. normalWS = snormalWS;
  135. }
  136. else {
  137. normalWS = NormalizeNormalPerPixel(normalWS);
  138. diffuseNormalWS = normalWS;
  139. }
  140. viewDirectionWS = SafeNormalize(viewDirectionWS);
  141. // GI Lighting
  142. half3 bakedGI;
  143. #ifdef LIGHTMAP_ON
  144. lightMapUV = lightMapUV * unity_LightmapST.xy + unity_LightmapST.zw;
  145. bakedGI = SAMPLE_GI(lightMapUV, half3(0,0,0), diffuseNormalWS);
  146. #else
  147. bakedGI = SampleSH(diffuseNormalWS);
  148. #endif
  149. BRDFData brdfData;
  150. InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData);
  151. float4 clipPos = TransformWorldToHClip(positionWS);
  152. // Get Shadow Sampling Coords
  153. #if SHADOWS_SCREEN
  154. float4 shadowCoord = ComputeScreenPos(clipPos);
  155. #else
  156. float4 shadowCoord = TransformWorldToShadowCoord(positionWS);
  157. #endif
  158. Light mainLight = GetMainLight(shadowCoord);
  159. half3 mainLightColor = mainLight.color;
  160. // SSAO
  161. #if defined(_SCREEN_SPACE_OCCLUSION)
  162. float4 ndc = clipPos * 0.5f;
  163. float2 normalized = float2(ndc.x, ndc.y * _ProjectionParams.x) + ndc.w;
  164. normalized /= clipPos.w;
  165. normalized *= _ScreenParams.xy;
  166. // We could also use IN.Screenpos(default) --> ( IN.Screenpos.xy * _ScreenParams.xy)
  167. // HDRP 10.1
  168. normalized = GetNormalizedScreenSpaceUV(normalized);
  169. AmbientOcclusionFactor aoFactor = GetScreenSpaceAmbientOcclusion(normalized);
  170. mainLight.color *= aoFactor.directAmbientOcclusion;
  171. occlusion = min(occlusion, aoFactor.indirectAmbientOcclusion);
  172. #endif
  173. FinalLighting = GlobalIllumination_Lux(brdfData, bakedGI, occlusion, normalWS, viewDirectionWS, AmbientReflection);
  174. // Backscattering
  175. if (enableBackScattering) {
  176. FinalLighting += backScattering * SampleSH(-diffuseNormalWS) * albedo * occlusion * translucency.x * subsurfaceColor * skinMask;
  177. }
  178. MixRealtimeAndBakedGI(mainLight, normalWS, bakedGI, half4(0, 0, 0, 0));
  179. half NdotLUnclamped = dot(diffuseNormalWS, mainLight.direction);
  180. half NdotL = saturate( dot(normalWS, mainLight.direction) );
  181. FinalLighting += LightingPhysicallyBasedSkin(brdfData, mainLight, normalWS, viewDirectionWS, NdotL, NdotLUnclamped, curvature, skinMask);
  182. // Subsurface Scattering
  183. half transPower = translucency.y;
  184. half3 transLightDir = mainLight.direction + normalWS * translucency.w;
  185. half transDot = dot( transLightDir, -viewDirectionWS );
  186. transDot = exp2(saturate(transDot) * transPower - transPower);
  187. FinalLighting += skinMask * subsurfaceColor * transDot * (1.0 - saturate(NdotLUnclamped)) * mainLightColor * lerp(1.0h, mainLight.shadowAttenuation, translucency.z) * translucency.x;
  188. // URP 10
  189. half4 shadowMask = half4(1, 1, 1, 1);
  190. #ifdef _ADDITIONAL_LIGHTS
  191. uint pixelLightCount = GetAdditionalLightsCount();
  192. for (uint i = 0u; i < pixelLightCount; ++i)
  193. {
  194. //Light light = GetAdditionalLight(i, inputData.positionWS);
  195. // Get index upfront as we need it for GetAdditionalLightShadowParams();
  196. int index = GetPerObjectLightIndex(i);
  197. // Light light = GetAdditionalPerObjectLight(index, positionWS); // here; shadowAttenuation = 1.0;
  198. // URP 10: We have to use the new GetAdditionalLight function
  199. Light light = GetAdditionalLight(i, positionWS, shadowMask);
  200. half3 lightColor = light.color;
  201. #if defined(_SCREEN_SPACE_OCCLUSION)
  202. light.color *= aoFactor.directAmbientOcclusion;
  203. #endif
  204. half NdotLUnclamped = dot(diffuseNormalWS, light.direction);
  205. NdotL = saturate( dot(normalWS, light.direction) );
  206. FinalLighting += LightingPhysicallyBasedSkin(brdfData, light, normalWS, viewDirectionWS, NdotL, NdotLUnclamped, curvature, skinMask);
  207. // Transmission
  208. half4 shadowParams = GetAdditionalLightShadowParams(index);
  209. lightColor *= lerp(1, shadowParams.x, maskbyshadowstrength); // shadowParams.x == shadow strength, which is 0 for point lights
  210. transLightDir = light.direction + normalWS * translucency.w;
  211. transDot = dot( transLightDir, -viewDirectionWS );
  212. transDot = exp2(saturate(transDot) * transPower - transPower);
  213. FinalLighting += skinMask * subsurfaceColor * transDot * (1.0 - NdotL) * lightColor * lerp(1.0h, light.shadowAttenuation, translucency.z) * light.distanceAttenuation * translucency.x;
  214. }
  215. #endif
  216. #ifdef _ADDITIONAL_LIGHTS_VERTEX
  217. // FinalLighting += inputData.vertexLighting * brdfData.diffuse;
  218. #endif
  219. FinalLighting += emission;
  220. // Set Albedo for meta pass
  221. #if defined(LIGHTWEIGHT_META_PASS_INCLUDED) || defined(UNIVERSAL_META_PASS_INCLUDED)
  222. FinalLighting = half3(0,0,0);
  223. MetaAlbedo = albedo;
  224. MetaSpecular = specular;
  225. #else
  226. MetaAlbedo = half3(0,0,0);
  227. MetaSpecular = half3(0,0,0);
  228. #endif
  229. #endif
  230. }
  231. // Unity 2019.1. needs a float version
  232. void Lighting_float(
  233. // Base inputs
  234. half3 positionWS,
  235. half3 viewDirectionWS,
  236. // Normal inputs
  237. half3 normalWS,
  238. half3 tangentWS,
  239. half3 bitangentWS,
  240. bool enableNormalMapping,
  241. bool enableDiffuseNormalMapping,
  242. bool enableBackScattering,
  243. bool useVertexNormal,
  244. // Surface description
  245. half3 albedo,
  246. half metallic,
  247. half3 specular,
  248. half smoothness,
  249. half occlusion,
  250. half3 emission,
  251. half alpha,
  252. half4 translucency,
  253. half AmbientReflection,
  254. half3 subsurfaceColor,
  255. half curvature,
  256. half skinMask,
  257. half maskbyshadowstrength,
  258. half backScattering,
  259. Texture2D normalMap,
  260. SamplerState sampler_Normal,
  261. float2 UV,
  262. float bumpScale,
  263. float diffuseBias,
  264. // Lightmapping
  265. float2 lightMapUV,
  266. // Final lit color
  267. out half3 MetaAlbedo,
  268. out half3 FinalLighting,
  269. out half3 MetaSpecular
  270. )
  271. {
  272. Lighting_half(
  273. positionWS, viewDirectionWS, normalWS, tangentWS, bitangentWS, enableNormalMapping, enableDiffuseNormalMapping, enableBackScattering, useVertexNormal,
  274. albedo, metallic, specular, smoothness, occlusion, emission, alpha,
  275. translucency, AmbientReflection, subsurfaceColor, curvature, skinMask, maskbyshadowstrength,
  276. backScattering,
  277. normalMap, sampler_Normal, UV, bumpScale, diffuseBias,
  278. lightMapUV,
  279. MetaAlbedo, FinalLighting, MetaSpecular
  280. );
  281. }
  282. #endif