pbrLightFunctions.fx 6.3 KB

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