light.glsl 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /* light.glsl -- Contains everything you need to manage lights
  2. *
  3. * Copyright (c) 2025-2026 Le Juez Victor
  4. *
  5. * This software is provided 'as-is', without any express or implied warranty.
  6. * For conditions of distribution and use, see accompanying LICENSE file.
  7. */
  8. /* === Includes === */
  9. #include "../math.glsl"
  10. #include "../pbr.glsl"
  11. /* === Macros === */
  12. #if defined(NUM_FORWARD_LIGHTS)
  13. # define SAMPLE_SHADOW_PROJ(name) float name(int lightIndex, vec4 Pls, float cNdotL, mat2 diskRot)
  14. # define SAMPLE_SHADOW_OMNI(name) float name(int lightIndex, vec3 Pws, float cNdotL, mat2 diskRot)
  15. # define LIGHT uLights[lightIndex]
  16. #else
  17. # define SAMPLE_SHADOW_PROJ(name) float name(vec3 Pws, float cNdotL, mat2 diskRot)
  18. # define SAMPLE_SHADOW_OMNI(name) float name(vec3 Pws, float cNdotL, mat2 diskRot)
  19. # define LIGHT uLight
  20. #endif
  21. /* === Constants === */
  22. // Should be defined in client side
  23. // #define NUM_FORWARD_LIGHTS 8
  24. #define LIGHT_DIR 0
  25. #define LIGHT_SPOT 1
  26. #define LIGHT_OMNI 2
  27. #define SHADOW_SAMPLES 8
  28. const vec2 VOGEL_DISK[8] = vec2[8](
  29. vec2(0.250000, 0.000000),
  30. vec2(-0.319290, 0.292496),
  31. vec2(0.048872, -0.556877),
  32. vec2(0.402444, 0.524918),
  33. vec2(-0.738535, -0.130636),
  34. vec2(0.699605, -0.445031),
  35. vec2(-0.234004, 0.870484),
  36. vec2(-0.446271, -0.859268)
  37. );
  38. /* === Structures === */
  39. struct Light {
  40. mat4 viewProj;
  41. vec3 color;
  42. vec3 position;
  43. vec3 direction;
  44. float specular;
  45. float energy;
  46. float range;
  47. float near;
  48. float far;
  49. float attenuation;
  50. float innerCutOff;
  51. float outerCutOff;
  52. float shadowSoftness;
  53. float shadowDepthBias;
  54. float shadowSlopeBias;
  55. int shadowLayer; //< less than zero if no shadows
  56. int type;
  57. };
  58. /* === Uniform Block === */
  59. #ifdef NUM_FORWARD_LIGHTS
  60. layout(std140) uniform LightArrayBlock {
  61. Light uLights[NUM_FORWARD_LIGHTS];
  62. int uNumLights;
  63. };
  64. #else
  65. layout(std140) uniform LightBlock {
  66. Light uLight;
  67. };
  68. #endif
  69. /* === Functions === */
  70. vec3 L_Diffuse(float cLdotH, float cNdotV, float cNdotL, float roughness)
  71. {
  72. float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5;
  73. float FdV = 1.0 + FD90_minus_1 * PBR_SchlickFresnel(cNdotV);
  74. float FdL = 1.0 + FD90_minus_1 * PBR_SchlickFresnel(cNdotL);
  75. return vec3(M_INV_PI * (FdV * FdL * cNdotL)); // Diffuse BRDF (Burley)
  76. }
  77. vec3 L_Specular(vec3 F0, float cLdotH, float cNdotH, float cNdotV, float cNdotL, float roughness)
  78. {
  79. roughness = max(roughness, 0.02); // >0.01 to avoid FP16 overflow after GGX distribution
  80. float alphaGGX = roughness * roughness;
  81. float D = PBR_DistributionGGX(cNdotH, alphaGGX);
  82. float G = PBR_GeometryGGX(cNdotL, cNdotV, alphaGGX);
  83. float cLdotH5 = PBR_SchlickFresnel(cLdotH);
  84. float F90 = clamp(50.0 * F0.g, 0.0, 1.0);
  85. vec3 F = F0 + (F90 - F0) * cLdotH5;
  86. return cNdotL * D * F * G; // Specular BRDF (Schlick GGX)
  87. }
  88. #ifdef L_SHADOW_IMPL
  89. mat2 L_ShadowDebandingMatrix(vec2 fragCoord)
  90. {
  91. float r = M_TAU * M_HashIGN(fragCoord);
  92. float sr = sin(r), cr = cos(r);
  93. return mat2(vec2(cr, -sr), vec2(sr, cr));
  94. }
  95. SAMPLE_SHADOW_PROJ(L_SampleShadowDir)
  96. {
  97. #if !defined(NUM_FORWARD_LIGHTS)
  98. vec4 Pls = LIGHT.viewProj * vec4(Pws, 1.0);
  99. #endif
  100. vec3 projCoords = Pls.xyz / Pls.w * 0.5 + 0.5;
  101. float bias = LIGHT.shadowDepthBias + LIGHT.shadowSlopeBias * (1.0 - cNdotL);
  102. float compareDepth = projCoords.z - bias;
  103. float shadow = 0.0;
  104. for (int i = 0; i < SHADOW_SAMPLES; ++i) {
  105. vec2 offset = diskRot * VOGEL_DISK[i] * LIGHT.shadowSoftness;
  106. shadow += texture(uShadowDirTex, vec4(projCoords.xy + offset, LIGHT.shadowLayer, compareDepth));
  107. }
  108. shadow /= float(SHADOW_SAMPLES);
  109. vec3 distToBorder = min(projCoords, 1.0 - projCoords);
  110. float edgeFade = smoothstep(0.0, 0.15, min(distToBorder.x, min(distToBorder.y, distToBorder.z)));
  111. shadow = mix(1.0, shadow, edgeFade);
  112. return shadow;
  113. }
  114. SAMPLE_SHADOW_PROJ(L_SampleShadowSpot)
  115. {
  116. #if !defined(NUM_FORWARD_LIGHTS)
  117. vec4 Pls = LIGHT.viewProj * vec4(Pws, 1.0);
  118. #endif
  119. vec3 projCoords = Pls.xyz / Pls.w * 0.5 + 0.5;
  120. float bias = LIGHT.shadowDepthBias + LIGHT.shadowSlopeBias * (1.0 - cNdotL);
  121. float compareDepth = projCoords.z - bias;
  122. float shadow = 0.0;
  123. for (int i = 0; i < SHADOW_SAMPLES; ++i) {
  124. vec2 offset = diskRot * VOGEL_DISK[i] * LIGHT.shadowSoftness;
  125. shadow += texture(uShadowSpotTex, vec4(projCoords.xy + offset, LIGHT.shadowLayer, compareDepth));
  126. }
  127. return shadow / float(SHADOW_SAMPLES);
  128. }
  129. SAMPLE_SHADOW_OMNI(L_SampleShadowOmni)
  130. {
  131. vec3 lightToFrag = Pws - LIGHT.position;
  132. float currentDepth = length(lightToFrag);
  133. float bias = LIGHT.shadowDepthBias + LIGHT.shadowSlopeBias * (1.0 - cNdotL);
  134. float compareDepth = (currentDepth - bias) / LIGHT.far;
  135. mat3 OBN = M_OrthonormalBasis(lightToFrag / currentDepth);
  136. float shadow = 0.0;
  137. for (int i = 0; i < SHADOW_SAMPLES; ++i) {
  138. vec2 diskOffset = diskRot * VOGEL_DISK[i] * LIGHT.shadowSoftness;
  139. shadow += texture(uShadowOmniTex, vec4(OBN * vec3(diskOffset.xy, 1.0), LIGHT.shadowLayer), compareDepth);
  140. }
  141. return shadow / float(SHADOW_SAMPLES);
  142. }
  143. #endif // L_SHADOW_IMPL
  144. /* === Undefs === */
  145. #undef SAMPLE_SHADOW_PROJ
  146. #undef SAMPLE_SHADOW_OMNI
  147. #undef LIGHT