#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
in vec3 WorldPos;
in vec3 Normal;// material parameters
uniform vec3 albedo;
uniform float metallic;
uniform float roughness;
uniform float ao;// lights
uniform vec3 lightPositions[4];
uniform vec3 lightColors[4];
uniform vec3 camPos;constfloat PI =3.14159265359;// ----------------------------------------------------------------------------floatDistributionGGX(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 nom = a2;float denom =(NdotH2 *(a2 -1.0)+1.0);
denom = PI * denom * denom;return nom / denom;}// ----------------------------------------------------------------------------floatGeometrySchlickGGX(float NdotV,float roughness){float r =(roughness +1.0);float k =(r*r)/8.0;float nom = NdotV;float denom = NdotV *(1.0- k)+ k;return nom / denom;}// ----------------------------------------------------------------------------floatGeometrySmith(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 =GeometrySchlickGGX(NdotV, roughness);float ggx1 =GeometrySchlickGGX(NdotL, roughness);return ggx1 * ggx2;}// ----------------------------------------------------------------------------
vec3 fresnelSchlick(float cosTheta, vec3 F0){return F0 +(1.0- F0)*pow(clamp(1.0- cosTheta,0.0,1.0),5.0);}// ----------------------------------------------------------------------------voidmain(){
vec3 N =normalize(Normal);
vec3 V =normalize(camPos - WorldPos);// calculate reflectance at normal incidence; if dia-electric (like plastic) use F0 // of 0.04 and if it's a metal, use the albedo color as F0 (metallic workflow)
vec3 F0 =vec3(0.04);
F0 =mix(F0, albedo, metallic);// reflectance equation
vec3 Lo =vec3(0.0);for(int i =0; i <4;++i){// calculate per-light radiance
vec3 L =normalize(lightPositions[i]- WorldPos);
vec3 H =normalize(V + L);float distance =length(lightPositions[i]- WorldPos);float attenuation =1.0/(distance * distance);
vec3 radiance = lightColors[i]* attenuation;// Cook-Torrance BRDFfloat NDF =DistributionGGX(N, H, roughness);float G =GeometrySmith(N, V, L, roughness);
vec3 F =fresnelSchlick(clamp(dot(H, V),0.0,1.0), F0);
vec3 numerator = NDF * G * F;float denominator =4*max(dot(N, V),0.0)*max(dot(N, L),0.0)+0.0001;// + 0.0001 to prevent divide by zero
vec3 specular = numerator / denominator;// kS is equal to Fresnel
vec3 kS = F;// for energy conservation, the diffuse and specular light can't// be above 1.0 (unless the surface emits light); to preserve this// relationship the diffuse component (kD) should equal 1.0 - kS.
vec3 kD =vec3(1.0)- kS;// multiply kD by the inverse metalness such that only non-metals // have diffuse lighting, or a linear blend if partly metal (pure metals// have no diffuse light).
kD *=1.0- metallic;// scale light by NdotLfloat NdotL =max(dot(N, L),0.0);// add to outgoing radiance Lo
Lo +=(kD * albedo / PI + specular)* radiance * NdotL;// note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again}// ambient lighting (note that the next IBL tutorial will replace // this ambient lighting with environment lighting).
vec3 ambient =vec3(0.03)* albedo * ao;
vec3 color = ambient + Lo;// HDR tonemapping
color = color /(color +vec3(1.0));// gamma correct
color =pow(color,vec3(1.0/2.2));
FragColor =vec4(color,1.0);}