Browse Source

Add filament's functions to specular and diffuse lobe calculations

Panagiotis Christopoulos Charitos 4 years ago
parent
commit
674dff8b43

+ 2 - 2
AnKi/Shaders/ForwardShadingCommonFrag.glsl

@@ -37,7 +37,7 @@ Vec4 readAnimatedTextureRgba(texture2DArray tex, sampler sampl, F32 period, Vec2
 // Iterate the clusters to compute the light color
 Vec3 computeLightColorHigh(Vec3 diffCol, Vec3 worldPos)
 {
-	diffCol = diffuseLambert(diffCol);
+	diffCol = diffuseLobe(diffCol);
 	Vec3 outColor = Vec3(0.0);
 
 	// Find the cluster and then the light counts
@@ -110,7 +110,7 @@ Vec3 computeLightColorLow(Vec3 diffCol, Vec3 worldPos)
 					 * (F32(u_clusteredShading.m_zSplitCount) / F32(u_clusteredShading.m_lightVolumeLastZSplit + 1u)));
 
 	const Vec3 light = textureLod(u_lightVol, u_linearAnyClampSampler, uvw, 0.0).rgb;
-	return diffuseLambert(diffCol) * light;
+	return diffuseLobe(diffCol) * light;
 }
 
 void particleAlpha(Vec4 color, Vec4 scaleColor, Vec4 biasColor)

+ 46 - 33
AnKi/Shaders/LightFunctions.glsl

@@ -78,71 +78,84 @@ Vec3 F_Unreal(Vec3 specular, F32 VoH)
 
 // Fresnel Schlick: "An Inexpensive BRDF Model for Physically-Based Rendering"
 // It has lower VGRPs than F_Unreal
-// specular: The specular color aka F0
-Vec3 F_Schlick(Vec3 specular, F32 VoH)
+ANKI_RP Vec3 F_Schlick(ANKI_RP Vec3 f0, ANKI_RP F32 VoH)
 {
-	const F32 a = 1.0 - VoH;
-	const F32 a2 = a * a;
-	const F32 a5 = a2 * a2 * a; // a5 = a^5
-	return /*saturate(50.0 * specular.g) */ a5 + (1.0 - a5) * specular;
+	const ANKI_RP F32 f = pow(1.0 - VoH, 5.0);
+	return f + f0 * (1.0 - f);
 }
 
 // D(n,h) aka NDF: GGX Trowbridge-Reitz
-F32 D_GGX(F32 roughness, F32 NoH)
+ANKI_RP F32 D_GGX(ANKI_RP F32 roughness, ANKI_RP F32 NoH, ANKI_RP Vec3 h, ANKI_RP Vec3 worldNormal)
 {
-	const F32 a = roughness * roughness;
-	const F32 a2 = a * a;
+#if ANKI_OS_ANDROID
+	const ANKI_RP Vec3 NxH = cross(worldNormal, h);
+	const ANKI_RP F32 oneMinusNoHSquared = dot(NxH, NxH);
+#else
+	const ANKI_RP F32 oneMinusNoHSquared = 1.0 - NoH * NoH;
+#endif
 
-	const F32 D = (NoH * a2 - NoH) * NoH + 1.0;
-	return a2 / (PI * D * D);
+	const ANKI_RP F32 a = roughness * roughness;
+	const ANKI_RP F32 v = NoH * a;
+	const ANKI_RP F32 k = a / (oneMinusNoHSquared + v * v);
+	const ANKI_RP F32 d = k * k * (1.0 / PI);
+	return saturateRp(d);
 }
 
 // Visibility term: Geometric shadowing divided by BRDF denominator
-F32 V_Schlick(F32 roughness, F32 NoV, F32 NoL)
+ANKI_RP F32 V_Schlick(ANKI_RP F32 roughness, ANKI_RP F32 NoV, ANKI_RP F32 NoL)
 {
-	const F32 k = (roughness * roughness) * 0.5;
-	const F32 Vis_SchlickV = NoV * (1.0 - k) + k;
-	const F32 Vis_SchlickL = NoL * (1.0 - k) + k;
+	const ANKI_RP F32 k = (roughness * roughness) * 0.5;
+	const ANKI_RP F32 Vis_SchlickV = NoV * (1.0 - k) + k;
+	const ANKI_RP F32 Vis_SchlickL = NoL * (1.0 - k) + k;
 	return 0.25 / (Vis_SchlickV * Vis_SchlickL);
 }
 
-Vec3 envBRDF(Vec3 specular, F32 roughness, texture2D integrationLut, sampler integrationLutSampler, F32 NoV)
+// Visibility term: Hammon 2017, "PBR Diffuse Lighting for GGX+Smith Microsurfaces"
+ANKI_RP F32 V_SmithGGXCorrelatedFast(ANKI_RP F32 roughness, ANKI_RP F32 NoV, ANKI_RP F32 NoL)
 {
-	const Vec2 envBRDF = textureLod(integrationLut, integrationLutSampler, Vec2(roughness, NoV), 0.0).xy;
-	return specular * envBRDF.x + min(1.0, 50.0 * specular.g) * envBRDF.y;
+	const ANKI_RP F32 a = roughness * roughness;
+	const ANKI_RP F32 v = 0.5 / mix(2.0 * NoL * NoV, NoL + NoV, a);
+	return saturateRp(v);
+}
+
+ANKI_RP F32 Fd_Lambert()
+{
+	return 1.0 / PI;
 }
 
