EntityLighting.hlsl 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. #ifndef UNITY_ENTITY_LIGHTING_INCLUDED
  2. #define UNITY_ENTITY_LIGHTING_INCLUDED
  3. #if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
  4. #pragma warning (disable : 3205) // conversion of larger type to smaller
  5. #endif
  6. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
  7. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
  8. #define LIGHTMAP_RGBM_MAX_GAMMA real(5.0) // NB: Must match value in RGBMRanges.h
  9. #define LIGHTMAP_RGBM_MAX_LINEAR real(34.493242) // LIGHTMAP_RGBM_MAX_GAMMA ^ 2.2
  10. #ifdef UNITY_LIGHTMAP_RGBM_ENCODING
  11. #ifdef UNITY_COLORSPACE_GAMMA
  12. #define LIGHTMAP_HDR_MULTIPLIER LIGHTMAP_RGBM_MAX_GAMMA
  13. #define LIGHTMAP_HDR_EXPONENT real(1.0) // Not used in gamma color space
  14. #else
  15. #define LIGHTMAP_HDR_MULTIPLIER LIGHTMAP_RGBM_MAX_LINEAR
  16. #define LIGHTMAP_HDR_EXPONENT real(2.2)
  17. #endif
  18. #elif defined(UNITY_LIGHTMAP_DLDR_ENCODING)
  19. #ifdef UNITY_COLORSPACE_GAMMA
  20. #define LIGHTMAP_HDR_MULTIPLIER real(2.0)
  21. #else
  22. #define LIGHTMAP_HDR_MULTIPLIER real(4.59) // 2.0 ^ 2.2
  23. #endif
  24. #define LIGHTMAP_HDR_EXPONENT real(0.0)
  25. #else // (UNITY_LIGHTMAP_FULL_HDR)
  26. #define LIGHTMAP_HDR_MULTIPLIER real(1.0)
  27. #define LIGHTMAP_HDR_EXPONENT real(1.0)
  28. #endif
  29. // TODO: Check if PI is correctly handled!
  30. // Ref: "Efficient Evaluation of Irradiance Environment Maps" from ShaderX 2
  31. real3 SHEvalLinearL0L1(real3 N, real4 shAr, real4 shAg, real4 shAb)
  32. {
  33. real4 vA = real4(N, 1.0);
  34. real3 x1;
  35. // Linear (L1) + constant (L0) polynomial terms
  36. x1.r = dot(shAr, vA);
  37. x1.g = dot(shAg, vA);
  38. x1.b = dot(shAb, vA);
  39. return x1;
  40. }
  41. real3 SHEvalLinearL1(real3 N, real3 shAr, real3 shAg, real3 shAb)
  42. {
  43. real3 x1;
  44. x1.r = dot(shAr, N);
  45. x1.g = dot(shAg, N);
  46. x1.b = dot(shAb, N);
  47. return x1;
  48. }
  49. real3 SHEvalLinearL2(real3 N, real4 shBr, real4 shBg, real4 shBb, real4 shC)
  50. {
  51. real3 x2;
  52. // 4 of the quadratic (L2) polynomials
  53. real4 vB = N.xyzz * N.yzzx;
  54. x2.r = dot(shBr, vB);
  55. x2.g = dot(shBg, vB);
  56. x2.b = dot(shBb, vB);
  57. // Final (5th) quadratic (L2) polynomial
  58. real vC = N.x * N.x - N.y * N.y;
  59. real3 x3 = shC.rgb * vC;
  60. return x2 + x3;
  61. }
  62. #if HAS_HALF
  63. half3 SampleSH9(half4 SHCoefficients[7], half3 N)
  64. {
  65. half4 shAr = SHCoefficients[0];
  66. half4 shAg = SHCoefficients[1];
  67. half4 shAb = SHCoefficients[2];
  68. half4 shBr = SHCoefficients[3];
  69. half4 shBg = SHCoefficients[4];
  70. half4 shBb = SHCoefficients[5];
  71. half4 shCr = SHCoefficients[6];
  72. // Linear + constant polynomial terms
  73. half3 res = SHEvalLinearL0L1(N, shAr, shAg, shAb);
  74. // Quadratic polynomials
  75. res += SHEvalLinearL2(N, shBr, shBg, shBb, shCr);
  76. #ifdef UNITY_COLORSPACE_GAMMA
  77. res = LinearToSRGB(res);
  78. #endif
  79. return res;
  80. }
  81. #endif
  82. float3 SampleSH9(float4 SHCoefficients[7], float3 N)
  83. {
  84. float4 shAr = SHCoefficients[0];
  85. float4 shAg = SHCoefficients[1];
  86. float4 shAb = SHCoefficients[2];
  87. float4 shBr = SHCoefficients[3];
  88. float4 shBg = SHCoefficients[4];
  89. float4 shBb = SHCoefficients[5];
  90. float4 shCr = SHCoefficients[6];
  91. // Linear + constant polynomial terms
  92. float3 res = SHEvalLinearL0L1(N, shAr, shAg, shAb);
  93. // Quadratic polynomials
  94. res += SHEvalLinearL2(N, shBr, shBg, shBb, shCr);
  95. #ifdef UNITY_COLORSPACE_GAMMA
  96. res = LinearToSRGB(res);
  97. #endif
  98. return res;
  99. }
  100. // texture3dLod is not supported on gles2.
  101. #if !defined(SHADER_API_GLES)
  102. // This sample a 3D volume storing SH
  103. // Volume is store as 3D texture with 4 R, G, B, Occ set of 4 coefficient store atlas in same 3D texture. Occ is use for occlusion.
  104. // TODO: the packing here is inefficient as we will fetch values far away from each other and they may not fit into the cache - Suggest we pack RGB continuously
  105. // TODO: The calcul of texcoord could be perform with a single matrix multicplication calcualted on C++ side that will fold probeVolumeMin and probeVolumeSizeInv into it and handle the identity case, no reasons to do it in C++ (ask Ionut about it)
  106. // It should also handle the camera relative path (if the render pipeline use it)
  107. // bakeDiffuseLighting and backBakeDiffuseLighting must be initialize outside the function
  108. void SampleProbeVolumeSH4(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float3 backNormalWS, float4x4 WorldToTexture,
  109. float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv,
  110. inout float3 bakeDiffuseLighting, inout float3 backBakeDiffuseLighting)
  111. {
  112. float3 position = (transformToLocal == 1.0) ? mul(WorldToTexture, float4(positionWS, 1.0)).xyz : positionWS;
  113. float3 texCoord = (position - probeVolumeMin) * probeVolumeSizeInv.xyz;
  114. // Each component is store in the same texture 3D. Each use one quater on the x axis
  115. // Here we get R component then increase by step size (0.25) to get other component. This assume 4 component
  116. // but last one is not used.
  117. // Clamp to edge of the "internal" texture, as R is from half texel to size of R texture minus half texel.
  118. // This avoid leaking
  119. texCoord.x = clamp(texCoord.x * 0.25, 0.5 * texelSizeX, 0.25 - 0.5 * texelSizeX);
  120. float4 shAr = SAMPLE_TEXTURE3D_LOD(SHVolumeTexture, SHVolumeSampler, texCoord, 0);
  121. texCoord.x += 0.25;
  122. float4 shAg = SAMPLE_TEXTURE3D_LOD(SHVolumeTexture, SHVolumeSampler, texCoord, 0);
  123. texCoord.x += 0.25;
  124. float4 shAb = SAMPLE_TEXTURE3D_LOD(SHVolumeTexture, SHVolumeSampler, texCoord, 0);
  125. bakeDiffuseLighting += SHEvalLinearL0L1(normalWS, shAr, shAg, shAb);
  126. backBakeDiffuseLighting += SHEvalLinearL0L1(backNormalWS, shAr, shAg, shAb);
  127. }
  128. // Just a shortcut that call function above
  129. float3 SampleProbeVolumeSH4(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float4x4 WorldToTexture,
  130. float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv)
  131. {
  132. float3 backNormalWSUnused = 0.0;
  133. float3 bakeDiffuseLighting = 0.0;
  134. float3 backBakeDiffuseLightingUnused = 0.0;
  135. SampleProbeVolumeSH4(TEXTURE3D_ARGS(SHVolumeTexture, SHVolumeSampler), positionWS, normalWS, backNormalWSUnused, WorldToTexture,
  136. transformToLocal, texelSizeX, probeVolumeMin, probeVolumeSizeInv,
  137. bakeDiffuseLighting, backBakeDiffuseLightingUnused);
  138. return bakeDiffuseLighting;
  139. }
  140. // The SphericalHarmonicsL2 coefficients are packed into 7 coefficients per color channel instead of 9.
  141. // The packing from 9 to 7 is done from engine code and will use the alpha component of the pixel to store an additional SH coefficient.
  142. // The 3D atlas texture will contain 7 SH coefficient parts.
  143. // bakeDiffuseLighting and backBakeDiffuseLighting must be initialize outside the function
  144. void SampleProbeVolumeSH9(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float3 backNormalWS, float4x4 WorldToTexture,
  145. float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv,
  146. inout float3 bakeDiffuseLighting, inout float3 backBakeDiffuseLighting)
  147. {
  148. float3 position = (transformToLocal == 1.0f) ? mul(WorldToTexture, float4(positionWS, 1.0)).xyz : positionWS;
  149. float3 texCoord = (position - probeVolumeMin) * probeVolumeSizeInv;
  150. const uint shCoeffCount = 7;
  151. const float invShCoeffCount = 1.0f / float(shCoeffCount);
  152. // We need to compute proper X coordinate to sample into the atlas.
  153. texCoord.x = texCoord.x / shCoeffCount;
  154. // Clamp the x coordinate otherwise we'll have leaking between RGB coefficients.
  155. float texCoordX = clamp(texCoord.x, 0.5f * texelSizeX, invShCoeffCount - 0.5f * texelSizeX);
  156. float4 SHCoefficients[7];
  157. for (uint i = 0; i < shCoeffCount; i++)
  158. {
  159. texCoord.x = texCoordX + i * invShCoeffCount;
  160. SHCoefficients[i] = SAMPLE_TEXTURE3D_LOD(SHVolumeTexture, SHVolumeSampler, texCoord, 0);
  161. }
  162. bakeDiffuseLighting += SampleSH9(SHCoefficients, normalize(normalWS));
  163. backBakeDiffuseLighting += SampleSH9(SHCoefficients, normalize(backNormalWS));
  164. }
  165. // Just a shortcut that call function above
  166. float3 SampleProbeVolumeSH9(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float4x4 WorldToTexture,
  167. float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv)
  168. {
  169. float3 backNormalWSUnused = 0.0;
  170. float3 bakeDiffuseLighting = 0.0;
  171. float3 backBakeDiffuseLightingUnused = 0.0;
  172. SampleProbeVolumeSH9(TEXTURE3D_ARGS(SHVolumeTexture, SHVolumeSampler), positionWS, normalWS, backNormalWSUnused, WorldToTexture,
  173. transformToLocal, texelSizeX, probeVolumeMin, probeVolumeSizeInv,
  174. bakeDiffuseLighting, backBakeDiffuseLightingUnused);
  175. return bakeDiffuseLighting;
  176. }
  177. #endif
  178. float4 SampleProbeOcclusion(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float4x4 WorldToTexture,
  179. float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv)
  180. {
  181. float3 position = (transformToLocal == 1.0) ? mul(WorldToTexture, float4(positionWS, 1.0)).xyz : positionWS;
  182. float3 texCoord = (position - probeVolumeMin) * probeVolumeSizeInv.xyz;
  183. // Sample fourth texture in the atlas
  184. // We need to compute proper U coordinate to sample.
  185. // Clamp the coordinate otherwize we'll have leaking between ShB coefficients and Probe Occlusion(Occ) info
  186. texCoord.x = max(texCoord.x * 0.25 + 0.75, 0.75 + 0.5 * texelSizeX);
  187. return SAMPLE_TEXTURE3D(SHVolumeTexture, SHVolumeSampler, texCoord);
  188. }
  189. // Following functions are to sample enlighten lightmaps (or lightmaps encoded the same way as our
  190. // enlighten implementation). They assume use of RGB9E5 for dynamic illuminance map and RGBM for baked ones.
  191. // It is required for other platform that aren't supporting this format to implement variant of these functions
  192. // (But these kind of platform should use regular render loop and not news shaders).
  193. // TODO: This is the max value allowed for emissive (bad name - but keep for now to retrieve it) (It is 8^2.2 (gamma) and 8 is the limit of punctual light slider...), comme from UnityCg.cginc. Fix it!
  194. // Ask Jesper if this can be change for HDRenderPipeline
  195. #define EMISSIVE_RGBM_SCALE 97.0
  196. // RGBM stuff is temporary. For now baked lightmap are in RGBM and the RGBM range for lightmaps is specific so we can't use the generic method.
  197. // In the end baked lightmaps are going to be BC6H so the code will be the same as dynamic lightmaps.
  198. // Same goes for emissive packed as an input for Enlighten with another hard coded multiplier.
  199. // TODO: This function is used with the LightTransport pass to encode lightmap or emissive
  200. real4 PackEmissiveRGBM(real3 rgb)
  201. {
  202. real kOneOverRGBMMaxRange = 1.0 / EMISSIVE_RGBM_SCALE;
  203. const real kMinMultiplier = 2.0 * 1e-2;
  204. real4 rgbm = real4(rgb * kOneOverRGBMMaxRange, 1.0);
  205. rgbm.a = max(max(rgbm.r, rgbm.g), max(rgbm.b, kMinMultiplier));
  206. rgbm.a = ceil(rgbm.a * 255.0) / 255.0;
  207. // Division-by-zero warning from d3d9, so make compiler happy.
  208. rgbm.a = max(rgbm.a, kMinMultiplier);
  209. rgbm.rgb /= rgbm.a;
  210. return rgbm;
  211. }
  212. real3 UnpackLightmapRGBM(real4 rgbmInput, real4 decodeInstructions)
  213. {
  214. #ifdef UNITY_COLORSPACE_GAMMA
  215. return rgbmInput.rgb * (rgbmInput.a * decodeInstructions.x);
  216. #else
  217. return rgbmInput.rgb * (PositivePow(rgbmInput.a, decodeInstructions.y) * decodeInstructions.x);
  218. #endif
  219. }
  220. real3 UnpackLightmapDoubleLDR(real4 encodedColor, real4 decodeInstructions)
  221. {
  222. return encodedColor.rgb * decodeInstructions.x;
  223. }
  224. #ifndef BUILTIN_TARGET_API
  225. real3 DecodeLightmap(real4 encodedIlluminance, real4 decodeInstructions)
  226. {
  227. #if defined(UNITY_LIGHTMAP_RGBM_ENCODING)
  228. return UnpackLightmapRGBM(encodedIlluminance, decodeInstructions);
  229. #elif defined(UNITY_LIGHTMAP_DLDR_ENCODING)
  230. return UnpackLightmapDoubleLDR(encodedIlluminance, decodeInstructions);
  231. #else // (UNITY_LIGHTMAP_FULL_HDR)
  232. return encodedIlluminance.rgb;
  233. #endif
  234. }
  235. #endif
  236. real3 DecodeHDREnvironment(real4 encodedIrradiance, real4 decodeInstructions)
  237. {
  238. // Take into account texture alpha if decodeInstructions.w is true(the alpha value affects the RGB channels)
  239. real alpha = max(decodeInstructions.w * (encodedIrradiance.a - 1.0) + 1.0, 0.0);
  240. // If Linear mode is not supported we can skip exponent part
  241. return (decodeInstructions.x * PositivePow(alpha, decodeInstructions.y)) * encodedIrradiance.rgb;
  242. }
  243. #if defined(UNITY_DOTS_INSTANCING_ENABLED)
  244. #define TEXTURE2D_LIGHTMAP_PARAM TEXTURE2D_ARRAY_PARAM
  245. #define TEXTURE2D_LIGHTMAP_ARGS TEXTURE2D_ARRAY_ARGS
  246. #define SAMPLE_TEXTURE2D_LIGHTMAP SAMPLE_TEXTURE2D_ARRAY
  247. #define LIGHTMAP_EXTRA_ARGS float2 uv, float slice
  248. #define LIGHTMAP_EXTRA_ARGS_USE uv, slice
  249. #else
  250. #define TEXTURE2D_LIGHTMAP_PARAM TEXTURE2D_PARAM
  251. #define TEXTURE2D_LIGHTMAP_ARGS TEXTURE2D_ARGS
  252. #define SAMPLE_TEXTURE2D_LIGHTMAP SAMPLE_TEXTURE2D
  253. #define LIGHTMAP_EXTRA_ARGS float2 uv
  254. #define LIGHTMAP_EXTRA_ARGS_USE uv
  255. #endif
  256. real3 SampleSingleLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), LIGHTMAP_EXTRA_ARGS, float4 transform, bool encodedLightmap, real4 decodeInstructions)
  257. {
  258. // transform is scale and bias
  259. uv = uv * transform.xy + transform.zw;
  260. real3 illuminance = real3(0.0, 0.0, 0.0);
  261. // Remark: baked lightmap is RGBM for now, dynamic lightmap is RGB9E5
  262. if (encodedLightmap)
  263. {
  264. real4 encodedIlluminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgba;
  265. illuminance = DecodeLightmap(encodedIlluminance, decodeInstructions);
  266. }
  267. else
  268. {
  269. illuminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgb;
  270. }
  271. return illuminance;
  272. }
  273. void SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_PARAM(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS, float4 transform,
  274. float3 normalWS, float3 backNormalWS, bool encodedLightmap, real4 decodeInstructions, inout real3 bakeDiffuseLighting, inout real3 backBakeDiffuseLighting)
  275. {
  276. // In directional mode Enlighten bakes dominant light direction
  277. // in a way, that using it for half Lambert and then dividing by a "rebalancing coefficient"
  278. // gives a result close to plain diffuse response lightmaps, but normalmapped.
  279. // Note that dir is not unit length on purpose. Its length is "directionality", like
  280. // for the directional specular lightmaps.
  281. // transform is scale and bias
  282. uv = uv * transform.xy + transform.zw;
  283. real4 direction = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapDirTex, lightmapDirSampler, LIGHTMAP_EXTRA_ARGS_USE);
  284. // Remark: baked lightmap is RGBM for now, dynamic lightmap is RGB9E5
  285. real3 illuminance = real3(0.0, 0.0, 0.0);
  286. if (encodedLightmap)
  287. {
  288. real4 encodedIlluminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgba;
  289. illuminance = DecodeLightmap(encodedIlluminance, decodeInstructions);
  290. }
  291. else
  292. {
  293. illuminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgb;
  294. }
  295. real halfLambert = dot(normalWS, direction.xyz - 0.5) + 0.5;
  296. bakeDiffuseLighting += illuminance * halfLambert / max(1e-4, direction.w);
  297. real backHalfLambert = dot(backNormalWS, direction.xyz - 0.5) + 0.5;
  298. backBakeDiffuseLighting += illuminance * backHalfLambert / max(1e-4, direction.w);
  299. }
  300. // Just a shortcut that call function above
  301. real3 SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_PARAM(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS, float4 transform,
  302. float3 normalWS, bool encodedLightmap, real4 decodeInstructions)
  303. {
  304. float3 backNormalWSUnused = 0.0;
  305. real3 bakeDiffuseLighting = 0.0;
  306. real3 backBakeDiffuseLightingUnused = 0.0;
  307. SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_ARGS(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_ARGS(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS_USE, transform,
  308. normalWS, backNormalWSUnused, encodedLightmap, decodeInstructions, bakeDiffuseLighting, backBakeDiffuseLightingUnused);
  309. return bakeDiffuseLighting;
  310. }
  311. #if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3
  312. #pragma warning (enable : 3205) // conversion of larger type to smaller
  313. #endif
  314. #endif // UNITY_ENTITY_LIGHTING_INCLUDED