95 lines
2.5 KiB
GLSL
95 lines
2.5 KiB
GLSL
#version 330 core
|
|
|
|
const float DIELECTRIC_SPECULAR = 0.04;
|
|
|
|
// math.glsl
|
|
float M_PI();
|
|
float M_1_PI();
|
|
float sqr(float x);
|
|
float pow5(float x);
|
|
|
|
/*
|
|
* Fresnel, Schlick's approximation.
|
|
*/
|
|
vec3 F_Schlick(float VdotH, vec3 f0)
|
|
{
|
|
return f0 + (vec3(1.0) - f0) * pow5(clamp(1.0 - VdotH, 0.0, 1.0));
|
|
}
|
|
|
|
/*
|
|
* Fresnel, Schlick's approximation, monochromatic.
|
|
*/
|
|
float F_Schlick(float VdotH, float f0)
|
|
{
|
|
return f0 + (1.0 - f0) * pow5(clamp(1.0 - VdotH, 0.0, 1.0));
|
|
}
|
|
|
|
/*
|
|
* Normal distribution function, Trowbridge-Reitz/GGX microfacet distribution.
|
|
*/
|
|
float D_GGX(float NdotH, float a2)
|
|
{
|
|
float f = (NdotH * a2 - NdotH) * NdotH + 1.0;
|
|
return M_PI() * f * f;
|
|
}
|
|
|
|
/*
|
|
* Geometric attenuation, Smith-GGX formulation.
|
|
*/
|
|
float G1_Smith_GGX(float NdotX, float a2)
|
|
{
|
|
return NdotX + sqrt(NdotX * (NdotX - NdotX * a2) + a2);
|
|
}
|
|
|
|
/*
|
|
* Get the Fresnel reflectance at 0 degrees (light hitting the surface
|
|
* perpendicularly) from PBR parameters.
|
|
*/
|
|
vec3 f0_from_pbr(vec3 base_color, float metallic)
|
|
{
|
|
return mix(vec3(DIELECTRIC_SPECULAR), base_color, metallic);
|
|
}
|
|
|
|
/*
|
|
* Evaluate the color of a standard PBR surface illuminated by an analytical
|
|
* light source. The evaluated BSDF consists of a specular lobe and a diffuse
|
|
* lobe. The specular lobe is the Cook-Torrance microfacet model, and the
|
|
* diffuse lobe is a simple Lambertian.
|
|
*
|
|
* Note that the calculations here do not match the literature. Brian Karis
|
|
* approach of refactoring by NdotX/NdotX has been used to optimize the code.
|
|
*/
|
|
vec3 surface_eval_analytical(
|
|
// Material
|
|
vec3 base_color, float metallic, float roughness, vec3 f0,
|
|
// Light
|
|
vec3 light_intensity, float occlusion,
|
|
// Vectors
|
|
vec3 N, vec3 L, vec3 V)
|
|
{
|
|
float NdotL = dot(N, L);
|
|
// Skip fragments that are completely occluded or that are not facing the light
|
|
if (occlusion <= 0.0 || NdotL <= 0.0)
|
|
return vec3(0.0);
|
|
NdotL = max(NdotL, 1e-4);
|
|
|
|
float a = max(sqr(roughness), 0.045);
|
|
float a2 = sqr(a);
|
|
|
|
vec3 H = normalize(L + V);
|
|
float NdotV = max(dot(N, V), 1e-4);
|
|
float NdotH = max(dot(N, H), 1e-4);
|
|
float VdotH = max(dot(V, H), 1e-4);
|
|
|
|
vec3 c_diff = mix(base_color * (1.0 - DIELECTRIC_SPECULAR), vec3(0.0), metallic);
|
|
|
|
vec3 F = F_Schlick(VdotH, f0);
|
|
float G = G1_Smith_GGX(NdotV, a2) * G1_Smith_GGX(NdotL, a2);
|
|
float D = D_GGX(NdotH, a2);
|
|
|
|
vec3 f_specular = (F * a2) / max(D * G, 1e-5);
|
|
vec3 f_diffuse = (vec3(1.0) - F) * c_diff * M_1_PI();
|
|
vec3 bsdf = f_diffuse + f_specular;
|
|
|
|
return bsdf * light_intensity * occlusion * NdotL;
|
|
}
|