#version 330 core in vert_t { vec2 tex_coords; } vert; out vec2 frag_color; const float PI = 3.14159265359; float radical_inverse_vdc(uint bits) { bits = (bits << 16u) | (bits >> 16u); bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); return float(bits) * 2.3283064365386963e-10; // / 0x100000000 } vec2 hammersley(uint i, uint n) { return vec2(float(i) / float(n), radical_inverse_vdc(i)); } vec3 importance_sample_ggx(vec2 xi, vec3 n, float roughness) { float a = roughness * roughness; float phi = 2.0 * PI * xi.x; float cos_theta = sqrt((1.0 - xi.y) / (1.0 + (a * a - 1.0) * xi.y)); float sin_theta = sqrt(1.0 - cos_theta * cos_theta); vec3 h; h.x = cos(phi) * sin_theta; h.y = sin(phi) * sin_theta; h.z = cos_theta; vec3 up = abs(n.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); vec3 tangent = normalize(cross(up, n)); vec3 bitangent = cross(n, tangent); vec3 samplevec = tangent * h.x + bitangent * h.y + n * h.z; return normalize(samplevec); } float geometry_schlick_ggx(float ndotv, float roughness) { float a = roughness; float k = (a * a) / 2.0; float nom = ndotv; float denom = ndotv * (1.0 - k) + k; return nom / denom; } float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) { float ndotv = max(dot(n, v), 0.0); float ndotl = max(dot(n, l), 0.0); float ggx1 = geometry_schlick_ggx(ndotl, roughness); float ggx2 = geometry_schlick_ggx(ndotv, roughness); return ggx1 * ggx2; } vec2 integrate_brdf(float ndotv, float roughness) { vec3 v; v.x = sqrt(1.0 - ndotv * ndotv); v.y = 0.0; v.z = ndotv; float a = 0.0; float b = 0.0; vec3 n = vec3(0.0, 0.0, 1.0); uint sample_count = 1024u; for (uint i = 0u; i < sample_count; i++) { vec2 xi = hammersley(i, sample_count); vec3 h = importance_sample_ggx(xi, n, roughness); vec3 l = normalize(2.0 * dot(v, h) * h - v); float ndotl = max(l.z, 0.0); float ndoth = max(h.z, 0.0); float vdoth = max(dot(v, h), 0.0); if (ndotl > 0.0) { float g = geometry_smith(n, v, l, roughness); float g_vis = (g * vdoth) / (ndoth * ndotv); float fc = pow(1.0 - vdoth, 5.0); a += (1.0 - fc) * g_vis; b += fc * g_vis; } } a /= float(sample_count); b /= float(sample_count); return vec2(a, b); } void main() { frag_color = integrate_brdf(vert.tex_coords.x, vert.tex_coords.y); }