pbrLightFunctions.fx 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. // Light Computing
  2. struct lightingInfo
  3. {
  4. vec3 diffuse;
  5. #ifdef SPECULARTERM
  6. vec3 specular;
  7. #endif
  8. };
  9. struct pointLightingInfo
  10. {
  11. vec3 lightOffset;
  12. float lightDistanceSquared;
  13. float attenuation;
  14. };
  15. struct spotLightingInfo
  16. {
  17. vec3 lightOffset;
  18. float lightDistanceSquared;
  19. vec3 directionToLightCenterW;
  20. float attenuation;
  21. };
  22. float computeDistanceLightFalloff_Standard(vec3 lightOffset, float range)
  23. {
  24. return max(0., 1.0 - length(lightOffset) / range);
  25. }
  26. float computeDistanceLightFalloff_Physical(float lightDistanceSquared)
  27. {
  28. return 1.0 / ((lightDistanceSquared + 0.001));
  29. }
  30. float computeDistanceLightFalloff_GLTF(float lightDistanceSquared, float inverseSquaredRange)
  31. {
  32. const float minDistanceSquared = 0.01*0.01;
  33. float lightDistanceFalloff = 1.0 / (max(lightDistanceSquared, minDistanceSquared));
  34. float factor = lightDistanceSquared * inverseSquaredRange;
  35. float attenuation = clamp(1.0 - factor * factor, 0., 1.);
  36. attenuation *= attenuation;
  37. // Smooth attenuation of the falloff defined by the range.
  38. lightDistanceFalloff *= attenuation;
  39. return lightDistanceFalloff;
  40. }
  41. float computeDistanceLightFalloff(vec3 lightOffset, float lightDistanceSquared, float range, float inverseSquaredRange)
  42. {
  43. #ifdef USEPHYSICALLIGHTFALLOFF
  44. return computeDistanceLightFalloff_Physical(lightDistanceSquared);
  45. #elif defined(USEGLTFLIGHTFALLOFF)
  46. return computeDistanceLightFalloff_GLTF(lightDistanceSquared, inverseSquaredRange);
  47. #else
  48. return computeDistanceLightFalloff_Standard(lightOffset, range);
  49. #endif
  50. }
  51. float computeDirectionalLightFalloff_Standard(vec3 lightDirection, vec3 directionToLightCenterW, float cosHalfAngle, float exponent)
  52. {
  53. float falloff = 0.0;
  54. float cosAngle = max(0.000000000000001, dot(-lightDirection, directionToLightCenterW));
  55. if (cosAngle >= cosHalfAngle)
  56. {
  57. falloff = max(0., pow(cosAngle, exponent));
  58. }
  59. return falloff;
  60. }
  61. float computeDirectionalLightFalloff_Physical(vec3 lightDirection, vec3 directionToLightCenterW, float cosHalfAngle)
  62. {
  63. const float kMinusLog2ConeAngleIntensityRatio = 6.64385618977; // -log2(0.01)
  64. // Calculate a Spherical Gaussian (von Mises-Fisher distribution, not angle-based Gaussian) such that the peak is in the light direction,
  65. // and the value at the nominal cone angle is 1% of the peak. Because we want the distribution to decay from unity (100%)
  66. // at the peak direction (dot product = 1) down to 1% at the nominal cone cutoff (dot product = cosAngle)
  67. // the falloff rate expressed in terms of the base-two dot product is therefore -log2(ConeAngleIntensityRatio) / (1.0 - cosAngle).
  68. // Note that the distribution is unnormalised in that peak density is unity, rather than the total energy is unity.
  69. float concentrationKappa = kMinusLog2ConeAngleIntensityRatio / (1.0 - cosHalfAngle);
  70. // Evaluate spherical gaussian for light directional falloff for spot light type (note: spot directional falloff;
  71. // not directional light type)
  72. vec4 lightDirectionSpreadSG = vec4(-lightDirection * concentrationKappa, -concentrationKappa);
  73. float falloff = exp2(dot(vec4(directionToLightCenterW, 1.0), lightDirectionSpreadSG));
  74. return falloff;
  75. }
  76. float computeDirectionalLightFalloff_GLTF(vec3 lightDirection, vec3 directionToLightCenterW, float lightAngleScale, float lightAngleOffset)
  77. {
  78. // On the CPU
  79. // float lightAngleScale = 1.0 f / max (0.001f, ( cosInner - cosOuter ));
  80. // float lightAngleOffset = -cosOuter * angleScale;
  81. float cd = dot(-lightDirection, directionToLightCenterW);
  82. float falloff = clamp(cd * lightAngleScale + lightAngleOffset, 0., 1.);
  83. // smooth the transition
  84. falloff *= falloff;
  85. return falloff;
  86. }
  87. float computeDirectionalLightFalloff(vec3 lightDirection, vec3 directionToLightCenterW, float cosHalfAngle, float exponent, float lightAngleScale, float lightAngleOffset)
  88. {
  89. #ifdef USEPHYSICALLIGHTFALLOFF
  90. return computeDirectionalLightFalloff_Physical(lightDirection, directionToLightCenterW, cosHalfAngle);
  91. #elif defined(USEGLTFLIGHTFALLOFF)
  92. return computeDirectionalLightFalloff_GLTF(lightDirection, directionToLightCenterW, lightAngleScale, lightAngleOffset);
  93. #else
  94. return computeDirectionalLightFalloff_Standard(lightDirection, directionToLightCenterW, cosHalfAngle, exponent);
  95. #endif
  96. }
  97. pointLightingInfo computePointLightingInfo(vec4 lightData) {
  98. pointLightingInfo result;
  99. result.lightOffset = lightData.xyz - vPositionW;
  100. result.lightDistanceSquared = dot(result.lightOffset, result.lightOffset);
  101. return result;
  102. }
  103. spotLightingInfo computeSpotLightingInfo(vec4 lightData) {
  104. spotLightingInfo result;
  105. result.lightOffset = lightData.xyz - vPositionW;
  106. result.directionToLightCenterW = normalize(result.lightOffset);
  107. result.lightDistanceSquared = dot(result.lightOffset, result.lightOffset);
  108. return result;
  109. }
  110. lightingInfo computePointLighting(pointLightingInfo info, vec3 viewDirectionW, vec3 vNormal, vec3 diffuseColor, float lightRadius, float roughness, float NdotV, vec3 reflectance0, vec3 reflectance90, float geometricRoughnessFactor, out float NdotL) {
  111. lightingInfo result;
  112. float lightDistance = sqrt(info.lightDistanceSquared);
  113. vec3 lightDirection = normalize(info.lightOffset);
  114. // Roughness
  115. roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, lightDistance);
  116. // diffuse
  117. vec3 H = normalize(viewDirectionW + lightDirection);
  118. NdotL = clamp(dot(vNormal, lightDirection), 0.00000000001, 1.0);
  119. float VdotH = clamp(dot(viewDirectionW, H), 0.0, 1.0);
  120. float diffuseTerm = computeDiffuseTerm(NdotL, NdotV, VdotH, roughness);
  121. result.diffuse = diffuseTerm * diffuseColor * info.attenuation;
  122. #ifdef SPECULARTERM
  123. // Specular
  124. float NdotH = clamp(dot(vNormal, H), 0.000000000001, 1.0);
  125. vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, reflectance0, reflectance90, geometricRoughnessFactor);
  126. result.specular = specTerm * diffuseColor * info.attenuation;
  127. #endif
  128. return result;
  129. }
  130. lightingInfo computeSpotLighting(spotLightingInfo info, vec3 viewDirectionW, vec3 vNormal, vec4 lightDirection, vec3 diffuseColor, float lightRadius, float roughness, float NdotV, vec3 reflectance0, vec3 reflectance90, float geometricRoughnessFactor, out float NdotL) {
  131. lightingInfo result;
  132. // Roughness.
  133. float lightDistance = sqrt(info.lightDistanceSquared);
  134. roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, lightDistance);
  135. // Diffuse
  136. vec3 H = normalize(viewDirectionW + info.directionToLightCenterW);
  137. NdotL = clamp(dot(vNormal, info.directionToLightCenterW), 0.000000000001, 1.0);
  138. float VdotH = clamp(dot(viewDirectionW, H), 0.0, 1.0);
  139. float diffuseTerm = computeDiffuseTerm(NdotL, NdotV, VdotH, roughness);
  140. result.diffuse = diffuseTerm * diffuseColor * info.attenuation;
  141. #ifdef SPECULARTERM
  142. // Specular
  143. float NdotH = clamp(dot(vNormal, H), 0.000000000001, 1.0);
  144. vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, reflectance0, reflectance90, geometricRoughnessFactor);
  145. result.specular = specTerm * diffuseColor * info.attenuation;
  146. #endif
  147. return result;
  148. }
  149. lightingInfo computeDirectionalLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float lightRadius, float roughness, float NdotV, vec3 reflectance0, vec3 reflectance90, float geometricRoughnessFactor, out float NdotL) {
  150. lightingInfo result;
  151. float lightDistance = length(-lightData.xyz);
  152. vec3 lightDirection = normalize(-lightData.xyz);
  153. // Roughness
  154. roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, lightDistance);
  155. // diffuse
  156. vec3 H = normalize(viewDirectionW + lightDirection);
  157. NdotL = clamp(dot(vNormal, lightDirection), 0.00000000001, 1.0);
  158. float VdotH = clamp(dot(viewDirectionW, H), 0.0, 1.0);
  159. float diffuseTerm = computeDiffuseTerm(NdotL, NdotV, VdotH, roughness);
  160. result.diffuse = diffuseTerm * diffuseColor;
  161. #ifdef SPECULARTERM
  162. // Specular
  163. float NdotH = clamp(dot(vNormal, H), 0.000000000001, 1.0);
  164. vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, reflectance0, reflectance90, geometricRoughnessFactor);
  165. result.specular = specTerm * diffuseColor;
  166. #endif
  167. return result;
  168. }
  169. lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float roughness, float NdotV, vec3 reflectance0, vec3 reflectance90, float geometricRoughnessFactor, out float NdotL) {
  170. lightingInfo result;
  171. // Roughness
  172. // Do not touch roughness on hemispheric.
  173. // Diffuse
  174. NdotL = dot(vNormal, lightData.xyz) * 0.5 + 0.5;
  175. result.diffuse = mix(groundColor, diffuseColor, NdotL);
  176. #ifdef SPECULARTERM
  177. // Specular
  178. vec3 lightVectorW = normalize(lightData.xyz);
  179. vec3 H = normalize(viewDirectionW + lightVectorW);
  180. float NdotH = clamp(dot(vNormal, H), 0.000000000001, 1.0);
  181. NdotL = clamp(NdotL, 0.000000000001, 1.0);
  182. float VdotH = clamp(dot(viewDirectionW, H), 0.0, 1.0);
  183. vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, reflectance0, reflectance90, geometricRoughnessFactor);
  184. result.specular = specTerm * diffuseColor;
  185. #endif
  186. return result;
  187. }
  188. vec3 computeProjectionTextureDiffuseLighting(sampler2D projectionLightSampler, mat4 textureProjectionMatrix){
  189. vec4 strq = textureProjectionMatrix * vec4(vPositionW, 1.0);
  190. strq /= strq.w;
  191. vec3 textureColor = texture2D(projectionLightSampler, strq.xy).rgb;
  192. return toLinearSpace(textureColor);
  193. }