LightFunctions.glsl 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. // Contains functions for light calculations
  6. #pragma once
  7. #include <AnKi/Shaders/Functions.glsl>
  8. #include <AnKi/Shaders/CollisionFunctions.glsl>
  9. #include <AnKi/Shaders/PackFunctions.glsl>
  10. #include <AnKi/Shaders/Include/ClusteredShadingTypes.h>
  11. #include <AnKi/Shaders/Include/Evsm.h>
  12. // Do some EVSM magic with depth
  13. Vec2 evsmProcessDepth(F32 depth)
  14. {
  15. depth = 2.0 * depth - 1.0;
  16. const F32 pos = exp(EVSM_POSITIVE_CONSTANT * depth);
  17. const F32 neg = -exp(EVSM_NEGATIVE_CONSTANT * depth);
  18. return Vec2(pos, neg);
  19. }
  20. F32 linstep(F32 a, F32 b, F32 v)
  21. {
  22. return saturate((v - a) / (b - a));
  23. }
  24. // Reduces VSM light bleedning
  25. F32 reduceLightBleeding(F32 pMax, F32 amount)
  26. {
  27. // Remove the [0, amount] tail and linearly rescale (amount, 1].
  28. return linstep(amount, 1.0, pMax);
  29. }
  30. F32 chebyshevUpperBound(Vec2 moments, F32 mean, F32 minVariance, F32 lightBleedingReduction)
  31. {
  32. // Compute variance
  33. F32 variance = moments.y - (moments.x * moments.x);
  34. variance = max(variance, minVariance);
  35. // Compute probabilistic upper bound
  36. const F32 d = mean - moments.x;
  37. F32 pMax = variance / (variance + (d * d));
  38. pMax = reduceLightBleeding(pMax, lightBleedingReduction);
  39. // One-tailed Chebyshev
  40. return (mean <= moments.x) ? 1.0 : pMax;
  41. }
  42. // Compute the shadow factor of EVSM given the 2 depths
  43. F32 evsmComputeShadowFactor(F32 occluderDepth, Vec4 shadowMapMoments)
  44. {
  45. const Vec2 evsmOccluderDepths = evsmProcessDepth(occluderDepth);
  46. const Vec2 depthScale =
  47. EVSM_BIAS * 0.01 * Vec2(EVSM_POSITIVE_CONSTANT, EVSM_NEGATIVE_CONSTANT) * evsmOccluderDepths;
  48. const Vec2 minVariance = depthScale * depthScale;
  49. #if !ANKI_EVSM4
  50. return chebyshevUpperBound(shadowMapMoments.xy, evsmOccluderDepths.x, minVariance.x, EVSM_LIGHT_BLEEDING_REDUCTION);
  51. #else
  52. const F32 pos =
  53. chebyshevUpperBound(shadowMapMoments.xy, evsmOccluderDepths.x, minVariance.x, EVSM_LIGHT_BLEEDING_REDUCTION);
  54. const F32 neg =
  55. chebyshevUpperBound(shadowMapMoments.zw, evsmOccluderDepths.y, minVariance.y, EVSM_LIGHT_BLEEDING_REDUCTION);
  56. return min(pos, neg);
  57. #endif
  58. }
  59. // Fresnel term unreal
  60. // specular: The specular color aka F0
  61. Vec3 F_Unreal(Vec3 specular, F32 VoH)
  62. {
  63. return specular + (1.0 - specular) * pow(2.0, (-5.55473 * VoH - 6.98316) * VoH);
  64. }
  65. // Fresnel Schlick: "An Inexpensive BRDF Model for Physically-Based Rendering"
  66. // It has lower VGRPs than F_Unreal
  67. // specular: The specular color aka F0
  68. Vec3 F_Schlick(Vec3 specular, F32 VoH)
  69. {
  70. const F32 a = 1.0 - VoH;
  71. const F32 a2 = a * a;
  72. const F32 a5 = a2 * a2 * a; // a5 = a^5
  73. return /*saturate(50.0 * specular.g) */ a5 + (1.0 - a5) * specular;
  74. }
  75. // D(n,h) aka NDF: GGX Trowbridge-Reitz
  76. F32 D_GGX(F32 roughness, F32 NoH)
  77. {
  78. const F32 a = roughness * roughness;
  79. const F32 a2 = a * a;
  80. const F32 D = (NoH * a2 - NoH) * NoH + 1.0;
  81. return a2 / (PI * D * D);
  82. }
  83. // Visibility term: Geometric shadowing divided by BRDF denominator
  84. F32 V_Schlick(F32 roughness, F32 NoV, F32 NoL)
  85. {
  86. const F32 k = (roughness * roughness) * 0.5;
  87. const F32 Vis_SchlickV = NoV * (1.0 - k) + k;
  88. const F32 Vis_SchlickL = NoL * (1.0 - k) + k;
  89. return 0.25 / (Vis_SchlickV * Vis_SchlickL);
  90. }
  91. Vec3 envBRDF(Vec3 specular, F32 roughness, texture2D integrationLut, sampler integrationLutSampler, F32 NoV)
  92. {
  93. const Vec2 envBRDF = textureLod(integrationLut, integrationLutSampler, Vec2(roughness, NoV), 0.0).xy;
  94. return specular * envBRDF.x + min(1.0, 50.0 * specular.g) * envBRDF.y;
  95. }
  96. Vec3 diffuseLambert(Vec3 diffuse)
  97. {
  98. return diffuse * (1.0 / PI);
  99. }
  100. // Performs BRDF specular lighting
  101. Vec3 computeSpecularColorBrdf(GbufferInfo gbuffer, Vec3 viewDir, Vec3 frag2Light)
  102. {
  103. const Vec3 H = normalize(frag2Light + viewDir);
  104. const F32 NoL = max(EPSILON, dot(gbuffer.m_normal, frag2Light));
  105. const F32 VoH = max(EPSILON, dot(viewDir, H));
  106. const F32 NoH = max(EPSILON, dot(gbuffer.m_normal, H));
  107. const F32 NoV = max(EPSILON, dot(gbuffer.m_normal, viewDir));
  108. // F
  109. #if 0
  110. const Vec3 F = F_Unreal(gbuffer.m_specular, VoH);
  111. #else
  112. const Vec3 F = F_Schlick(gbuffer.m_specular, VoH);
  113. #endif
  114. // D
  115. const F32 D = D_GGX(gbuffer.m_roughness, NoH);
  116. // Vis
  117. const F32 V = V_Schlick(gbuffer.m_roughness, NoV, NoL);
  118. return F * (V * D);
  119. }
  120. F32 computeSpotFactor(Vec3 l, F32 outerCos, F32 innerCos, Vec3 spotDir)
  121. {
  122. const F32 costheta = -dot(l, spotDir);
  123. const F32 spotFactor = smoothstep(outerCos, innerCos, costheta);
  124. return spotFactor;
  125. }
  126. U32 computeShadowSampleCount(const U32 COUNT, F32 zVSpace)
  127. {
  128. const F32 MAX_DISTANCE = 5.0;
  129. const F32 z = max(zVSpace, -MAX_DISTANCE);
  130. F32 sampleCountf = F32(COUNT) + z * (F32(COUNT) / MAX_DISTANCE);
  131. sampleCountf = max(sampleCountf, 1.0);
  132. const U32 sampleCount = U32(sampleCountf);
  133. return sampleCount;
  134. }
  135. F32 computeShadowFactorSpotLight(SpotLight light, Vec3 worldPos, texture2D spotMap, sampler spotMapSampler)
  136. {
  137. const Vec4 texCoords4 = light.m_textureMatrix * Vec4(worldPos, 1.0);
  138. const Vec3 texCoords3 = texCoords4.xyz / texCoords4.w;
  139. const Vec4 shadowMoments = textureLod(spotMap, spotMapSampler, texCoords3.xy, 0.0);
  140. return evsmComputeShadowFactor(texCoords3.z, shadowMoments);
  141. }
  142. // Compute the shadow factor of point (omni) lights.
  143. F32 computeShadowFactorPointLight(PointLight light, Vec3 frag2Light, texture2D shadowMap, sampler shadowMapSampler)
  144. {
  145. const Vec3 dir = -frag2Light;
  146. const Vec3 dirabs = abs(dir);
  147. const F32 dist = max(dirabs.x, max(dirabs.y, dirabs.z));
  148. // 1) Project the dist to light's proj mat
  149. //
  150. const F32 near = CLUSTER_OBJECT_FRUSTUM_NEAR_PLANE;
  151. const F32 far = light.m_radius;
  152. const F32 g = near - far;
  153. const F32 zVSpace = -dist;
  154. const F32 w = -zVSpace;
  155. F32 z = (far * zVSpace + far * near) / g;
  156. z /= w;
  157. // 2) Read shadow tex
  158. //
  159. // Convert cube coords
  160. U32 faceIdxu;
  161. Vec2 uv = convertCubeUvsu(dir, faceIdxu);
  162. // Get the atlas offset
  163. const Vec2 atlasOffset = light.m_shadowAtlasTileOffsets[faceIdxu];
  164. // Compute UV
  165. uv = fma(uv, Vec2(light.m_shadowAtlasTileScale), atlasOffset);
  166. // Sample
  167. const Vec4 shadowMoments = textureLod(shadowMap, shadowMapSampler, uv, 0.0);
  168. // 3) Compare
  169. //
  170. const F32 shadowFactor = evsmComputeShadowFactor(z, shadowMoments);
  171. return shadowFactor;
  172. }
  173. // Compute the shadow factor of a directional light
  174. F32 computeShadowFactorDirLight(DirectionalLight light, U32 cascadeIdx, Vec3 worldPos, texture2D shadowMap,
  175. sampler shadowMapSampler)
  176. {
  177. #define ANKI_FAST_CASCADES_WORKAROUND 1 // Doesn't make sense but it's super fast
  178. #if ANKI_FAST_CASCADES_WORKAROUND
  179. // Assumes MAX_SHADOW_CASCADES2 is 4
  180. Mat4 lightProjectionMat;
  181. switch(cascadeIdx)
  182. {
  183. case 0:
  184. lightProjectionMat = light.m_textureMatrices[0];
  185. break;
  186. case 1:
  187. lightProjectionMat = light.m_textureMatrices[1];
  188. break;
  189. case 2:
  190. lightProjectionMat = light.m_textureMatrices[2];
  191. break;
  192. default:
  193. lightProjectionMat = light.m_textureMatrices[3];
  194. }
  195. #else
  196. const Mat4 lightProjectionMat = light.m_textureMatrices[cascadeIdx];
  197. #endif
  198. const Vec4 texCoords4 = lightProjectionMat * Vec4(worldPos, 1.0);
  199. const Vec3 texCoords3 = texCoords4.xyz / texCoords4.w;
  200. const Vec4 shadowMoments = textureLod(shadowMap, shadowMapSampler, texCoords3.xy, 0.0);
  201. return evsmComputeShadowFactor(texCoords3.z, shadowMoments);
  202. }
  203. // Compute the shadow factor of a directional light
  204. F32 computeShadowFactorDirLight(Mat4 lightProjectionMat, Vec3 worldPos, texture2D shadowMap,
  205. samplerShadow shadowMapSampler)
  206. {
  207. const Vec4 texCoords4 = lightProjectionMat * Vec4(worldPos, 1.0);
  208. const Vec3 texCoords3 = texCoords4.xyz / texCoords4.w;
  209. const F32 shadowFactor = textureLod(shadowMap, shadowMapSampler, texCoords3, 0.0);
  210. return shadowFactor;
  211. }
  212. // Compute the cubemap texture lookup vector given the reflection vector (r) the radius squared of the probe (R2) and
  213. // the frag pos in sphere space (f)
  214. Vec3 computeCubemapVecAccurate(Vec3 r, F32 R2, Vec3 f)
  215. {
  216. // Compute the collision of the r to the inner part of the sphere
  217. // From now on we work on the sphere's space
  218. // Project the center of the sphere (it's zero now since we are in sphere space) in ray "f,r"
  219. const Vec3 p = f - r * dot(f, r);
  220. // The collision to the sphere is point x where x = p + T * r
  221. // Because of the pythagorean theorem: R^2 = dot(p, p) + dot(T * r, T * r)
  222. // solving for T, T = R / |p|
  223. // then x becomes x = sqrt(R^2 - dot(p, p)) * r + p;
  224. F32 pp = dot(p, p);
  225. pp = min(pp, R2);
  226. const F32 sq = sqrt(R2 - pp);
  227. const Vec3 x = p + sq * r;
  228. return x;
  229. }
  230. // Cheap version of computeCubemapVecAccurate
  231. Vec3 computeCubemapVecCheap(Vec3 r, F32 R2, Vec3 f)
  232. {
  233. return r;
  234. }
  235. F32 computeAttenuationFactor(F32 squareRadiusOverOne, Vec3 frag2Light)
  236. {
  237. const F32 fragLightDist = dot(frag2Light, frag2Light);
  238. F32 att = 1.0 - fragLightDist * squareRadiusOverOne;
  239. att = max(0.0, att);
  240. return att * att;
  241. }
  242. // Given the probe properties trace a ray inside the probe and find the cube tex coordinates to sample
  243. Vec3 intersectProbe(Vec3 fragPos, // Ray origin
  244. Vec3 rayDir, // Ray direction
  245. Vec3 probeAabbMin, Vec3 probeAabbMax,
  246. Vec3 probeOrigin // Cubemap origin
  247. )
  248. {
  249. // Compute the intersection point
  250. const F32 intresectionDist = testRayAabbInside(fragPos, rayDir, probeAabbMin, probeAabbMax);
  251. const Vec3 intersectionPoint = fragPos + intresectionDist * rayDir;
  252. // Compute the cubemap vector
  253. return intersectionPoint - probeOrigin;
  254. }
  255. // Compute a weight (factor) of fragPos against some probe's bounds. The weight will be zero when fragPos is close to
  256. // AABB bounds and 1.0 at fadeDistance and less.
  257. F32 computeProbeBlendWeight(Vec3 fragPos, // Doesn't need to be inside the AABB
  258. Vec3 probeAabbMin, Vec3 probeAabbMax, F32 fadeDistance)
  259. {
  260. // Compute the min distance of fragPos from the edges of the AABB
  261. const Vec3 distFromMin = fragPos - probeAabbMin;
  262. const Vec3 distFromMax = probeAabbMax - fragPos;
  263. const Vec3 minDistVec = min(distFromMin, distFromMax);
  264. const F32 minDist = min(minDistVec.x, min(minDistVec.y, minDistVec.z));
  265. // Use saturate because minDist might be negative.
  266. return saturate(minDist / fadeDistance);
  267. }
  268. // Given the value of the 6 faces of the dice and a normal, sample the correct weighted value.
  269. // https://www.shadertoy.com/view/XtcBDB
  270. Vec3 sampleAmbientDice(Vec3 posx, Vec3 negx, Vec3 posy, Vec3 negy, Vec3 posz, Vec3 negz, Vec3 normal)
  271. {
  272. const Vec3 axisWeights = abs(normal);
  273. const Vec3 uv = NDC_TO_UV(normal);
  274. Vec3 col = mix(negx, posx, uv.x) * axisWeights.x;
  275. col += mix(negy, posy, uv.y) * axisWeights.y;
  276. col += mix(negz, posz, uv.z) * axisWeights.z;
  277. // Divide by weight
  278. col /= axisWeights.x + axisWeights.y + axisWeights.z + EPSILON;
  279. return col;
  280. }
  281. // Sample the irradiance term from the clipmap
  282. Vec3 sampleGlobalIllumination(const Vec3 worldPos, const Vec3 normal, const GlobalIlluminationProbe probe,
  283. texture3D textures[MAX_VISIBLE_GLOBAL_ILLUMINATION_PROBES], sampler linearAnyClampSampler)
  284. {
  285. // Find the UVW
  286. Vec3 uvw = (worldPos - probe.m_aabbMin) / (probe.m_aabbMax - probe.m_aabbMin);
  287. // The U contains the 6 directions so divide
  288. uvw.x /= 6.0;
  289. // Calmp it to avoid direction leaking
  290. uvw.x = clamp(uvw.x, probe.m_halfTexelSizeU, (1.0 / 6.0) - probe.m_halfTexelSizeU);
  291. // Read the irradiance
  292. Vec3 irradiancePerDir[6u];
  293. ANKI_UNROLL for(U32 dir = 0u; dir < 6u; ++dir)
  294. {
  295. // Point to the correct UV
  296. Vec3 shiftedUVw = uvw;
  297. shiftedUVw.x += (1.0 / 6.0) * F32(dir);
  298. irradiancePerDir[dir] =
  299. textureLod(textures[nonuniformEXT(probe.m_textureIndex)], linearAnyClampSampler, shiftedUVw, 0.0).rgb;
  300. }
  301. // Sample the irradiance
  302. const Vec3 irradiance = sampleAmbientDice(irradiancePerDir[0], irradiancePerDir[1], irradiancePerDir[2],
  303. irradiancePerDir[3], irradiancePerDir[4], irradiancePerDir[5], normal);
  304. return irradiance;
  305. }
  306. U32 computeShadowCascadeIndex(F32 distance, F32 p, F32 effectiveShadowDistance, U32 shadowCascadeCount)
  307. {
  308. const F32 shadowCascadeCountf = F32(shadowCascadeCount);
  309. F32 idx = pow(distance / effectiveShadowDistance, 1.0f / p) * shadowCascadeCountf;
  310. idx = min(idx, shadowCascadeCountf - 1.0f);
  311. return U32(idx);
  312. }