pbrLightFunctions.fx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // Light Computing
  2. struct lightingInfo
  3. {
  4. vec3 diffuse;
  5. #ifdef SPECULARTERM
  6. vec3 specular;
  7. #endif
  8. };
  9. float computeDistanceLightFalloff(vec3 lightOffset, float lightDistanceSquared, float range)
  10. {
  11. #ifdef USEPHYSICALLIGHTFALLOFF
  12. float lightDistanceFalloff = 1.0 / ((lightDistanceSquared + 0.001));
  13. #else
  14. float lightDistanceFalloff = max(0., 1.0 - length(lightOffset) / range);
  15. #endif
  16. return lightDistanceFalloff;
  17. }
  18. float computeDirectionalLightFalloff(vec3 lightDirection, vec3 directionToLightCenterW, float cosHalfAngle, float exponent)
  19. {
  20. float falloff = 0.0;
  21. #ifdef USEPHYSICALLIGHTFALLOFF
  22. const float kMinusLog2ConeAngleIntensityRatio = 6.64385618977; // -log2(0.01)
  23. // Calculate a Spherical Gaussian (von Mises-Fisher distribution, not angle-based Gaussian) such that the peak is in the light direction,
  24. // and the value at the nominal cone angle is 1% of the peak. Because we want the distribution to decay from unity (100%)
  25. // at the peak direction (dot product = 1) down to 1% at the nominal cone cutoff (dot product = cosAngle)
  26. // the falloff rate expressed in terms of the base-two dot product is therefore -log2(ConeAngleIntensityRatio) / (1.0 - cosAngle).
  27. // Note that the distribution is unnormalised in that peak density is unity, rather than the total energy is unity.
  28. float concentrationKappa = kMinusLog2ConeAngleIntensityRatio / (1.0 - cosHalfAngle);
  29. // Evaluate spherical gaussian for light directional falloff for spot light type (note: spot directional falloff;
  30. // not directional light type)
  31. vec4 lightDirectionSpreadSG = vec4(-lightDirection * concentrationKappa, -concentrationKappa);
  32. falloff = exp2(dot(vec4(directionToLightCenterW, 1.0), lightDirectionSpreadSG));
  33. #else
  34. float cosAngle = max(0.000000000000001, dot(-lightDirection, directionToLightCenterW));
  35. if (cosAngle >= cosHalfAngle)
  36. {
  37. falloff = max(0., pow(cosAngle, exponent));
  38. }
  39. #endif
  40. return falloff;
  41. }
  42. lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, vec3 reflectance0, vec3 reflectance90, float geometricRoughnessFactor, out float NdotL) {
  43. lightingInfo result;
  44. vec3 lightDirection;
  45. float attenuation = 1.0;
  46. float lightDistance;
  47. // Point
  48. if (lightData.w == 0.)
  49. {
  50. vec3 lightOffset = lightData.xyz - vPositionW;
  51. float lightDistanceSquared = dot(lightOffset, lightOffset);
  52. attenuation = computeDistanceLightFalloff(lightOffset, lightDistanceSquared, rangeRadius);
  53. lightDistance = sqrt(lightDistanceSquared);
  54. lightDirection = normalize(lightOffset);
  55. }
  56. // Directional
  57. else
  58. {
  59. lightDistance = length(-lightData.xyz);
  60. lightDirection = normalize(-lightData.xyz);
  61. }
  62. // Roughness
  63. roughness = adjustRoughnessFromLightProperties(roughness, rangeRadius, lightDistance);
  64. // diffuse
  65. vec3 H = normalize(viewDirectionW + lightDirection);
  66. NdotL = clamp(dot(vNormal, lightDirection), 0.00000000001, 1.0);
  67. float VdotH = clamp(dot(viewDirectionW, H), 0.0, 1.0);
  68. float diffuseTerm = computeDiffuseTerm(NdotL, NdotV, VdotH, roughness);
  69. result.diffuse = diffuseTerm * diffuseColor * attenuation;
  70. #ifdef SPECULARTERM
  71. // Specular
  72. float NdotH = clamp(dot(vNormal, H), 0.000000000001, 1.0);
  73. vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, reflectance0, reflectance90, geometricRoughnessFactor);
  74. result.specular = specTerm * diffuseColor * attenuation;
  75. #endif
  76. return result;
  77. }
  78. lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, vec3 reflectance0, vec3 reflectance90, float geometricRoughnessFactor, out float NdotL) {
  79. lightingInfo result;
  80. vec3 lightOffset = lightData.xyz - vPositionW;
  81. vec3 directionToLightCenterW = normalize(lightOffset);
  82. // Distance falloff.
  83. float lightDistanceSquared = dot(lightOffset, lightOffset);
  84. float attenuation = computeDistanceLightFalloff(lightOffset, lightDistanceSquared, rangeRadius);
  85. // Directional falloff.
  86. float directionalAttenuation = computeDirectionalLightFalloff(lightDirection.xyz, directionToLightCenterW, lightDirection.w, lightData.w);
  87. attenuation *= directionalAttenuation;
  88. // Roughness.
  89. float lightDistance = sqrt(lightDistanceSquared);
  90. roughness = adjustRoughnessFromLightProperties(roughness, rangeRadius, lightDistance);
  91. // Diffuse
  92. vec3 H = normalize(viewDirectionW + directionToLightCenterW);
  93. NdotL = clamp(dot(vNormal, directionToLightCenterW), 0.000000000001, 1.0);
  94. float VdotH = clamp(dot(viewDirectionW, H), 0.0, 1.0);
  95. float diffuseTerm = computeDiffuseTerm(NdotL, NdotV, VdotH, roughness);
  96. result.diffuse = diffuseTerm * diffuseColor * attenuation;
  97. #ifdef SPECULARTERM
  98. // Specular
  99. float NdotH = clamp(dot(vNormal, H), 0.000000000001, 1.0);
  100. vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, reflectance0, reflectance90, geometricRoughnessFactor);
  101. result.specular = specTerm * diffuseColor * attenuation;
  102. #endif
  103. return result;
  104. }
  105. 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) {
  106. lightingInfo result;
  107. // Roughness
  108. // Do not touch roughness on hemispheric.
  109. // Diffuse
  110. NdotL = dot(vNormal, lightData.xyz) * 0.5 + 0.5;
  111. result.diffuse = mix(groundColor, diffuseColor, NdotL);
  112. #ifdef SPECULARTERM
  113. // Specular
  114. vec3 lightVectorW = normalize(lightData.xyz);
  115. vec3 H = normalize(viewDirectionW + lightVectorW);
  116. float NdotH = clamp(dot(vNormal, H), 0.000000000001, 1.0);
  117. NdotL = clamp(NdotL, 0.000000000001, 1.0);
  118. float VdotH = clamp(dot(viewDirectionW, H), 0.0, 1.0);
  119. vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, reflectance0, reflectance90, geometricRoughnessFactor);
  120. result.specular = specTerm * diffuseColor;
  121. #endif
  122. return result;
  123. }