|
|
@@ -15,85 +15,57 @@ const float LIGHT_FRUSTUM_NEAR_PLANE = 0.1 / 4.0;
|
|
|
const uint SHADOW_SAMPLE_COUNT = 16;
|
|
|
const float ESM_CONSTANT = 40.0;
|
|
|
|
|
|
-float computeAttenuationFactor(float lightRadius, vec3 frag2Light)
|
|
|
+// Fresnel term unreal
|
|
|
+vec3 F_Unreal(vec3 specular, float VoH)
|
|
|
{
|
|
|
- float fragLightDist = dot(frag2Light, frag2Light);
|
|
|
- float att = 1.0 - fragLightDist * lightRadius;
|
|
|
- att = max(0.0, att);
|
|
|
- return att * att;
|
|
|
+ return specular + (1.0 - specular) * pow(2.0, (-5.55473 * VoH - 6.98316) * VoH);
|
|
|
}
|
|
|
|
|
|
-vec3 fresnelSchlickRoughness(vec3 F0, float roughness, vec3 normal, vec3 viewDir)
|
|
|
+// D(n,h) aka NDF: GGX Trowbridge-Reitz
|
|
|
+float D_GGX(float roughness, float NoH)
|
|
|
{
|
|
|
- float cosTheta = max(dot(normal, viewDir), EPSILON);
|
|
|
- vec3 F = F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 + EPSILON - cosTheta, 5.0);
|
|
|
- return F;
|
|
|
+ float a = roughness * roughness;
|
|
|
+ float a2 = a * a;
|
|
|
+
|
|
|
+ float D = (NoH * a2 - NoH) * NoH + 1.0;
|
|
|
+ return a2 / (PI * D * D);
|
|
|
}
|
|
|
|
|
|
-// Compute the factors that will be used to calculat the final specular and diffuse indirect terms
|
|
|
-void computeSpecAndDiffuseIndirectFactors(
|
|
|
- vec3 viewDir, GbufferInfo gbuffer, sampler2D integrationLut, out vec3 specIndirectTerm, out vec3 diffIndirectTerm)
|
|
|
+// Visibility term: Geometric shadowing divided by BRDF denominator
|
|
|
+float V_Schlick(float roughness, float NoV, float NoL)
|
|
|
{
|
|
|
- // Reflectance
|
|
|
- float roughness2 = gbuffer.roughness * gbuffer.roughness;
|
|
|
- vec3 F0 = mix(gbuffer.specular, gbuffer.diffuse, gbuffer.metallic);
|
|
|
- vec3 F = fresnelSchlickRoughness(F0, roughness2, gbuffer.normal, viewDir);
|
|
|
-
|
|
|
- float ndotv = max(dot(gbuffer.normal, viewDir), EPSILON);
|
|
|
- vec2 envBRDF = texture(integrationLut, vec2(gbuffer.roughness, ndotv)).xy;
|
|
|
- specIndirectTerm = F * envBRDF.x + envBRDF.y;
|
|
|
+ float k = (roughness * roughness) * 0.5;
|
|
|
+ float Vis_SchlickV = NoV * (1.0 - k) + k;
|
|
|
+ float Vis_SchlickL = NoL * (1.0 - k) + k;
|
|
|
+ return 0.25 / (Vis_SchlickV * Vis_SchlickL);
|
|
|
+}
|
|
|
|
|
|
- vec3 kS = F;
|
|
|
- vec3 kD = 1.0 - kS;
|
|
|
- kD *= 1.0 - gbuffer.metallic;
|
|
|
+vec3 envBRDF(vec3 specular, float roughness, sampler2D integrationLut, float NoV)
|
|
|
+{
|
|
|
+ vec2 envBRDF = texture(integrationLut, vec2(roughness, NoV)).xy;
|
|
|
+ return specular * envBRDF.x + envBRDF.y;
|
|
|
+}
|
|
|
|
|
|
- diffIndirectTerm = kD * gbuffer.diffuse;
|
|
|
+vec3 diffuseLambert(vec3 diffuse)
|
|
|
+{
|
|
|
+ return diffuse * (1.0 / PI);
|
|
|
}
|
|
|
|
|
|
// Performs BRDF specular lighting
|
|
|
-vec3 computeSpecularColorBrdf(GbufferInfo gbuffer, vec3 viewDir, vec3 frag2Light, vec3 lightSpecCol)
|
|
|
+vec3 computeSpecularColorBrdf(GbufferInfo gbuffer, vec3 viewDir, vec3 frag2Light)
|
|
|
{
|
|
|
- float nol = max(0.0, dot(gbuffer.normal, frag2Light));
|
|
|
- vec3 h = normalize(frag2Light + viewDir);
|
|
|
- float a2 = gbuffer.roughness * gbuffer.roughness;
|
|
|
-
|
|
|
- // Fresnel
|
|
|
-#if 0
|
|
|
- // Schlick
|
|
|
- vec3 F = gbuffer.specular + (1.0 - gbuffer.specular) * pow((1.0 + EPSILON - loh), 5.0);
|
|
|
-#else
|
|
|
- // Unreal
|
|
|
- float voh = dot(viewDir, h);
|
|
|
- vec3 F = gbuffer.specular + (1.0 - gbuffer.specular) * pow(2.0, (-5.55473 * voh - 6.98316) * voh);
|
|
|
-#endif
|
|
|
+ vec3 H = normalize(frag2Light + viewDir);
|
|
|
|
|
|
- // D(n,h) aka NDF: GGX Trowbridge-Reitz
|
|
|
- float noh = dot(gbuffer.normal, h);
|
|
|
- float D = noh * noh * (a2 - 1.0) + 1.0;
|
|
|
- D = a2 / (PI * D * D);
|
|
|
-
|
|
|
- // G(frag2Light,viewDir,h)/(4*dot(n,h)*dot(n,viewDir)) aka Visibility term: Geometric shadowing divided by BRDF
|
|
|
- // denominator
|
|
|
-#if 0
|
|
|
- float nov = max(EPSILON, dot(n, viewDir));
|
|
|
- float V_v = nov + sqrt((nov - nov * a2) * nov + a2);
|
|
|
- float V_l = nol + sqrt((nol - nol * a2) * nol + a2);
|
|
|
- float V = 1.0 / (V_l * V_v);
|
|
|
-#else
|
|
|
- float k = (a2 + 1.0);
|
|
|
- k = k * k / 8.0;
|
|
|
- float nov = max(EPSILON, dot(gbuffer.normal, viewDir));
|
|
|
- float V_v = nov * (1.0 - k) + k;
|
|
|
- float V_l = nol * (1.0 - k) + k;
|
|
|
- float V = 1.0 / (4.0 * V_l * V_v);
|
|
|
-#endif
|
|
|
+ float NoL = max(EPSILON, dot(gbuffer.normal, frag2Light));
|
|
|
+ float VoH = max(EPSILON, dot(viewDir, H));
|
|
|
+ float NoH = max(EPSILON, dot(gbuffer.normal, H));
|
|
|
+ float NoV = max(EPSILON, dot(gbuffer.normal, viewDir));
|
|
|
|
|
|
- return F * (V * D) * lightSpecCol;
|
|
|
-}
|
|
|
+ vec3 F = F_Unreal(gbuffer.specular, VoH);
|
|
|
+ float D = D_GGX(gbuffer.roughness, NoH);
|
|
|
+ float V = V_Schlick(gbuffer.roughness, NoV, NoL);
|
|
|
|
|
|
-vec3 computeDiffuseColor(vec3 diffCol, vec3 lightDiffCol)
|
|
|
-{
|
|
|
- return diffCol * lightDiffCol;
|
|
|
+ return F * (V * D);
|
|
|
}
|
|
|
|
|
|
float computeSpotFactor(vec3 l, float outerCos, float innerCos, vec3 spotDir)
|
|
|
@@ -188,4 +160,12 @@ vec3 computeCubemapVecCheap(in vec3 r, in float R2, in vec3 f)
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
+float computeAttenuationFactor(float lightRadius, vec3 frag2Light)
|
|
|
+{
|
|
|
+ float fragLightDist = dot(frag2Light, frag2Light);
|
|
|
+ float att = 1.0 - fragLightDist * lightRadius;
|
|
|
+ att = max(0.0, att);
|
|
|
+ return att * att;
|
|
|
+}
|
|
|
+
|
|
|
#endif
|