-Vec3 diffuseLambert(Vec3 diffuse)
+ANKI_RP Vec3 diffuseLobe(ANKI_RP Vec3 diffuse)
 {
-	return diffuse * (1.0 / PI);
+	return diffuse * Fd_Lambert();
 }
 
 // Performs BRDF specular lighting
-Vec3 computeSpecularColorBrdf(GbufferInfo gbuffer, Vec3 viewDir, Vec3 frag2Light)
+ANKI_RP Vec3 specularIsotropicLobe(GbufferInfo gbuffer, Vec3 viewDir, Vec3 frag2Light)
 {
-	const Vec3 H = normalize(frag2Light + viewDir);
+	const ANKI_RP Vec3 H = normalize(frag2Light + viewDir);
 
-	const F32 NoL = max(EPSILON, dot(gbuffer.m_normal, frag2Light));
-	const F32 VoH = max(EPSILON, dot(viewDir, H));
-	const F32 NoH = max(EPSILON, dot(gbuffer.m_normal, H));
-	const F32 NoV = max(EPSILON, dot(gbuffer.m_normal, viewDir));
+	const ANKI_RP F32 NoL = max(0.0, dot(gbuffer.m_normal, frag2Light));
+	const ANKI_RP F32 VoH = max(0.0, dot(viewDir, H));
+	const ANKI_RP F32 NoH = max(0.0, dot(gbuffer.m_normal, H));
+	const ANKI_RP F32 NoV = max(0.05, dot(gbuffer.m_normal, viewDir));
 
 	// F
-#if 0
-	const Vec3 F = F_Unreal(gbuffer.m_specular, VoH);
-#else
-	const Vec3 F = F_Schlick(gbuffer.m_specular, VoH);
-#endif
+	const ANKI_RP Vec3 F = F_Schlick(gbuffer.m_specular, VoH);
 
 	// D
-	const F32 D = D_GGX(gbuffer.m_roughness, NoH);
+	const ANKI_RP F32 D = D_GGX(gbuffer.m_roughness, NoH, H, gbuffer.m_normal);
 
 	// Vis
-	const F32 V = V_Schlick(gbuffer.m_roughness, NoV, NoL);
+	const ANKI_RP F32 V = V_SmithGGXCorrelatedFast(gbuffer.m_roughness, NoV, NoL);
 
 	return F * (V * D);
 }
 
+Vec3 envBRDF(Vec3 specular, F32 roughness, texture2D integrationLut, sampler integrationLutSampler, F32 NoV)
+{
+	const Vec2 envBRDF = textureLod(integrationLut, integrationLutSampler, Vec2(roughness, NoV), 0.0).xy;
+	return specular * envBRDF.x + min(1.0, 50.0 * specular.g) * envBRDF.y;
+}
+
 F32 computeSpotFactor(Vec3 l, F32 outerCos, F32 innerCos, Vec3 spotDir)
 {
 	const F32 costheta = -dot(l, spotDir);

+ 4 - 4
AnKi/Shaders/LightShading.ankiprog

@@ -48,8 +48,8 @@ layout(location = 0) out Vec3 out_color;
 #define LIGHTING_COMMON_BRDF() \
 	const Vec3 frag2Light = light.m_position - worldPos; \
 	const Vec3 l = normalize(frag2Light); \
-	const Vec3 specC = computeSpecularColorBrdf(gbuffer, viewDir, l); \
-	const Vec3 diffC = diffuseLambert(gbuffer.m_diffuse); \
+	const Vec3 specC = specularIsotropicLobe(gbuffer, viewDir, l); \
+	const Vec3 diffC = diffuseLobe(gbuffer.m_diffuse); \
 	const F32 att = computeAttenuationFactor(light.m_squareRadiusOverOne, frag2Light); \
 	F32 lambert = max(0.0, dot(gbuffer.m_normal, l));
 
@@ -115,8 +115,8 @@ void main()
 
 		const F32 lambert = max(gbuffer.m_subsurface, dot(l, gbuffer.m_normal));
 
-		const Vec3 diffC = diffuseLambert(gbuffer.m_diffuse);
-		const Vec3 specC = computeSpecularColorBrdf(gbuffer, viewDir, l);
+		const Vec3 diffC = diffuseLobe(gbuffer.m_diffuse);
+		const Vec3 specC = specularIsotropicLobe(gbuffer, viewDir, l);
 
 		out_color += (diffC + specC) * dirLight.m_diffuseColor * (shadowFactor * lambert);
 	}

+ 2 - 2
AnKi/Shaders/TraditionalDeferredShading.ankiprog

@@ -100,7 +100,7 @@ void main()
 	const Vec3 worldPos = worldPos4.xyz / worldPos4.w;
 
 	// Compute diff
-	const Vec3 diffC = diffuseLambert(gbuffer.m_diffuse);
+	const Vec3 diffC = diffuseLobe(gbuffer.m_diffuse);
 
 	// Compute spec
 	const Vec3 viewDir = normalize(u_unis.m_camPos - worldPos);
@@ -113,7 +113,7 @@ void main()
 #endif
 
 #if SPECULAR == 1
-	const Vec3 specC = computeSpecularColorBrdf(gbuffer, viewDir, l);
+	const Vec3 specC = specularIsotropicLobe(gbuffer, viewDir, l);
 #else
 	const Vec3 specC = Vec3(0.0);
 #endif