brdf.glsl 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #ifndef _BRDF_GLSL_
  2. #define _BRDF_GLSL_
  3. // http://xlgames-inc.github.io/posts/improvedibl/
  4. // http://blog.selfshadow.com/publications/s2013-shading-course/
  5. vec3 f_schlick(const vec3 f0, const float vh) {
  6. return f0 + (1.0 - f0) * exp2((-5.55473 * vh - 6.98316) * vh);
  7. }
  8. float v_smithschlick(const float nl, const float nv, const float a) {
  9. return 1.0 / ((nl * (1.0 - a) + a) * (nv * (1.0 - a) + a));
  10. }
  11. float d_ggx(const float nh, const float a) {
  12. float a2 = a * a;
  13. float denom = pow(nh * nh * (a2 - 1.0) + 1.0, 2.0);
  14. return a2 * (1.0 / 3.1415926535) / denom;
  15. }
  16. vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const float nh, const float nv, const float vh) {
  17. float a = roughness * roughness;
  18. return d_ggx(nh, a) * clamp(v_smithschlick(nl, nv, a), 0.0, 1.0) * f_schlick(f0, vh) / 4.0;
  19. }
  20. // John Hable - Optimizing GGX Shaders
  21. // http://filmicworlds.com/blog/optimizing-ggx-shaders-with-dotlh/
  22. vec3 specularBRDFb(const vec3 f0, const float roughness, const float dotNL, const float dotNH, const float dotLH) {
  23. // D
  24. const float pi = 3.1415926535;
  25. float alpha = roughness * roughness;
  26. float alphaSqr = alpha * alpha;
  27. float denom = dotNH * dotNH * (alphaSqr - 1.0) + 1.0;
  28. float D = alphaSqr / (pi * denom * denom);
  29. // F
  30. const float F_a = 1.0;
  31. float F_b = pow(1.0 - dotLH, 5.0);
  32. // V
  33. float vis;
  34. float k = alpha / 2.0;
  35. float k2 = k * k;
  36. float invK2 = 1.0 - k2;
  37. vis = 1.0 / (dotLH * dotLH * invK2 + k2);
  38. vec2 FV_helper = vec2((F_a - F_b) * vis, F_b * vis);
  39. vec3 FV = f0 * FV_helper.x + FV_helper.y;
  40. vec3 specular = clamp(dotNL, 0.0, 1.0) * D * FV;
  41. return specular / 4.0; // TODO: get rid of / 4.0
  42. }
  43. vec3 orenNayarDiffuseBRDF(const vec3 albedo, const float roughness, const float nv, const float nl, const float vh) {
  44. float a = roughness * roughness;
  45. float s = a;
  46. float s2 = s * s;
  47. float vl = 2.0 * vh * vh - 1.0; // Double angle identity
  48. float Cosri = vl - nv * nl;
  49. float C1 = 1.0 - 0.5 * s2 / (s2 + 0.33);
  50. float test = 1.0;
  51. if (Cosri >= 0.0) test = (1.0 / (max(nl, nv)));
  52. float C2 = 0.45 * s2 / (s2 + 0.09) * Cosri * test;
  53. return albedo * max(0.0, nl) * (C1 + C2) * (1.0 + roughness * 0.5);
  54. }
  55. vec3 lambertDiffuseBRDF(const vec3 albedo, const float nl) {
  56. return albedo * max(0.0, nl);
  57. }
  58. vec3 surfaceAlbedo(const vec3 baseColor, const float metalness) {
  59. return mix(baseColor, vec3(0.0), metalness);
  60. }
  61. vec3 surfaceF0(const vec3 baseColor, const float metalness) {
  62. return mix(vec3(0.04), baseColor, metalness);
  63. }
  64. float getMipFromRoughness(const float roughness, const float numMipmaps) {
  65. // First mipmap level = roughness 0, last = roughness = 1
  66. return roughness * numMipmaps;
  67. }
  68. float wardSpecular(vec3 N, vec3 H, float dotNL, float dotNV, float dotNH, vec3 fiberDirection, float shinyParallel, float shinyPerpendicular) {
  69. if(dotNL < 0.0 || dotNV < 0.0) {
  70. return 0.0;
  71. }
  72. // fiberDirection - parse from rotation
  73. // shinyParallel - roughness
  74. // shinyPerpendicular - anisotropy
  75. vec3 fiberParallel = normalize(fiberDirection);
  76. vec3 fiberPerpendicular = normalize(cross(N, fiberDirection));
  77. float dotXH = dot(fiberParallel, H);
  78. float dotYH = dot(fiberPerpendicular, H);
  79. const float PI = 3.1415926535;
  80. float coeff = sqrt(dotNL/dotNV) / (4.0 * PI * shinyParallel * shinyPerpendicular);
  81. float theta = (pow(dotXH/shinyParallel, 2.0) + pow(dotYH/shinyPerpendicular, 2.0)) / (1.0 + dotNH);
  82. return clamp(coeff * exp(-2.0 * theta), 0.0, 1.0);
  83. }
  84. // https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
  85. // vec3 EnvBRDFApprox(vec3 SpecularColor, float Roughness, float NoV) {
  86. // const vec4 c0 = { -1, -0.0275, -0.572, 0.022 };
  87. // const vec4 c1 = { 1, 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. // return SpecularColor * AB.x + AB.y;
  92. // }
  93. // float EnvBRDFApproxNonmetal(float Roughness, float NoV) {
  94. // // Same as EnvBRDFApprox( 0.04, Roughness, NoV )
  95. // const vec2 c0 = { -1, -0.0275 };
  96. // const vec2 c1 = { 1, 0.0425 };
  97. // vec2 r = Roughness * c0 + c1;
  98. // return min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
  99. // }
  100. float D_Approx(const float Roughness, const float RoL) {
  101. float a = Roughness * Roughness;
  102. float a2 = a * a;
  103. float rcp_a2 = 1.0 / a2;//rcp(a2);
  104. // 0.5 / ln(2), 0.275 / ln(2)
  105. float c = 0.72134752 * rcp_a2 + 0.39674113;
  106. return rcp_a2 * exp2( c * RoL - c );
  107. }
  108. #endif