#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; 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_shlick(float costheta, vec3 f0) { return f0 + (1.0 - f0) * pow(1.0 - costheta, 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_shlick_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_shlick_ggx(ndotv, roughness); float ggx1 = geometry_shlick_ggx(ndotl, roughness); return ggx1 * ggx2; } void main(void) { vec3 n = vert.normal; vec3 v = normalize(camera - vert.position); 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_shlick(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 ks = fresnel_shlick(max(dot(n, v), 0.0), f0); vec3 kd = 1.0 - ks; kd *= 1.0 - metallic; vec3 irradiance = texture(irradiance_map, n).rgb; vec3 diffuse = irradiance * color; vec3 ambient = kd * diffuse * ao; frag_color = vec4(ambient + lo, 1.0); }