aboutsummaryrefslogtreecommitdiff
path: root/shaders/brdf_integration_map.frag
diff options
context:
space:
mode:
Diffstat (limited to 'shaders/brdf_integration_map.frag')
-rw-r--r--shaders/brdf_integration_map.frag93
1 files changed, 93 insertions, 0 deletions
diff --git a/shaders/brdf_integration_map.frag b/shaders/brdf_integration_map.frag
new file mode 100644
index 0000000..bb2cebd
--- /dev/null
+++ b/shaders/brdf_integration_map.frag
@@ -0,0 +1,93 @@
1precision highp float;
2
3#define PI 3.1415926535897932384626433832795
4#define NUM_SAMPLES 1024
5
6in vec2 Texcoord;
7
8layout (location = 0) out vec2 Color;
9
10float radical_inverse_VdC(uint bits) {
11 bits = (bits << 16u) | (bits >> 16u);
12 bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
13 bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
14 bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
15 bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
16 return float(bits) * 2.3283064365386963e-10; // / 0x100000000
17}
18
19vec2 hammersley(uint i, uint N) {
20 return vec2(float(i)/float(N), radical_inverse_VdC(i));
21}
22
23vec3 importance_sample_GGX(vec2 sample_box, vec3 N, float roughness) {
24 float r2 = roughness * roughness;
25
26 // Spherical coordinates.
27 float phi = 2.0 * PI * sample_box.x;
28 float cos_theta = sqrt((1.0 - sample_box.y) / (1.0 + (r2*r2 - 1.0) * sample_box.y));
29 float sin_theta = sqrt(1.0 - cos_theta * cos_theta);
30
31 // Map spherical coordinates to Cartesian coordinates in tangent space.
32 vec3 H = vec3(cos(phi) * sin_theta, sin(phi) * sin_theta, cos_theta);
33
34 // Map from tangent space to world space.
35 //
36 // Tangent space:
37 //
38 // N
39 // |
40 // |
41 // |
42 // |_ _ _ _ _ B
43 // /
44 // /
45 // T
46 vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
47 vec3 T = normalize(cross(up,N));
48 vec3 B = cross(N,T);
49 vec3 H_ws = H.x*T + H.y*B + H.z*N;
50 return H_ws;
51}
52
53float geometry_schlick_GGX(float k, float NdotV) {
54 return NdotV / (NdotV * (1.0 - k) + k);
55}
56
57float geometry_smith(float roughness, float NdotL, float NdotV) {
58 float k = roughness * roughness / 2.0; // IBL
59 return geometry_schlick_GGX(k, NdotV) * geometry_schlick_GGX(k, NdotL);
60}
61
62vec2 integrate_brdf(float NdotV, float roughness)
63{
64 vec3 V = vec3(sqrt(1.0 - NdotV * NdotV), 0.0, NdotV);
65 vec3 N = vec3(0.0, 0.0, 1.0);
66
67 float scale = 0.0;
68 float bias = 0.0;
69 for (int i = 0; i < NUM_SAMPLES; ++i) {
70 vec2 sample_box = hammersley(i, NUM_SAMPLES);
71 vec3 H = importance_sample_GGX(sample_box, N, roughness);
72 vec3 L = reflect(-V,H);
73 float NdotL = max(0.0, L.z);
74
75 if (NdotL > 0.0) {
76 float NdotH = max(0.0, H.z);
77 float VdotH = max(0.0, dot(V,H));
78 float G = geometry_smith(roughness, NdotL, NdotV);
79 float G_vis = (G * VdotH) / (NdotH * NdotV);
80 float Fc = pow(1.0 - VdotH, 5.0);
81 scale += (1.0 - Fc) * G_vis;
82 bias += Fc * G_vis;
83 }
84 }
85 scale /= float(NUM_SAMPLES);
86 bias /= float(NUM_SAMPLES);
87 return vec2(scale, bias);
88}
89
90void main()
91{
92 Color = integrate_brdf(Texcoord.x, Texcoord.y);
93}