vec3 IBLColor(vec3 viewDir)
{
//
// based on the split sum formula approximation
// L(v)=\int_\Omega L(l)f(l,v) \cos \theta_l
// which, by the split sum approiximation (assuming independence+GGX distrubition),
// roughly equals (within a margin of error)
// [\int_\Omega L(l)] * [\int_\Omega f(l,v) \cos \theta_l].
// the first term is the reflectance irradiance integral
vec3 IBLDiffuse=Diffuse*texture(diffuseSampler,normalizedAngle(normal)).rgb;
vec3 reflectVec=normalize(reflect(-viewDir,normal));
vec2 reflCoord=normalizedAngle(reflectVec);
vec3 IBLRefl=texture(reflImgSampler,vec3(reflCoord,Roughness)).rgb;
vec2 IBLbrdf=texture(reflBRDFSampler,vec2(dot(normal,viewDir),Roughness)).rg;
float specularMultiplier=Fresnel0*IBLbrdf.x+IBLbrdf.y;
vec3 dielectric=IBLDiffuse+specularMultiplier*IBLRefl;
vec3 metal=Diffuse*IBLRefl;
return mix(dielectric,metal,Metallic);
}
#else
// h is the halfway vector between normal and light direction
// GGX Trowbridge-Reitz Approximation
float NDF_TRG(vec3 h)
{
float ndoth=max(dot(normal,h),0.0);
float alpha2=Roughness2*Roughness2;
float denom=ndoth*ndoth*(alpha2-1.0)+1.0;
return denom != 0.0 ? alpha2/(denom*denom) : 0.0;
}
// Given a point x and direction \omega,
// L_i=\int_{\Omega}f(x,\omega_i,\omega) L(x,\omega_i)(\hat{n}\cdot \omega_i)
// d\omega_i, where \Omega is the hemisphere covering a point,
// f is the BRDF function, L is the radiance from a given angle and position.
normal=normalize(Normal);
normal=gl_FrontFacing ? normal : -normal;
#ifdef ORTHOGRAPHIC
vec3 viewDir=vec3(0.0,0.0,1.0);
#else
vec3 viewDir=-normalize(ViewPosition);
#endif
vec3 color;
#ifdef USE_IBL
color=IBLColor(viewDir);
#else
// For a finite point light, the rendering equation simplifies.
color=emissive.rgb;
for(uint i=0u; i < nlights; ++i) {
Light Li=lights[i];
vec3 L=Li.direction;
float cosTheta=max(dot(normal,L),0.0); // $\omega_i \cdot n$ term
vec3 radiance=cosTheta*Li.color;
color += BRDF(viewDir,L)*radiance;
}
#endif
outColor=vec4(color,diffuse.a);
#else
outColor=emissive;
#endif