pbrFunctions.fx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Constants
  2. #define RECIPROCAL_PI2 0.15915494
  3. #define FRESNEL_MAXIMUM_ON_ROUGH 0.25
  4. // PBR CUSTOM CONSTANTS
  5. const float kRougnhessToAlphaScale = 0.1;
  6. const float kRougnhessToAlphaOffset = 0.29248125;
  7. float convertRoughnessToAverageSlope(float roughness)
  8. {
  9. // Calculate AlphaG as square of roughness; add epsilon to avoid numerical issues
  10. const float kMinimumVariance = 0.0005;
  11. float alphaG = square(roughness) + kMinimumVariance;
  12. return alphaG;
  13. }
  14. // From Microfacet Models for Refraction through Rough Surfaces, Walter et al. 2007
  15. float smithVisibilityG1_TrowbridgeReitzGGX(float dot, float alphaG)
  16. {
  17. float tanSquared = (1.0 - dot * dot) / (dot * dot);
  18. return 2.0 / (1.0 + sqrt(1.0 + alphaG * alphaG * tanSquared));
  19. }
  20. float smithVisibilityG_TrowbridgeReitzGGX_Walter(float NdotL, float NdotV, float alphaG)
  21. {
  22. return smithVisibilityG1_TrowbridgeReitzGGX(NdotL, alphaG) * smithVisibilityG1_TrowbridgeReitzGGX(NdotV, alphaG);
  23. }
  24. // Trowbridge-Reitz (GGX)
  25. // Generalised Trowbridge-Reitz with gamma power=2.0
  26. float normalDistributionFunction_TrowbridgeReitzGGX(float NdotH, float alphaG)
  27. {
  28. // Note: alphaG is average slope (gradient) of the normals in slope-space.
  29. // It is also the (trigonometric) tangent of the median distribution value, i.e. 50% of normals have
  30. // a tangent (gradient) closer to the macrosurface than this slope.
  31. float a2 = square(alphaG);
  32. float d = NdotH * NdotH * (a2 - 1.0) + 1.0;
  33. return a2 / (PI * d * d);
  34. }
  35. vec3 fresnelSchlickGGX(float VdotH, vec3 reflectance0, vec3 reflectance90)
  36. {
  37. return reflectance0 + (reflectance90 - reflectance0) * pow(clamp(1.0 - VdotH, 0., 1.), 5.0);
  38. }
  39. vec3 fresnelSchlickEnvironmentGGX(float VdotN, vec3 reflectance0, vec3 reflectance90, float smoothness)
  40. {
  41. // Schlick fresnel approximation, extended with basic smoothness term so that rough surfaces do not approach reflectance90 at grazing angle
  42. float weight = mix(FRESNEL_MAXIMUM_ON_ROUGH, 1.0, smoothness);
  43. return reflectance0 + weight * (reflectance90 - reflectance0) * pow(clamp(1.0 - VdotN, 0., 1.), 5.0);
  44. }
  45. // Cook Torance Specular computation.
  46. vec3 computeSpecularTerm(float NdotH, float NdotL, float NdotV, float VdotH, float roughness, vec3 reflectance0, vec3 reflectance90)
  47. {
  48. float alphaG = convertRoughnessToAverageSlope(roughness);
  49. float distribution = normalDistributionFunction_TrowbridgeReitzGGX(NdotH, alphaG);
  50. float visibility = smithVisibilityG_TrowbridgeReitzGGX_Walter(NdotL, NdotV, alphaG);
  51. visibility /= (4.0 * NdotL * NdotV); // Cook Torance Denominator integated in viibility to avoid issues when visibility function changes.
  52. float specTerm = max(0., visibility * distribution) * NdotL;
  53. vec3 fresnel = fresnelSchlickGGX(VdotH, reflectance0, reflectance90);
  54. return fresnel * specTerm;
  55. }
  56. float computeDiffuseTerm(float NdotL, float NdotV, float VdotH, float roughness)
  57. {
  58. // Diffuse fresnel falloff as per Disney principled BRDF, and in the spirit of
  59. // of general coupled diffuse/specular models e.g. Ashikhmin Shirley.
  60. float diffuseFresnelNV = pow(clamp(1.0 - NdotL, 0.000001, 1.), 5.0);
  61. float diffuseFresnelNL = pow(clamp(1.0 - NdotV, 0.000001, 1.), 5.0);
  62. float diffuseFresnel90 = 0.5 + 2.0 * VdotH * VdotH * roughness;
  63. float fresnel =
  64. (1.0 + (diffuseFresnel90 - 1.0) * diffuseFresnelNL) *
  65. (1.0 + (diffuseFresnel90 - 1.0) * diffuseFresnelNV);
  66. return fresnel * NdotL / PI;
  67. }
  68. float adjustRoughnessFromLightProperties(float roughness, float lightRadius, float lightDistance)
  69. {
  70. #ifdef USEPHYSICALLIGHTFALLOFF
  71. // At small angle this approximation works.
  72. float lightRoughness = lightRadius / lightDistance;
  73. // Distribution can sum.
  74. float totalRoughness = clamp(lightRoughness + roughness, 0., 1.);
  75. return totalRoughness;
  76. #else
  77. return roughness;
  78. #endif
  79. }
  80. float computeDefaultMicroSurface(float microSurface, vec3 reflectivityColor)
  81. {
  82. const float kReflectivityNoAlphaWorkflow_SmoothnessMax = 0.95;
  83. float reflectivityLuminance = getLuminance(reflectivityColor);
  84. float reflectivityLuma = sqrt(reflectivityLuminance);
  85. microSurface = reflectivityLuma * kReflectivityNoAlphaWorkflow_SmoothnessMax;
  86. return microSurface;
  87. }
  88. // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
  89. // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
  90. float fresnelGrazingReflectance(float reflectance0) {
  91. float reflectance90 = clamp(reflectance0 * 25.0, 0.0, 1.0);
  92. return reflectance90;
  93. }
  94. // To enable 8 bit textures to be used we need to pack and unpack the LOD
  95. //inverse alpha is used to work around low-alpha bugs in Edge and Firefox
  96. #define UNPACK_LOD(x) (1.0 - x) * 255.0
  97. float getLodFromAlphaG(float cubeMapDimensionPixels, float alphaG, float NdotV) {
  98. float microsurfaceAverageSlope = alphaG;
  99. // Compensate for solid angle change between half-vector measure (Blinn-Phong) and reflected-vector measure (Phong):
  100. // dWr = 4*cos(theta)*dWh,
  101. // where dWr = solid angle (delta omega) in environment incident radiance (reflection-vector) measure;
  102. // where dWh = solid angle (delta omega) in microfacet normal (half-vector) measure;
  103. // so the relationship is proportional to cosine theta = NdotV.
  104. // The constant factor of four is handled elsewhere as part of the scale/offset filter parameters.
  105. microsurfaceAverageSlope *= sqrt(abs(NdotV));
  106. float microsurfaceAverageSlopeTexels = microsurfaceAverageSlope * cubeMapDimensionPixels;
  107. float lod = log2(microsurfaceAverageSlopeTexels);
  108. return lod;
  109. }
  110. float environmentRadianceOcclusion(float ambientOcclusion, float NdotVUnclamped) {
  111. // Best balanced (implementation time vs result vs perf) analytical environment specular occlusion found.
  112. // http://research.tri-ace.com/Data/cedec2011_RealtimePBR_Implementation_e.pptx
  113. float temp = NdotVUnclamped + ambientOcclusion;
  114. return clamp(square(temp) - 1.0 + ambientOcclusion, 0.0, 1.0);
  115. }
  116. float environmentHorizonOcclusion(vec3 reflection, vec3 normal) {
  117. // http://marmosetco.tumblr.com/post/81245981087
  118. #ifdef REFLECTIONMAP_OPPOSITEZ
  119. reflection.z *= -1.0;
  120. #endif
  121. float temp = clamp( 1.0 + 1.1 * dot(reflection, normal), 0.0, 1.0);
  122. return square(temp);
  123. }