summaryrefslogtreecommitdiff
path: root/pbr/ibl_specular/pbr.frag
blob: 3ed20181e4abc0821bcfe359eab04b19635f2d75 (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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#version 330 core

in vert_t {
	vec3 position;
	vec3 normal;
} vert;

out vec4 frag_color;

uniform vec3 camera;

uniform vec3 color;
uniform float metallic;
uniform float roughness;
uniform float ao;

uniform samplerCube irradiance_map;
uniform samplerCube prefilter_map;
uniform sampler2D brdf_lut;

struct light_t {
	vec3 position;
	vec3 color;
};

const int light_count = 4;
uniform light_t lights[light_count];

const float PI = 3.14159265358; 

vec3 fresnel_schlick(float costheta, vec3 f0)
{
	return f0 + (1.0 - f0) * pow(1.0 - costheta, 5.0);
}

vec3 fresnel_schlick_roughness(float costheta, vec3 f0, float roughness)
{
    return f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(clamp(1.0 - costheta, 0.0, 1.0), 5.0);
}   

float distribution_ggx(vec3 n, vec3 h, float roughness)
{
	float a = roughness * roughness;
	float a2 = a * a;
	float ndoth = max(dot(n, h), 0.0);
	float ndoth2 = ndoth * ndoth;

	float num = a2;
	float denom = (ndoth2 * (a2 - 1.0) + 1.0);
	denom = PI * denom * denom;

	return num / denom;
}

float geometry_schlick_ggx(float ndotv, float roughness)
{
	float r = roughness + 1.0;
	float k = r * r / 8.0;

	float num = ndotv;
	float denom = ndotv * (1.0 - k) + k;
	
	return num / 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 ggx2 = geometry_schlick_ggx(ndotv, roughness);
	float ggx1 = geometry_schlick_ggx(ndotl, roughness);

	return ggx1 * ggx2;
}

void main(void)
{
	vec3 n = vert.normal;
	vec3 v = normalize(camera - vert.position);
	vec3 r = reflect(-v, n);

	vec3 f0 = vec3(0.04);
	f0 = mix(f0, color, metallic);

	vec3 lo = vec3(0.0);
	for (int i = 0; i < light_count; i++) {
		vec3 l = normalize(lights[i].position - vert.position);
		vec3 h = normalize(v + l);
		float ndotv = max(dot(n, v), 0.0);
		float ndotl = max(dot(n, l), 0.0);

		float distance = length(lights[i].position - vert.position);
		float attenuation = 1.0 / (distance * distance);

		vec3 radiance = lights[i].color * attenuation;

		vec3 f = fresnel_schlick(max(dot(h, v), 0.0), f0);

		float ndf = distribution_ggx(n, h, roughness);
		float g = geometry_smith(n, v, l, roughness);

		vec3 numerator = ndf * g * f;
		float denominator = 4.0 * ndotv * ndotl;
		vec3 specular = numerator / max(denominator, 0.001);

		vec3 ks = f;
		vec3 kd = vec3(1.0) - ks;

		kd *= 1.0 - metallic;

		lo += (kd * color / PI + specular) * radiance * ndotl;
	}

	vec3 f = fresnel_schlick_roughness(max(dot(n, v), 0.0), f0, roughness);

	vec3 ks = f;
	vec3 kd = 1.0 - ks;
	kd *= 1.0 - metallic;

	vec3 irradiance = texture(irradiance_map, n).rgb;
	vec3 diffuse = irradiance * color;

	float max_reflection_lod = 4.0;
	vec3 prefiltered = textureLod(prefilter_map, r, roughness * max_reflection_lod).rgb;
	vec2 brdf = texture(brdf_lut, vec2(max(dot(n, v), 0.0), roughness)).rg;
	vec3 specular = prefiltered * (f * brdf.x + brdf.y);

	vec3 ambient = (kd * diffuse + specular)* ao;

	frag_color = vec4(ambient + lo, 1.0);
}