You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
4.1 KiB

  1. /*******************************************************************************************
  2. *
  3. * rPBR [shader] - Bidirectional reflectance distribution function fragment shader
  4. *
  5. * Copyright (c) 2017 Victor Fisac
  6. *
  7. **********************************************************************************************/
  8. #version 330
  9. #define MAX_SAMPLES 1024u
  10. // Input vertex attributes (from vertex shader)
  11. in vec2 fragTexCoord;
  12. // Constant values
  13. const float PI = 3.14159265359;
  14. // Output fragment color
  15. out vec4 finalColor;
  16. float DistributionGGX(vec3 N, vec3 H, float roughness);
  17. float RadicalInverse_VdC(uint bits);
  18. vec2 Hammersley(uint i, uint N);
  19. vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness);
  20. float GeometrySchlickGGX(float NdotV, float roughness);
  21. float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness);
  22. vec2 IntegrateBRDF(float NdotV, float roughness);
  23. float DistributionGGX(vec3 N, vec3 H, float roughness)
  24. {
  25. float a = roughness*roughness;
  26. float a2 = a*a;
  27. float NdotH = max(dot(N, H), 0.0);
  28. float NdotH2 = NdotH*NdotH;
  29. float nom = a2;
  30. float denom = (NdotH2*(a2 - 1.0) + 1.0);
  31. denom = PI*denom*denom;
  32. return nom/denom;
  33. }
  34. float RadicalInverse_VdC(uint bits)
  35. {
  36. bits = (bits << 16u) | (bits >> 16u);
  37. bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
  38. bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
  39. bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
  40. bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
  41. return float(bits) * 2.3283064365386963e-10; // / 0x100000000
  42. }
  43. vec2 Hammersley(uint i, uint N)
  44. {
  45. return vec2(float(i)/float(N), RadicalInverse_VdC(i));
  46. }
  47. vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
  48. {
  49. float a = roughness*roughness;
  50. float phi = 2.0 * PI * Xi.x;
  51. float cosTheta = sqrt((1.0 - Xi.y)/(1.0 + (a*a - 1.0)*Xi.y));
  52. float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
  53. // Transform from spherical coordinates to cartesian coordinates (halfway vector)
  54. vec3 H = vec3(cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta);
  55. // Transform from tangent space H vector to world space sample vector
  56. vec3 up = ((abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0));
  57. vec3 tangent = normalize(cross(up, N));
  58. vec3 bitangent = cross(N, tangent);
  59. vec3 sampleVec = tangent*H.x + bitangent*H.y + N*H.z;
  60. return normalize(sampleVec);
  61. }
  62. float GeometrySchlickGGX(float NdotV, float roughness)
  63. {
  64. // For IBL k is calculated different
  65. float k = (roughness*roughness)/2.0;
  66. float nom = NdotV;
  67. float denom = NdotV*(1.0 - k) + k;
  68. return nom/denom;
  69. }
  70. float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
  71. {
  72. float NdotV = max(dot(N, V), 0.0);
  73. float NdotL = max(dot(N, L), 0.0);
  74. float ggx2 = GeometrySchlickGGX(NdotV, roughness);
  75. float ggx1 = GeometrySchlickGGX(NdotL, roughness);
  76. return ggx1*ggx2;
  77. }
  78. vec2 IntegrateBRDF(float NdotV, float roughness)
  79. {
  80. vec3 V = vec3(sqrt(1.0 - NdotV*NdotV), 0.0, NdotV);
  81. float A = 0.0;
  82. float B = 0.0;
  83. vec3 N = vec3(0.0, 0.0, 1.0);
  84. for(uint i = 0u; i < MAX_SAMPLES; i++)
  85. {
  86. // Generate a sample vector that's biased towards the preferred alignment direction (importance sampling)
  87. vec2 Xi = Hammersley(i, MAX_SAMPLES);
  88. vec3 H = ImportanceSampleGGX(Xi, N, roughness);
  89. vec3 L = normalize(2.0*dot(V, H)*H - V);
  90. float NdotL = max(L.z, 0.0);
  91. float NdotH = max(H.z, 0.0);
  92. float VdotH = max(dot(V, H), 0.0);
  93. if (NdotL > 0.0)
  94. {
  95. float G = GeometrySmith(N, V, L, roughness);
  96. float G_Vis = (G*VdotH)/(NdotH*NdotV);
  97. float Fc = pow(1.0 - VdotH, 5.0);
  98. A += (1.0 - Fc)*G_Vis;
  99. B += Fc*G_Vis;
  100. }
  101. }
  102. // Calculate brdf average sample
  103. A /= float(MAX_SAMPLES);
  104. B /= float(MAX_SAMPLES);
  105. return vec2(A, B);
  106. }
  107. void main()
  108. {
  109. // Calculate brdf based on texture coordinates
  110. vec2 brdf = IntegrateBRDF(fragTexCoord.x, fragTexCoord.y);
  111. // Calculate final fragment color
  112. finalColor = vec4(brdf.r, brdf.g, 0.0, 1.0);
  113. }