brdf.chunk 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include <common/math/number>
  2. // for dielectric(non-metal) surfaces
  3. float F0ToIor(float F0)
  4. {
  5. return 2.0f / (1.0f - sqrt(F0)) - 1.0f;
  6. }
  7. float IorToF0(float ior)
  8. {
  9. float F0_sqrt = (ior-1.0) / (ior+1.0);
  10. return F0_sqrt * F0_sqrt;
  11. }
  12. float square(float a) { return a * a;}
  13. vec2 square(vec2 a) { return a * a;}
  14. vec3 square(vec3 a) { return a * a;}
  15. float G_Schlick( float roughness, float NoV, float NoL )
  16. {
  17. float k = square( 0.5 + 0.5*roughness );
  18. float G_SchlickV = NoV * (1.0 - k) + k;
  19. float G_SchlickL = NoL * (1.0 - k) + k;
  20. return 0.25 / ( G_SchlickV * G_SchlickL );
  21. }
  22. vec3 F_Schlick( vec3 specularColor, float VoH )
  23. {
  24. float Fc = exp2( (-5.55473 * VoH - 6.98316) * VoH );
  25. float selfShadowTerm = saturate(50.0 * specularColor.g);
  26. return specularColor * (1.0 - Fc) + vec3(selfShadowTerm * Fc);
  27. }
  28. vec3 F_SchlickMultiplier( vec3 specularColor, float VoH )
  29. {
  30. float Fc = exp2( (-5.55473 * VoH - 6.98316) * VoH );
  31. float selfShadowTerm = saturate(50.0 * specularColor.g);
  32. return vec3(1.0 - Fc) + vec3(selfShadowTerm * Fc) / (specularColor + vec3(EPSILON));
  33. }
  34. float D_GGX(float roughness, float NoH)
  35. {
  36. float m = roughness * roughness;
  37. float m2 = m * m;
  38. float d = (NoH * m2 - NoH) * NoH + 1.0;
  39. return m2 / max(EPSILON, d * d);
  40. }
  41. float D_GGXMobile(float roughness, float NoH) {
  42. float OneMinusNoHSqr = 1.0 - NoH * NoH;
  43. float a = roughness * roughness;
  44. float n = NoH * a;
  45. float p = a / max(EPSILON, OneMinusNoHSqr + n * n);
  46. return p * p;
  47. }
  48. void GetAnisotropicRoughness(float roughness, float anisotropyShape, out float roughnessX, out float roughnessY)
  49. {
  50. float shapeSign = sign(anisotropyShape);
  51. anisotropyShape *= anisotropyShape;
  52. float r1 = roughness, r2 = roughness;
  53. float lerpedRoughness = mix(1.0, 10.0, anisotropyShape);
  54. r2 *= shapeSign < 0.0 ? lerpedRoughness : 1.0;
  55. r1 *= shapeSign > 0.0 ? lerpedRoughness : 1.0;
  56. roughnessX = saturate(r1);
  57. roughnessY = saturate(r2);
  58. }
  59. // How to get an anisotropic offset along T/B:
  60. // 1. accurate: rotation TBN basis, let N intend to T/B, such as flow map as normalmap, output vec3(0, delta, 1) instead of vec3(0, 0, 1)
  61. // 2. not accurate: H intend to V, and passed to this function
  62. float D_GGXAniso(float RoughnessX, float RoughnessY, float NoH, vec3 H, vec3 X, vec3 Y)
  63. {
  64. float mx = max(EPSILON_LOWP, RoughnessX * RoughnessX);
  65. float my = max(EPSILON_LOWP, RoughnessY * RoughnessY);
  66. float XoH = dot(X, H);
  67. float YoH = dot(Y, H);
  68. float d = XoH * XoH / (mx * mx) + YoH * YoH / (my * my) + NoH * NoH;
  69. return 1.0 / max(EPSILON_LOWP, mx * my * d * d);
  70. }
  71. vec3 GetAnisotropicReflect(float roughness, float anisotropyShape, vec3 V, vec3 N, vec3 X, vec3 Y)
  72. {
  73. float shapeSign = sign(anisotropyShape);
  74. anisotropyShape *= anisotropyShape;
  75. //clamp to shape=0.6x for invert reflection artifact
  76. anisotropyShape = min(anisotropyShape, 0.4);
  77. // roughness->0 means optical smooth surface (back to isotropic)
  78. anisotropyShape *= smoothstep(0.0, 0.03, roughness);
  79. // use view co-planar vector instead of XoH->0 plane convolution, but not accuracy
  80. vec3 reflectTarget = shapeSign < 0.0 ? mix(N, -Y, anisotropyShape) :
  81. shapeSign > 0.0 ? mix(N, -X, anisotropyShape) : N;
  82. return reflect(-V, reflectTarget);
  83. }
  84. // EnvBRDFApprox
  85. vec3 IntegratedGFApprox (vec3 specular, float roughness, float NoV) {
  86. const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
  87. const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
  88. vec4 r = roughness * c0 + c1;
  89. float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;
  90. vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;
  91. AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);
  92. return max(vec3(0.0), specular * AB.x + AB.y);
  93. }
  94. void IntegratedGFMultiplier (out vec3 integratedGF, out vec3 integratedF, vec3 specular, float roughness, float NoV) {
  95. const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
  96. const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
  97. vec4 r = roughness * c0 + c1;
  98. float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;
  99. vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;
  100. AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);
  101. integratedF = vec3(max(0.0, AB.x));
  102. integratedGF = max(vec3(0.0), vec3(AB.x) + vec3(AB.y) / (specular + EPSILON_LOWP));
  103. }
  104. // isotropic sheen
  105. float Sheen_HorizonFading(float NoL)
  106. {
  107. const float horizonFade = 1.3;
  108. float horiz = saturate( 1.0 + horizonFade * NoL);
  109. return horiz * horiz;
  110. }
  111. float Sheen(float NoHSat, float NoL, float NoV, float roughness)
  112. {
  113. if (NoL <= 0.0 || NoV <= 0.0)
  114. return 0.0;
  115. float NoH2 = NoHSat*NoHSat;
  116. float NoL2 = NoL*NoL;
  117. float NoV2 = NoV*NoV;
  118. roughness += EPSILON_LOWP;
  119. float r2 = roughness*roughness;
  120. float t = 1.0 - NoH2 + NoH2/r2;
  121. float Pi_D = 1.0 / (roughness * t * t);
  122. float Li = sqrt(1.0 - NoL2 + r2*NoL2) / NoL;
  123. float Lo = sqrt(1.0 - NoV2 + r2*NoV2) / NoV;
  124. float G = (1.0 - exp(-(Li + Lo))) / (Li + Lo);
  125. return Sheen_HorizonFading(NoL) * Pi_D * G / NoV;
  126. }
  127. // simplify estimation for env lighting convolution
  128. float Sheen(float NoV, float roughness)
  129. {
  130. NoV *= NoV;
  131. float NoV2 = NoV*NoV;
  132. roughness += EPSILON_LOWP;
  133. float r2 = roughness*roughness;
  134. float t = 1.0 - NoV2 + NoV2/r2;
  135. float Pi_D = 1.0 / (roughness * t * t);
  136. float Lo = sqrt(1.0 - NoV2 + r2*NoV2) / NoV;
  137. float G = (1.0 - exp(-Lo)) / Lo;
  138. float sheen = Pi_D * G / NoV;
  139. return pow(max(0.0, sheen), 0.5);
  140. }
  141. // Diffuse_Lambert
  142. #define DiffuseCoefficient_EnergyConservation INV_PI