No Description

genbrdflut.frag 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. #version 450
  2. layout (location = 0) in vec2 inUV;
  3. layout (location = 0) out vec4 outColor;
  4. layout (constant_id = 0) const uint NUM_SAMPLES = 1024u;
  5. const float PI = 3.1415926536;
  6. // Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/
  7. float random(vec2 co)
  8. {
  9. float a = 12.9898;
  10. float b = 78.233;
  11. float c = 43758.5453;
  12. float dt= dot(co.xy ,vec2(a,b));
  13. float sn= mod(dt,3.14);
  14. return fract(sin(sn) * c);
  15. }
  16. vec2 hammersley2d(uint i, uint N)
  17. {
  18. // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
  19. uint bits = (i << 16u) | (i >> 16u);
  20. bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
  21. bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
  22. bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
  23. bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
  24. float rdi = float(bits) * 2.3283064365386963e-10;
  25. return vec2(float(i) /float(N), rdi);
  26. }
  27. // Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf
  28. vec3 importanceSample_GGX(vec2 Xi, float roughness, vec3 normal)
  29. {
  30. // Maps a 2D point to a hemisphere with spread based on roughness
  31. float alpha = roughness * roughness;
  32. float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1;
  33. float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y));
  34. float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
  35. vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
  36. // Tangent space
  37. vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
  38. vec3 tangentX = normalize(cross(up, normal));
  39. vec3 tangentY = normalize(cross(normal, tangentX));
  40. // Convert to world Space
  41. return normalize(tangentX * H.x + tangentY * H.y + normal * H.z);
  42. }
  43. // Geometric Shadowing function
  44. float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness)
  45. {
  46. float k = (roughness * roughness) / 2.0;
  47. float GL = dotNL / (dotNL * (1.0 - k) + k);
  48. float GV = dotNV / (dotNV * (1.0 - k) + k);
  49. return GL * GV;
  50. }
  51. vec2 BRDF(float NoV, float roughness)
  52. {
  53. // Normal always points along z-axis for the 2D lookup
  54. const vec3 N = vec3(0.0, 0.0, 1.0);
  55. vec3 V = vec3(sqrt(1.0 - NoV*NoV), 0.0, NoV);
  56. vec2 LUT = vec2(0.0);
  57. for(uint i = 0u; i < NUM_SAMPLES; i++) {
  58. vec2 Xi = hammersley2d(i, NUM_SAMPLES);
  59. vec3 H = importanceSample_GGX(Xi, roughness, N);
  60. vec3 L = 2.0 * dot(V, H) * H - V;
  61. float dotNL = max(dot(N, L), 0.0);
  62. float dotNV = max(dot(N, V), 0.0);
  63. float dotVH = max(dot(V, H), 0.0);
  64. float dotNH = max(dot(H, N), 0.0);
  65. if (dotNL > 0.0) {
  66. float G = G_SchlicksmithGGX(dotNL, dotNV, roughness);
  67. float G_Vis = (G * dotVH) / (dotNH * dotNV);
  68. float Fc = pow(1.0 - dotVH, 5.0);
  69. LUT += vec2((1.0 - Fc) * G_Vis, Fc * G_Vis);
  70. }
  71. }
  72. return LUT / float(NUM_SAMPLES);
  73. }
  74. void main()
  75. {
  76. outColor = vec4(BRDF(inUV.s, 1.0-inUV.t), 0.0, 1.0);
  77. }