Lighting.hlsl 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. #ifndef UNIVERSAL_LIGHTING_INCLUDED
  2. #define UNIVERSAL_LIGHTING_INCLUDED
  3. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
  4. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"
  5. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl"
  6. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
  7. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
  8. // If lightmap is not defined than we evaluate GI (ambient + probes) from SH
  9. // We might do it fully or partially in vertex to save shader ALU
  10. #if !defined(LIGHTMAP_ON)
  11. // TODO: Controls things like these by exposing SHADER_QUALITY levels (low, medium, high)
  12. #if defined(SHADER_API_GLES) || !defined(_NORMALMAP)
  13. // Evaluates SH fully in vertex
  14. #define EVALUATE_SH_VERTEX
  15. #elif !SHADER_HINT_NICE_QUALITY
  16. // Evaluates L2 SH in vertex and L0L1 in pixel
  17. #define EVALUATE_SH_MIXED
  18. #endif
  19. // Otherwise evaluate SH fully per-pixel
  20. #endif
  21. #ifdef LIGHTMAP_ON
  22. #define DECLARE_LIGHTMAP_OR_SH(lmName, shName, index) float2 lmName : TEXCOORD##index
  23. #define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT) OUT.xy = lightmapUV.xy * lightmapScaleOffset.xy + lightmapScaleOffset.zw;
  24. #define OUTPUT_SH(normalWS, OUT)
  25. #else
  26. #define DECLARE_LIGHTMAP_OR_SH(lmName, shName, index) half3 shName : TEXCOORD##index
  27. #define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT)
  28. #define OUTPUT_SH(normalWS, OUT) OUT.xyz = SampleSHVertex(normalWS)
  29. #endif
  30. ///////////////////////////////////////////////////////////////////////////////
  31. // Light Helpers //
  32. ///////////////////////////////////////////////////////////////////////////////
  33. // Abstraction over Light shading data.
  34. struct Light
  35. {
  36. half3 direction;
  37. half3 color;
  38. half distanceAttenuation;
  39. half shadowAttenuation;
  40. };
  41. ///////////////////////////////////////////////////////////////////////////////
  42. // Attenuation Functions /
  43. ///////////////////////////////////////////////////////////////////////////////
  44. // Matches Unity Vanila attenuation
  45. // Attenuation smoothly decreases to light range.
  46. float DistanceAttenuation(float distanceSqr, half2 distanceAttenuation)
  47. {
  48. // We use a shared distance attenuation for additional directional and puctual lights
  49. // for directional lights attenuation will be 1
  50. float lightAtten = rcp(distanceSqr);
  51. #if SHADER_HINT_NICE_QUALITY
  52. // Use the smoothing factor also used in the Unity lightmapper.
  53. half factor = distanceSqr * distanceAttenuation.x;
  54. half smoothFactor = saturate(1.0h - factor * factor);
  55. smoothFactor = smoothFactor * smoothFactor;
  56. #else
  57. // We need to smoothly fade attenuation to light range. We start fading linearly at 80% of light range
  58. // Therefore:
  59. // fadeDistance = (0.8 * 0.8 * lightRangeSq)
  60. // smoothFactor = (lightRangeSqr - distanceSqr) / (lightRangeSqr - fadeDistance)
  61. // We can rewrite that to fit a MAD by doing
  62. // distanceSqr * (1.0 / (fadeDistanceSqr - lightRangeSqr)) + (-lightRangeSqr / (fadeDistanceSqr - lightRangeSqr)
  63. // distanceSqr * distanceAttenuation.y + distanceAttenuation.z
  64. half smoothFactor = saturate(distanceSqr * distanceAttenuation.x + distanceAttenuation.y);
  65. #endif
  66. return lightAtten * smoothFactor;
  67. }
  68. half AngleAttenuation(half3 spotDirection, half3 lightDirection, half2 spotAttenuation)
  69. {
  70. // Spot Attenuation with a linear falloff can be defined as
  71. // (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle)
  72. // This can be rewritten as
  73. // invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle)
  74. // SdotL * invAngleRange + (-cosOuterAngle * invAngleRange)
  75. // SdotL * spotAttenuation.x + spotAttenuation.y
  76. // If we precompute the terms in a MAD instruction
  77. half SdotL = dot(spotDirection, lightDirection);
  78. half atten = saturate(SdotL * spotAttenuation.x + spotAttenuation.y);
  79. return atten * atten;
  80. }
  81. ///////////////////////////////////////////////////////////////////////////////
  82. // Light Abstraction //
  83. ///////////////////////////////////////////////////////////////////////////////
  84. Light GetMainLight()
  85. {
  86. Light light;
  87. light.direction = _MainLightPosition.xyz;
  88. // unity_LightData.z is 1 when not culled by the culling mask, otherwise 0.
  89. light.distanceAttenuation = unity_LightData.z;
  90. #if defined(LIGHTMAP_ON) || defined(_MIXED_LIGHTING_SUBTRACTIVE)
  91. // unity_ProbesOcclusion.x is the mixed light probe occlusion data
  92. light.distanceAttenuation *= unity_ProbesOcclusion.x;
  93. #endif
  94. light.shadowAttenuation = 1.0;
  95. light.color = _MainLightColor.rgb;
  96. return light;
  97. }
  98. Light GetMainLight(float4 shadowCoord)
  99. {
  100. Light light = GetMainLight();
  101. light.shadowAttenuation = MainLightRealtimeShadow(shadowCoord);
  102. return light;
  103. }
  104. // Fills a light struct given a perObjectLightIndex
  105. Light GetAdditionalPerObjectLight(int perObjectLightIndex, float3 positionWS)
  106. {
  107. // Abstraction over Light input constants
  108. #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
  109. float4 lightPositionWS = _AdditionalLightsBuffer[perObjectLightIndex].position;
  110. half3 color = _AdditionalLightsBuffer[perObjectLightIndex].color.rgb;
  111. half4 distanceAndSpotAttenuation = _AdditionalLightsBuffer[perObjectLightIndex].attenuation;
  112. half4 spotDirection = _AdditionalLightsBuffer[perObjectLightIndex].spotDirection;
  113. half4 lightOcclusionProbeInfo = _AdditionalLightsBuffer[perObjectLightIndex].occlusionProbeChannels;
  114. #else
  115. float4 lightPositionWS = _AdditionalLightsPosition[perObjectLightIndex];
  116. half3 color = _AdditionalLightsColor[perObjectLightIndex].rgb;
  117. half4 distanceAndSpotAttenuation = _AdditionalLightsAttenuation[perObjectLightIndex];
  118. half4 spotDirection = _AdditionalLightsSpotDir[perObjectLightIndex];
  119. half4 lightOcclusionProbeInfo = _AdditionalLightsOcclusionProbes[perObjectLightIndex];
  120. #endif
  121. // Directional lights store direction in lightPosition.xyz and have .w set to 0.0.
  122. // This way the following code will work for both directional and punctual lights.
  123. float3 lightVector = lightPositionWS.xyz - positionWS * lightPositionWS.w;
  124. float distanceSqr = max(dot(lightVector, lightVector), HALF_MIN);
  125. half3 lightDirection = half3(lightVector * rsqrt(distanceSqr));
  126. half attenuation = DistanceAttenuation(distanceSqr, distanceAndSpotAttenuation.xy) * AngleAttenuation(spotDirection.xyz, lightDirection, distanceAndSpotAttenuation.zw);
  127. Light light;
  128. light.direction = lightDirection;
  129. light.distanceAttenuation = attenuation;
  130. light.shadowAttenuation = AdditionalLightRealtimeShadow(perObjectLightIndex, positionWS);
  131. light.color = color;
  132. // In case we're using light probes, we can sample the attenuation from the `unity_ProbesOcclusion`
  133. #if defined(LIGHTMAP_ON) || defined(_MIXED_LIGHTING_SUBTRACTIVE)
  134. // First find the probe channel from the light.
  135. // Then sample `unity_ProbesOcclusion` for the baked occlusion.
  136. // If the light is not baked, the channel is -1, and we need to apply no occlusion.
  137. // probeChannel is the index in 'unity_ProbesOcclusion' that holds the proper occlusion value.
  138. int probeChannel = lightOcclusionProbeInfo.x;
  139. // lightProbeContribution is set to 0 if we are indeed using a probe, otherwise set to 1.
  140. half lightProbeContribution = lightOcclusionProbeInfo.y;
  141. half probeOcclusionValue = unity_ProbesOcclusion[probeChannel];
  142. light.distanceAttenuation *= max(probeOcclusionValue, lightProbeContribution);
  143. #endif
  144. return light;
  145. }
  146. uint GetPerObjectLightIndexOffset()
  147. {
  148. #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
  149. return unity_LightData.x;
  150. #else
  151. return 0;
  152. #endif
  153. }
  154. // Returns a per-object index given a loop index.
  155. // This abstract the underlying data implementation for storing lights/light indices
  156. int GetPerObjectLightIndex(uint index)
  157. {
  158. /////////////////////////////////////////////////////////////////////////////////////////////
  159. // Structured Buffer Path /
  160. // /
  161. // Lights and light indices are stored in StructuredBuffer. We can just index them. /
  162. // Currently all non-mobile platforms take this path :( /
  163. // There are limitation in mobile GPUs to use SSBO (performance / no vertex shader support) /
  164. /////////////////////////////////////////////////////////////////////////////////////////////
  165. #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
  166. uint offset = unity_LightData.x;
  167. return _AdditionalLightsIndices[offset + index];
  168. /////////////////////////////////////////////////////////////////////////////////////////////
  169. // UBO path /
  170. // /
  171. // We store 8 light indices in float4 unity_LightIndices[2]; /
  172. // Due to memory alignment unity doesn't support int[] or float[] /
  173. // Even trying to reinterpret cast the unity_LightIndices to float[] won't work /
  174. // it will cast to float4[] and create extra register pressure. :( /
  175. /////////////////////////////////////////////////////////////////////////////////////////////
  176. #elif !defined(SHADER_API_GLES)
  177. // since index is uint shader compiler will implement
  178. // div & mod as bitfield ops (shift and mask).
  179. // TODO: Can we index a float4? Currently compiler is
  180. // replacing unity_LightIndicesX[i] with a dp4 with identity matrix.
  181. // u_xlat16_40 = dot(unity_LightIndices[int(u_xlatu13)], ImmCB_0_0_0[u_xlati1]);
  182. // This increases both arithmetic and register pressure.
  183. return unity_LightIndices[index / 4][index % 4];
  184. #else
  185. // Fallback to GLES2. No bitfield magic here :(.
  186. // We limit to 4 indices per object and only sample unity_4LightIndices0.
  187. // Conditional moves are branch free even on mali-400
  188. // small arithmetic cost but no extra register pressure from ImmCB_0_0_0 matrix.
  189. half2 lightIndex2 = (index < 2.0h) ? unity_LightIndices[0].xy : unity_LightIndices[0].zw;
  190. half i_rem = (index < 2.0h) ? index : index - 2.0h;
  191. return (i_rem < 1.0h) ? lightIndex2.x : lightIndex2.y;
  192. #endif
  193. }
  194. // Fills a light struct given a loop i index. This will convert the i
  195. // index to a perObjectLightIndex
  196. Light GetAdditionalLight(uint i, float3 positionWS)
  197. {
  198. int perObjectLightIndex = GetPerObjectLightIndex(i);
  199. return GetAdditionalPerObjectLight(perObjectLightIndex, positionWS);
  200. }
  201. int GetAdditionalLightsCount()
  202. {
  203. // TODO: we need to expose in SRP api an ability for the pipeline cap the amount of lights
  204. // in the culling. This way we could do the loop branch with an uniform
  205. // This would be helpful to support baking exceeding lights in SH as well
  206. return min(_AdditionalLightsCount.x, unity_LightData.y);
  207. }
  208. ///////////////////////////////////////////////////////////////////////////////
  209. // BRDF Functions //
  210. ///////////////////////////////////////////////////////////////////////////////
  211. #define kDieletricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04) // standard dielectric reflectivity coef at incident angle (= 4%)
  212. struct BRDFData
  213. {
  214. half3 diffuse;
  215. half3 specular;
  216. half perceptualRoughness;
  217. half roughness;
  218. half roughness2;
  219. half grazingTerm;
  220. // We save some light invariant BRDF terms so we don't have to recompute
  221. // them in the light loop. Take a look at DirectBRDF function for detailed explaination.
  222. half normalizationTerm; // roughness * 4.0 + 2.0
  223. half roughness2MinusOne; // roughness^2 - 1.0
  224. };
  225. half ReflectivitySpecular(half3 specular)
  226. {
  227. #if defined(SHADER_API_GLES)
  228. return specular.r; // Red channel - because most metals are either monocrhome or with redish/yellowish tint
  229. #else
  230. return max(max(specular.r, specular.g), specular.b);
  231. #endif
  232. }
  233. half OneMinusReflectivityMetallic(half metallic)
  234. {
  235. // We'll need oneMinusReflectivity, so
  236. // 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)
  237. // store (1-dielectricSpec) in kDieletricSpec.a, then
  238. // 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
  239. // = alpha - metallic * alpha
  240. half oneMinusDielectricSpec = kDieletricSpec.a;
  241. return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
  242. }
  243. inline void InitializeBRDFData(half3 albedo, half metallic, half3 specular, half smoothness, half alpha, out BRDFData outBRDFData)
  244. {
  245. #ifdef _SPECULAR_SETUP
  246. half reflectivity = ReflectivitySpecular(specular);
  247. half oneMinusReflectivity = 1.0 - reflectivity;
  248. outBRDFData.diffuse = albedo * (half3(1.0h, 1.0h, 1.0h) - specular);
  249. outBRDFData.specular = specular;
  250. #else
  251. half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic);
  252. half reflectivity = 1.0 - oneMinusReflectivity;
  253. outBRDFData.diffuse = albedo * oneMinusReflectivity;
  254. outBRDFData.specular = lerp(kDieletricSpec.rgb, albedo, metallic);
  255. #endif
  256. outBRDFData.grazingTerm = saturate(smoothness + reflectivity);
  257. outBRDFData.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness);
  258. outBRDFData.roughness = max(PerceptualRoughnessToRoughness(outBRDFData.perceptualRoughness), HALF_MIN);
  259. outBRDFData.roughness2 = outBRDFData.roughness * outBRDFData.roughness;
  260. outBRDFData.normalizationTerm = outBRDFData.roughness * 4.0h + 2.0h;
  261. outBRDFData.roughness2MinusOne = outBRDFData.roughness2 - 1.0h;
  262. #ifdef _ALPHAPREMULTIPLY_ON
  263. outBRDFData.diffuse *= alpha;
  264. alpha = alpha * oneMinusReflectivity + reflectivity;
  265. #endif
  266. }
  267. half3 EnvironmentBRDF(BRDFData brdfData, half3 indirectDiffuse, half3 indirectSpecular, half fresnelTerm)
  268. {
  269. half3 c = indirectDiffuse * brdfData.diffuse;
  270. float surfaceReduction = 1.0 / (brdfData.roughness2 + 1.0);
  271. c += surfaceReduction * indirectSpecular * lerp(brdfData.specular, brdfData.grazingTerm, fresnelTerm);
  272. return c;
  273. }
  274. // Based on Minimalist CookTorrance BRDF
  275. // Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255
  276. //
  277. // * NDF [Modified] GGX
  278. // * Modified Kelemen and Szirmay-Kalos for Visibility term
  279. // * Fresnel approximated with 1/LdotH
  280. half3 DirectBDRF(BRDFData brdfData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS)
  281. {
  282. #ifndef _SPECULARHIGHLIGHTS_OFF
  283. float3 halfDir = SafeNormalize(float3(lightDirectionWS) + float3(viewDirectionWS));
  284. float NoH = saturate(dot(normalWS, halfDir));
  285. half LoH = saturate(dot(lightDirectionWS, halfDir));
  286. // GGX Distribution multiplied by combined approximation of Visibility and Fresnel
  287. // BRDFspec = (D * V * F) / 4.0
  288. // D = roughness^2 / ( NoH^2 * (roughness^2 - 1) + 1 )^2
  289. // V * F = 1.0 / ( LoH^2 * (roughness + 0.5) )
  290. // See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course
  291. // https://community.arm.com/events/1155
  292. // Final BRDFspec = roughness^2 / ( NoH^2 * (roughness^2 - 1) + 1 )^2 * (LoH^2 * (roughness + 0.5) * 4.0)
  293. // We further optimize a few light invariant terms
  294. // brdfData.normalizationTerm = (roughness + 0.5) * 4.0 rewritten as roughness * 4.0 + 2.0 to a fit a MAD.
  295. float d = NoH * NoH * brdfData.roughness2MinusOne + 1.00001f;
  296. half LoH2 = LoH * LoH;
  297. half specularTerm = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm);
  298. // On platforms where half actually means something, the denominator has a risk of overflow
  299. // clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)
  300. // sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))
  301. #if defined (SHADER_API_MOBILE) || defined (SHADER_API_SWITCH)
  302. specularTerm = specularTerm - HALF_MIN;
  303. specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
  304. #endif
  305. half3 color = specularTerm * brdfData.specular + brdfData.diffuse;
  306. return color;
  307. #else
  308. return brdfData.diffuse;
  309. #endif
  310. }
  311. ///////////////////////////////////////////////////////////////////////////////
  312. // Global Illumination //
  313. ///////////////////////////////////////////////////////////////////////////////
  314. // Samples SH L0, L1 and L2 terms
  315. half3 SampleSH(half3 normalWS)
  316. {
  317. // LPPV is not supported in Ligthweight Pipeline
  318. real4 SHCoefficients[7];
  319. SHCoefficients[0] = unity_SHAr;
  320. SHCoefficients[1] = unity_SHAg;
  321. SHCoefficients[2] = unity_SHAb;
  322. SHCoefficients[3] = unity_SHBr;
  323. SHCoefficients[4] = unity_SHBg;
  324. SHCoefficients[5] = unity_SHBb;
  325. SHCoefficients[6] = unity_SHC;
  326. return max(half3(0, 0, 0), SampleSH9(SHCoefficients, normalWS));
  327. }
  328. // SH Vertex Evaluation. Depending on target SH sampling might be
  329. // done completely per vertex or mixed with L2 term per vertex and L0, L1
  330. // per pixel. See SampleSHPixel
  331. half3 SampleSHVertex(half3 normalWS)
  332. {
  333. #if defined(EVALUATE_SH_VERTEX)
  334. return max(half3(0, 0, 0), SampleSH(normalWS));
  335. #elif defined(EVALUATE_SH_MIXED)
  336. // no max since this is only L2 contribution
  337. return SHEvalLinearL2(normalWS, unity_SHBr, unity_SHBg, unity_SHBb, unity_SHC);
  338. #endif
  339. // Fully per-pixel. Nothing to compute.
  340. return half3(0.0, 0.0, 0.0);
  341. }
  342. // SH Pixel Evaluation. Depending on target SH sampling might be done
  343. // mixed or fully in pixel. See SampleSHVertex
  344. half3 SampleSHPixel(half3 L2Term, half3 normalWS)
  345. {
  346. #if defined(EVALUATE_SH_VERTEX)
  347. return L2Term;
  348. #elif defined(EVALUATE_SH_MIXED)
  349. half3 L0L1Term = SHEvalLinearL0L1(normalWS, unity_SHAr, unity_SHAg, unity_SHAb);
  350. return max(half3(0, 0, 0), L2Term + L0L1Term);
  351. #endif
  352. // Default: Evaluate SH fully per-pixel
  353. return SampleSH(normalWS);
  354. }
  355. // Sample baked lightmap. Non-Direction and Directional if available.
  356. // Realtime GI is not supported.
  357. half3 SampleLightmap(float2 lightmapUV, half3 normalWS)
  358. {
  359. #ifdef UNITY_LIGHTMAP_FULL_HDR
  360. bool encodedLightmap = false;
  361. #else
  362. bool encodedLightmap = true;
  363. #endif
  364. half4 decodeInstructions = half4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0h, 0.0h);
  365. // The shader library sample lightmap functions transform the lightmap uv coords to apply bias and scale.
  366. // However, universal pipeline already transformed those coords in vertex. We pass half4(1, 1, 0, 0) and
  367. // the compiler will optimize the transform away.
  368. half4 transformCoords = half4(1, 1, 0, 0);
  369. #ifdef DIRLIGHTMAP_COMBINED
  370. return SampleDirectionalLightmap(TEXTURE2D_ARGS(unity_Lightmap, samplerunity_Lightmap),
  371. TEXTURE2D_ARGS(unity_LightmapInd, samplerunity_Lightmap),
  372. lightmapUV, transformCoords, normalWS, encodedLightmap, decodeInstructions);
  373. #elif defined(LIGHTMAP_ON)
  374. return SampleSingleLightmap(TEXTURE2D_ARGS(unity_Lightmap, samplerunity_Lightmap), lightmapUV, transformCoords, encodedLightmap, decodeInstructions);
  375. #else
  376. return half3(0.0, 0.0, 0.0);
  377. #endif
  378. }
  379. // We either sample GI from baked lightmap or from probes.
  380. // If lightmap: sampleData.xy = lightmapUV
  381. // If probe: sampleData.xyz = L2 SH terms
  382. #ifdef LIGHTMAP_ON
  383. #define SAMPLE_GI(lmName, shName, normalWSName) SampleLightmap(lmName, normalWSName)
  384. #else
  385. #define SAMPLE_GI(lmName, shName, normalWSName) SampleSHPixel(shName, normalWSName)
  386. #endif
  387. half3 GlossyEnvironmentReflection(half3 reflectVector, half perceptualRoughness, half occlusion)
  388. {
  389. #if !defined(_ENVIRONMENTREFLECTIONS_OFF)
  390. half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
  391. half4 encodedIrradiance = SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip);
  392. #if !defined(UNITY_USE_NATIVE_HDR)
  393. half3 irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
  394. #else
  395. half3 irradiance = encodedIrradiance.rbg;
  396. #endif
  397. return irradiance * occlusion;
  398. #endif // GLOSSY_REFLECTIONS
  399. return _GlossyEnvironmentColor.rgb * occlusion;
  400. }
  401. half3 SubtractDirectMainLightFromLightmap(Light mainLight, half3 normalWS, half3 bakedGI)
  402. {
  403. // Let's try to make realtime shadows work on a surface, which already contains
  404. // baked lighting and shadowing from the main sun light.
  405. // Summary:
  406. // 1) Calculate possible value in the shadow by subtracting estimated light contribution from the places occluded by realtime shadow:
  407. // a) preserves other baked lights and light bounces
  408. // b) eliminates shadows on the geometry facing away from the light
  409. // 2) Clamp against user defined ShadowColor.
  410. // 3) Pick original lightmap value, if it is the darkest one.
  411. // 1) Gives good estimate of illumination as if light would've been shadowed during the bake.
  412. // We only subtract the main direction light. This is accounted in the contribution term below.
  413. half shadowStrength = GetMainLightShadowStrength();
  414. half contributionTerm = saturate(dot(mainLight.direction, normalWS));
  415. half3 lambert = mainLight.color * contributionTerm;
  416. half3 estimatedLightContributionMaskedByInverseOfShadow = lambert * (1.0 - mainLight.shadowAttenuation);
  417. half3 subtractedLightmap = bakedGI - estimatedLightContributionMaskedByInverseOfShadow;
  418. // 2) Allows user to define overall ambient of the scene and control situation when realtime shadow becomes too dark.
  419. half3 realtimeShadow = max(subtractedLightmap, _SubtractiveShadowColor.xyz);
  420. realtimeShadow = lerp(bakedGI, realtimeShadow, shadowStrength);
  421. // 3) Pick darkest color
  422. return min(bakedGI, realtimeShadow);
  423. }
  424. half3 GlobalIllumination(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS)
  425. {
  426. half3 reflectVector = reflect(-viewDirectionWS, normalWS);
  427. half fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS)));
  428. half3 indirectDiffuse = bakedGI * occlusion;
  429. half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, occlusion);
  430. return EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
  431. }
  432. void MixRealtimeAndBakedGI(inout Light light, half3 normalWS, inout half3 bakedGI, half4 shadowMask)
  433. {
  434. #if defined(_MIXED_LIGHTING_SUBTRACTIVE) && defined(LIGHTMAP_ON)
  435. bakedGI = SubtractDirectMainLightFromLightmap(light, normalWS, bakedGI);
  436. #endif
  437. }
  438. ///////////////////////////////////////////////////////////////////////////////
  439. // Lighting Functions //
  440. ///////////////////////////////////////////////////////////////////////////////
  441. half3 LightingLambert(half3 lightColor, half3 lightDir, half3 normal)
  442. {
  443. half NdotL = saturate(dot(normal, lightDir));
  444. return lightColor * NdotL;
  445. }
  446. half3 LightingSpecular(half3 lightColor, half3 lightDir, half3 normal, half3 viewDir, half4 specular, half smoothness)
  447. {
  448. float3 halfVec = SafeNormalize(float3(lightDir) + float3(viewDir));
  449. half NdotH = saturate(dot(normal, halfVec));
  450. half modifier = pow(NdotH, smoothness);
  451. half3 specularReflection = specular.rgb * modifier;
  452. return lightColor * specularReflection;
  453. }
  454. half3 LightingPhysicallyBased(BRDFData brdfData, half3 lightColor, half3 lightDirectionWS, half lightAttenuation, half3 normalWS, half3 viewDirectionWS)
  455. {
  456. half NdotL = saturate(dot(normalWS, lightDirectionWS));
  457. half3 radiance = lightColor * (lightAttenuation * NdotL);
  458. return DirectBDRF(brdfData, normalWS, lightDirectionWS, viewDirectionWS) * radiance;
  459. }
  460. half3 LightingPhysicallyBased(BRDFData brdfData, Light light, half3 normalWS, half3 viewDirectionWS)
  461. {
  462. return LightingPhysicallyBased(brdfData, light.color, light.direction, light.distanceAttenuation * light.shadowAttenuation, normalWS, viewDirectionWS);
  463. }
  464. half3 VertexLighting(float3 positionWS, half3 normalWS)
  465. {
  466. half3 vertexLightColor = half3(0.0, 0.0, 0.0);
  467. #ifdef _ADDITIONAL_LIGHTS_VERTEX
  468. uint lightsCount = GetAdditionalLightsCount();
  469. for (uint lightIndex = 0u; lightIndex < lightsCount; ++lightIndex)
  470. {
  471. Light light = GetAdditionalLight(lightIndex, positionWS);
  472. half3 lightColor = light.color * light.distanceAttenuation;
  473. vertexLightColor += LightingLambert(lightColor, light.direction, normalWS);
  474. }
  475. #endif
  476. return vertexLightColor;
  477. }
  478. ///////////////////////////////////////////////////////////////////////////////
  479. // Fragment Functions //
  480. // Used by ShaderGraph and others builtin renderers //
  481. ///////////////////////////////////////////////////////////////////////////////
  482. half4 UniversalFragmentPBR(InputData inputData, half3 albedo, half metallic, half3 specular,
  483. half smoothness, half occlusion, half3 emission, half alpha)
  484. {
  485. BRDFData brdfData;
  486. InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData);
  487. Light mainLight = GetMainLight(inputData.shadowCoord);
  488. MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));
  489. half3 color = GlobalIllumination(brdfData, inputData.bakedGI, occlusion, inputData.normalWS, inputData.viewDirectionWS);
  490. color += LightingPhysicallyBased(brdfData, mainLight, inputData.normalWS, inputData.viewDirectionWS);
  491. #ifdef _ADDITIONAL_LIGHTS
  492. uint pixelLightCount = GetAdditionalLightsCount();
  493. for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
  494. {
  495. Light light = GetAdditionalLight(lightIndex, inputData.positionWS);
  496. color += LightingPhysicallyBased(brdfData, light, inputData.normalWS, inputData.viewDirectionWS);
  497. }
  498. #endif
  499. #ifdef _ADDITIONAL_LIGHTS_VERTEX
  500. color += inputData.vertexLighting * brdfData.diffuse;
  501. #endif
  502. color += emission;
  503. return half4(color, alpha);
  504. }
  505. half4 UniversalFragmentBlinnPhong(InputData inputData, half3 diffuse, half4 specularGloss, half smoothness, half3 emission, half alpha)
  506. {
  507. Light mainLight = GetMainLight(inputData.shadowCoord);
  508. MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));
  509. half3 attenuatedLightColor = mainLight.color * (mainLight.distanceAttenuation * mainLight.shadowAttenuation);
  510. half3 diffuseColor = inputData.bakedGI + LightingLambert(attenuatedLightColor, mainLight.direction, inputData.normalWS);
  511. half3 specularColor = LightingSpecular(attenuatedLightColor, mainLight.direction, inputData.normalWS, inputData.viewDirectionWS, specularGloss, smoothness);
  512. #ifdef _ADDITIONAL_LIGHTS
  513. uint pixelLightCount = GetAdditionalLightsCount();
  514. for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
  515. {
  516. Light light = GetAdditionalLight(lightIndex, inputData.positionWS);
  517. half3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
  518. diffuseColor += LightingLambert(attenuatedLightColor, light.direction, inputData.normalWS);
  519. specularColor += LightingSpecular(attenuatedLightColor, light.direction, inputData.normalWS, inputData.viewDirectionWS, specularGloss, smoothness);
  520. }
  521. #endif
  522. #ifdef _ADDITIONAL_LIGHTS_VERTEX
  523. diffuseColor += inputData.vertexLighting;
  524. #endif
  525. half3 finalColor = diffuseColor * diffuse + emission;
  526. #if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
  527. finalColor += specularColor;
  528. #endif
  529. return half4(finalColor, alpha);
  530. }
  531. //LWRP -> Universal Backwards Compatibility
  532. half4 LightweightFragmentPBR(InputData inputData, half3 albedo, half metallic, half3 specular,
  533. half smoothness, half occlusion, half3 emission, half alpha)
  534. {
  535. return UniversalFragmentPBR(inputData, albedo, metallic, specular, smoothness, occlusion, emission, alpha);
  536. }
  537. half4 LightweightFragmentBlinnPhong(InputData inputData, half3 diffuse, half4 specularGloss, half smoothness, half3 emission, half alpha)
  538. {
  539. return UniversalFragmentBlinnPhong(inputData, diffuse, specularGloss, smoothness, emission, alpha);
  540. }
  541. #endif