summaryrefslogtreecommitdiff
path: root/pbr/ibl_specular/brdf.frag
blob: 6e7cf5b15768f34c8a193e23b6cf54f27a38e4b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#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);
}