#version 140 // created by Thorsten Thormaehlen for educational purpose out vec4 outColor; in vec2 tc; in vec3 fn; in vec3 vertPos; uniform int mode; uniform vec3 lightDirection; uniform float metallic; uniform float roughness; const vec4 uBaseColor = vec4(0.25, 0.0, 0.0, 1.0); const float uReflectance = 0.5; const vec4 uAmbientColor = vec4(0.0, 0.0, 0.0, 1.0); const vec4 uLightColor = vec4(1.0, 1.0, 1.0, 1.0); const float uIrradiPerp = 18.0; #define RECIPROCAL_PI 0.3183098861837907 vec3 rgb2lin(vec3 rgb) { // sRGB to linear approximation return pow(rgb, vec3(2.2)); } vec3 lin2rgb(vec3 lin) { // linear to sRGB approximation return pow(lin, vec3(1.0 / 2.2)); } vec3 fresnelSchlick(float cosTheta, vec3 F0) { return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); } float D_GGX(float NoH, float roughness) { float alpha = roughness * roughness; float alpha2 = alpha * alpha; float NoH2 = NoH * NoH; float b = (NoH2 * (alpha2 - 1.0) + 1.0); return alpha2 * RECIPROCAL_PI / (b * b); } float G1_GGX_Schlick(float NoV, float roughness) { float alpha = roughness * roughness; float k = alpha / 2.0; return max(NoV, 0.001) / (NoV * (1.0 - k) + k); } float G_Smith(float NoV, float NoL, float roughness) { return G1_GGX_Schlick(NoL, roughness) * G1_GGX_Schlick(NoV, roughness); } float fresnelSchlick90(float cosTheta, float F0, float F90) { return F0 + (F90 - F0) * pow(1.0 - cosTheta, 5.0); } float disneyDiffuseFactor(float NoV, float NoL, float VoH, float roughness) { float alpha = roughness * roughness; float F90 = 0.5 + 2.0 * alpha * VoH * VoH; float F_in = fresnelSchlick90(NoL, 1.0, F90); float F_out = fresnelSchlick90(NoV, 1.0, F90); return F_in * F_out; } vec3 microfacetBRDF(in vec3 L, in vec3 V, in vec3 N, in float metallic, in float roughness, in vec3 baseColor, in float reflectance) { vec3 H = normalize(V + L); float NoV = clamp(dot(N, V), 0.0, 1.0); float NoL = clamp(dot(N, L), 0.0, 1.0); float NoH = clamp(dot(N, H), 0.0, 1.0); float VoH = clamp(dot(V, H), 0.0, 1.0); vec3 f0 = vec3(0.16 * (reflectance * reflectance)); f0 = mix(f0, baseColor, metallic); vec3 F = fresnelSchlick(VoH, f0); float D = D_GGX(NoH, roughness); float G = G_Smith(NoV, NoL, roughness); vec3 spec = (F * D * G) / (4.0 * max(NoV, 0.001) * max(NoL, 0.001)); vec3 rhoD = baseColor; // optionally rhoD *= vec3(1.0) - F; // rhoD *= disneyDiffuseFactor(NoV, NoL, VoH, roughness); rhoD *= (1.0 - metallic); vec3 diff = rhoD * RECIPROCAL_PI; return diff + spec; } void main() { vec3 lightDir = normalize(-lightDirection); vec3 viewDir = normalize(-vertPos); vec3 n = normalize(fn); vec3 radiance = rgb2lin(uAmbientColor.rgb); float irradiance = max(dot(lightDir, n), 0.0) * uIrradiPerp; if(irradiance > 0.0) { vec3 brdf = microfacetBRDF(lightDir, viewDir, n, metallic, roughness, rgb2lin(uBaseColor.rgb), uReflectance); radiance += brdf * irradiance * rgb2lin(uLightColor.rgb); } outColor.rgb = lin2rgb(radiance); // gamma correction outColor.a = 1.0; }