LightFunctions.glsl 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // Copyright (C) 2009-2019, 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 <shaders/Functions.glsl>
  8. #include <shaders/Pack.glsl>
  9. #include <shaders/glsl_cpp_common/ClusteredShading.h>
  10. const U32 SHADOW_SAMPLE_COUNT = 16;
  11. #if !defined(ESM_CONSTANT)
  12. const F32 ESM_CONSTANT = 40.0;
  13. #endif
  14. // Fresnel term unreal
  15. Vec3 F_Unreal(Vec3 specular, F32 VoH)
  16. {
  17. return specular + (1.0 - specular) * pow(2.0, (-5.55473 * VoH - 6.98316) * VoH);
  18. }
  19. // Fresnel Schlick: "An Inexpensive BRDF Model for Physically-Based Rendering"
  20. // It has lower VGRPs than F_Unreal
  21. Vec3 F_Schlick(Vec3 specular, F32 VoH)
  22. {
  23. const F32 a = 1.0 - VoH;
  24. const F32 a2 = a * a;
  25. const F32 a5 = a2 * a2 * a; // a5 = a^5
  26. return /*saturate(50.0 * specular.g) */ a5 + (1.0 - a5) * specular;
  27. }
  28. // D(n,h) aka NDF: GGX Trowbridge-Reitz
  29. F32 D_GGX(F32 roughness, F32 NoH)
  30. {
  31. const F32 a = roughness * roughness;
  32. const F32 a2 = a * a;
  33. const F32 D = (NoH * a2 - NoH) * NoH + 1.0;
  34. return a2 / (PI * D * D);
  35. }
  36. // Visibility term: Geometric shadowing divided by BRDF denominator
  37. F32 V_Schlick(F32 roughness, F32 NoV, F32 NoL)
  38. {
  39. const F32 k = (roughness * roughness) * 0.5;
  40. const F32 Vis_SchlickV = NoV * (1.0 - k) + k;
  41. const F32 Vis_SchlickL = NoL * (1.0 - k) + k;
  42. return 0.25 / (Vis_SchlickV * Vis_SchlickL);
  43. }
  44. Vec3 envBRDF(Vec3 specular, F32 roughness, sampler2D integrationLut, F32 NoV)
  45. {
  46. const F32 a = roughness * roughness;
  47. const F32 a2 = a * a;
  48. const Vec2 envBRDF = textureLod(integrationLut, Vec2(a2, NoV), 0.0).xy;
  49. return specular * envBRDF.x + /*min(1.0, 50.0 * specular.g) */ envBRDF.y;
  50. }
  51. Vec3 diffuseLambert(Vec3 diffuse)
  52. {
  53. return diffuse * (1.0 / PI);
  54. }
  55. // Performs BRDF specular lighting
  56. Vec3 computeSpecularColorBrdf(GbufferInfo gbuffer, Vec3 viewDir, Vec3 frag2Light)
  57. {
  58. const Vec3 H = normalize(frag2Light + viewDir);
  59. const F32 NoL = max(EPSILON, dot(gbuffer.m_normal, frag2Light));
  60. const F32 VoH = max(EPSILON, dot(viewDir, H));
  61. const F32 NoH = max(EPSILON, dot(gbuffer.m_normal, H));
  62. const F32 NoV = max(EPSILON, dot(gbuffer.m_normal, viewDir));
  63. // F
  64. #if 0
  65. const Vec3 F = F_Unreal(gbuffer.m_specular, VoH);
  66. #else
  67. const Vec3 F = F_Schlick(gbuffer.m_specular, VoH);
  68. #endif
  69. // D
  70. const F32 D = D_GGX(gbuffer.m_roughness, NoH);
  71. // Vis
  72. const F32 V = V_Schlick(gbuffer.m_roughness, NoV, NoL);
  73. return F * (V * D);
  74. }
  75. F32 computeSpotFactor(Vec3 l, F32 outerCos, F32 innerCos, Vec3 spotDir)
  76. {
  77. const F32 costheta = -dot(l, spotDir);
  78. const F32 spotFactor = smoothstep(outerCos, innerCos, costheta);
  79. return spotFactor;
  80. }
  81. U32 computeShadowSampleCount(const U32 COUNT, F32 zVSpace)
  82. {
  83. const F32 MAX_DISTANCE = 5.0;
  84. const F32 z = max(zVSpace, -MAX_DISTANCE);
  85. F32 sampleCountf = F32(COUNT) + z * (F32(COUNT) / MAX_DISTANCE);
  86. sampleCountf = max(sampleCountf, 1.0);
  87. const U32 sampleCount = U32(sampleCountf);
  88. return sampleCount;
  89. }
  90. F32 computeShadowFactorSpotLight(SpotLight light, Vec3 worldPos, sampler2D spotMapArr)
  91. {
  92. const Vec4 texCoords4 = light.m_texProjectionMat * Vec4(worldPos, 1.0);
  93. const Vec3 texCoords3 = texCoords4.xyz / texCoords4.w;
  94. const F32 near = LIGHT_FRUSTUM_NEAR_PLANE;
  95. const F32 far = light.m_radius;
  96. const F32 linearDepth = linearizeDepth(texCoords3.z, near, far);
  97. const F32 shadowFactor = textureLod(spotMapArr, texCoords3.xy, 0.0).r;
  98. return saturate(exp(ESM_CONSTANT * (shadowFactor - linearDepth)));
  99. }
  100. // Compute the shadow factor of point (omni) lights.
  101. F32 computeShadowFactorPointLight(PointLight light, Vec3 frag2Light, sampler2D shadowMap)
  102. {
  103. const Vec3 dir = -frag2Light;
  104. const Vec3 dirabs = abs(dir);
  105. const F32 dist = max(dirabs.x, max(dirabs.y, dirabs.z));
  106. const F32 near = LIGHT_FRUSTUM_NEAR_PLANE;
  107. const F32 far = light.m_radius;
  108. const F32 linearDepth = (dist - near) / (far - near);
  109. // Read tex
  110. F32 shadowFactor;
  111. {
  112. // Convert cube coords
  113. U32 faceIdxu;
  114. Vec2 uv = convertCubeUvsu(dir, faceIdxu);
  115. // Get the atlas offset
  116. Vec2 atlasOffset;
  117. atlasOffset.x = light.m_shadowAtlasTileOffsets[faceIdxu >> 1u][(faceIdxu & 1u) << 1u];
  118. atlasOffset.y = light.m_shadowAtlasTileOffsets[faceIdxu >> 1u][((faceIdxu & 1u) << 1u) + 1u];
  119. // Compute UV
  120. uv = fma(uv, Vec2(light.m_shadowAtlasTileScale), atlasOffset);
  121. // Sample
  122. shadowFactor = textureLod(shadowMap, uv, 0.0).r;
  123. }
  124. return saturate(exp(ESM_CONSTANT * (shadowFactor - linearDepth)));
  125. }
  126. // Compute the shadow factor of a directional light
  127. F32 computeShadowFactorDirLight(DirectionalLight light, U32 cascadeIdx, Vec3 worldPos, sampler2D shadowMap)
  128. {
  129. const Mat4 lightProjectionMat = light.m_textureMatrices[cascadeIdx];
  130. const Vec4 texCoords4 = lightProjectionMat * Vec4(worldPos, 1.0);
  131. const Vec3 texCoords3 = texCoords4.xyz / texCoords4.w;
  132. const F32 cascadeLinearDepth = texCoords3.z;
  133. F32 shadowFactor = textureLod(shadowMap, texCoords3.xy, 0.0).r;
  134. shadowFactor = saturate(exp(ESM_CONSTANT * 3.0 * (shadowFactor - cascadeLinearDepth)));
  135. return shadowFactor;
  136. }
  137. // Compute the shadow factor of a directional light
  138. F32 computeShadowFactorDirLight(Mat4 lightProjectionMat, Vec3 worldPos, sampler2DShadow shadowMap)
  139. {
  140. const Vec4 texCoords4 = lightProjectionMat * Vec4(worldPos, 1.0);
  141. const Vec3 texCoords3 = texCoords4.xyz / texCoords4.w;
  142. const F32 shadowFactor = textureLod(shadowMap, texCoords3, 0.0);
  143. return shadowFactor;
  144. }
  145. // Compute the cubemap texture lookup vector given the reflection vector (r) the radius squared of the probe (R2) and
  146. // the frag pos in sphere space (f)
  147. Vec3 computeCubemapVecAccurate(Vec3 r, F32 R2, Vec3 f)
  148. {
  149. // Compute the collision of the r to the inner part of the sphere
  150. // From now on we work on the sphere's space
  151. // Project the center of the sphere (it's zero now since we are in sphere space) in ray "f,r"
  152. const Vec3 p = f - r * dot(f, r);
  153. // The collision to the sphere is point x where x = p + T * r
  154. // Because of the pythagorean theorem: R^2 = dot(p, p) + dot(T * r, T * r)
  155. // solving for T, T = R / |p|
  156. // then x becomes x = sqrt(R^2 - dot(p, p)) * r + p;
  157. F32 pp = dot(p, p);
  158. pp = min(pp, R2);
  159. const F32 sq = sqrt(R2 - pp);
  160. const Vec3 x = p + sq * r;
  161. return x;
  162. }
  163. // Cheap version of computeCubemapVecAccurate
  164. Vec3 computeCubemapVecCheap(Vec3 r, F32 R2, Vec3 f)
  165. {
  166. return r;
  167. }
  168. F32 computeAttenuationFactor(F32 lightRadius, Vec3 frag2Light)
  169. {
  170. const F32 fragLightDist = dot(frag2Light, frag2Light);
  171. F32 att = 1.0 - fragLightDist * lightRadius;
  172. att = max(0.0, att);
  173. return att * att;
  174. }
  175. // Given the probe properties trace a ray inside the probe and find the cube tex coordinates to sample
  176. Vec3 intersectProbe(Vec3 fragPos, // Ray origin
  177. Vec3 rayDir, // Ray direction
  178. Vec3 probeAabbMin,
  179. Vec3 probeAabbMax,
  180. Vec3 probeOrigin // Cubemap origin
  181. )
  182. {
  183. // Compute the intersection point
  184. const F32 intresectionDist = rayAabbIntersectionInside(fragPos, rayDir, probeAabbMin, probeAabbMax);
  185. const Vec3 intersectionPoint = fragPos + intresectionDist * rayDir;
  186. // Compute the cubemap vector
  187. return intersectionPoint - probeOrigin;
  188. }
  189. // Compute a weight (factor) of fragPos against some probe's bounds. The weight will be zero when fragPos is close to
  190. // AABB bounds and 1.0 at fadeDistance and less.
  191. F32 computeProbeBlendWeight(Vec3 fragPos, // Doesn't need to be inside the AABB
  192. Vec3 probeAabbMin,
  193. Vec3 probeAabbMax,
  194. F32 fadeDistance)
  195. {
  196. // Compute the min distance of fragPos from the edges of the AABB
  197. const Vec3 distFromMin = fragPos - probeAabbMin;
  198. const Vec3 distFromMax = probeAabbMax - fragPos;
  199. const Vec3 minDistVec = min(distFromMin, distFromMax);
  200. const F32 minDist = min(minDistVec.x, min(minDistVec.y, minDistVec.z));
  201. // Use saturate because minDist might be negative.
  202. return saturate(minDist / fadeDistance);
  203. }