Parcourir la source

Align PBR to unreal's

Panagiotis Christopoulos Charitos il y a 7 ans
Parent
commit
5cc99f10fc

+ 4 - 5
programs/DeferredShading.ankiprog

@@ -122,20 +122,19 @@ void main()
 	vec3 l = normalize(frag2Light);
 	float nol = max(0.0, dot(gbuffer.normal, l));
 
-	vec3 specC = computeSpecularColorBrdf(gbuffer, viewDir, l, u_lspec);
-
-	vec3 diffC = computeDiffuseColor(gbuffer.diffuse, u_ldiff);
+	vec3 specC = computeSpecularColorBrdf(gbuffer, viewDir, l);
+	vec3 diffC = diffuseLambert(gbuffer.diffuse);
 
 	float att = computeAttenuationFactor(u_light.posRadius.w, frag2Light);
 	float lambert = nol;
 
 #if LIGHT_TYPE == POINT_LIGHT_TYPE
-	out_color = (specC + diffC) * (att * max(lambert, gbuffer.subsurface));
+	out_color = (specC + diffC) * u_ldiff * (att * max(lambert, gbuffer.subsurface));
 #else
 	float spot =
 		computeSpotFactor(l, u_light.diffuseColorOuterCos.w, u_light.specularColorInnerCos.w, u_light.lightDirPad1.xyz);
 
-	out_color = (diffC + specC) * (att * spot * max(lambert, gbuffer.subsurface));
+	out_color = (diffC + specC) * u_ldiff * (att * spot * max(lambert, gbuffer.subsurface));
 #endif
 }
 			]]></source>

+ 4 - 4
programs/LightShading.ankiprog

@@ -68,8 +68,8 @@ const float SUBSURFACE_MIN = 0.05;
 #define LIGHTING_COMMON_BRDF() \
 	vec3 frag2Light = light.posRadius.xyz - worldPos; \
 	vec3 l = normalize(frag2Light); \
-	vec3 specC = computeSpecularColorBrdf(gbuffer, viewDir, l, light.specularColorRadius.rgb); \
-	vec3 diffC = computeDiffuseColor(gbuffer.diffuse, light.diffuseColorShadowmapId.rgb); \
+	vec3 specC = computeSpecularColorBrdf(gbuffer, viewDir, l); \
+	vec3 diffC = diffuseLambert(gbuffer.diffuse); \
 	float att = computeAttenuationFactor(light.posRadius.w, frag2Light); \
 	float lambert = max(0.0, dot(gbuffer.normal, l));
 
@@ -123,7 +123,7 @@ void main()
 			lambert *= shadow;
 		}
 
-		outC += (diffC + specC) * (att * max(gbuffer.subsurface, lambert));
+		outC += (diffC + specC) * light.diffuseColorShadowmapId.rgb * (att * max(gbuffer.subsurface, lambert));
 	}
 
 	// Spot lights
@@ -145,7 +145,7 @@ void main()
 			lambert *= shadow;
 		}
 
-		outC += (diffC + specC) * (att * spot * max(gbuffer.subsurface, lambert));
+		outC += (diffC + specC) * light.diffuseColorShadowmapId.rgb * (att * spot * max(gbuffer.subsurface, lambert));
 	}
 
 	// Indirect

+ 10 - 12
programs/Reflections.ankiprog

@@ -239,19 +239,9 @@ void main()
 	vec4 worldPos4 = u_invViewProjMat * vec4(ndc, depth, 1.0);
 	vec3 worldPos = worldPos4.xyz / worldPos4.w;
 
-	// Compute how much reflections we need
-	vec3 specIndirectTerm;
-	vec3 diffIndirectTerm;
-	vec3 viewDir = normalize(u_cameraPos - worldPos);
-	computeSpecAndDiffuseIndirectFactors(viewDir, gbuffer, u_integrationLut, specIndirectTerm, diffIndirectTerm);
-	
-	bool runSslr = 
-		max(max(specIndirectTerm.x, specIndirectTerm.y), specIndirectTerm.z) > 0.05;
-
 	// Try SSR
 	float sslrFactor = 0.0;
 	vec3 sslrCol = vec3(0.0);
-	if(runSslr)
 	{
 		// Get view pos
 		vec4 viewPos4 = u_invProjMat * vec4(UV_TO_NDC(uv), depth, 1.0);
@@ -297,8 +287,16 @@ void main()
 	vec3 finalRefl = mix(probeCol, sslrCol, sslrFactor);
 
 	// Compute the final color
-	float ssao = textureLod(u_ssaoTex, uv, 0.0).r;
-	vec3 outColor = (indirectCol * diffIndirectTerm + finalRefl * specIndirectTerm) * ssao;
+	vec3 outColor;
+	{
+		vec3 viewDir = normalize(u_cameraPos - worldPos);
+		float NoV = max(EPSILON, dot(gbuffer.normal, viewDir));
+		vec3 env = envBRDF(gbuffer.specular, gbuffer.roughness, u_integrationLut, NoV);
+
+		float ssao = textureLod(u_ssaoTex, uv, 0.0).r;
+
+		outColor = (indirectCol * gbuffer.diffuse + finalRefl * env) * ssao;
+	}
 
 	// Store the color for the resolve
 	s_pixels[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = outColor;

+ 1 - 1
programs/VolumetricFog.ankiprog

@@ -200,7 +200,7 @@ void main()
 		kNear = kFar;
 	}
 
-	newCol *= u_fogParticleColor;
+	newCol *= diffuseLambert(u_fogParticleColor);
 
 	// Read history
 	float historyFeedback;

+ 2 - 2
shaders/ForwardShadingCommonFrag.glsl

@@ -58,7 +58,7 @@ vec3 computeLightColor(vec3 diffCol, vec3 worldPos)
 	{
 		PointLight light = u_pointLights[u_lightIndices[idxOffset++]];
 
-		vec3 diffC = computeDiffuseColor(diffCol, light.diffuseColorShadowmapId.rgb);
+		vec3 diffC = diffuseLambert(diffCol) * light.diffuseColorShadowmapId.rgb;
 
 		vec3 frag2Light = light.posRadius.xyz - worldPos;
 		float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
@@ -86,7 +86,7 @@ vec3 computeLightColor(vec3 diffCol, vec3 worldPos)
 	{
 		SpotLight light = u_spotLights[u_lightIndices[idxOffset++]];
 
-		vec3 diffC = computeDiffuseColor(diffCol, light.diffuseColorShadowmapId.rgb);
+		vec3 diffC = diffuseLambert(diffCol) * light.diffuseColorShadowmapId.rgb;
 
 		vec3 frag2Light = light.posRadius.xyz - worldPos;
 		float att = computeAttenuationFactor(light.posRadius.w, frag2Light);

+ 43 - 63
shaders/LightFunctions.glsl

@@ -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

+ 16 - 3
shaders/Pack.glsl

@@ -174,17 +174,30 @@ void readRoughnessSpecularFromGBuffer(in sampler2D rt1, in vec2 uv, out float ro
 // Read from the G buffer
 void readGBuffer(in sampler2D rt0, in sampler2D rt1, in sampler2D rt2, in vec2 uv, in float lod, out GbufferInfo g)
 {
-	vec4 comp = textureLod(rt0, uv, lod);
+	vec4 comp = textureLod(rt0, uv, 0.0);
 	g.diffuse = comp.xyz;
 	vec2 comp2 = unpackUnorm1ToUnorm2(comp.w);
 	g.subsurface = comp2.x;
 	g.metallic = comp2.y;
 
-	readRoughnessSpecularFromGBuffer(rt1, uv, g.roughness, g.specular);
+	comp = textureLod(rt1, uv, 0.0);
+	g.specular = comp.xyz;
+	g.roughness = comp.w;
 
-	comp = textureLod(rt2, uv, lod);
+	comp = textureLod(rt2, uv, 0.0);
 	g.normal = signedOctDecode(comp.xyw);
 	g.emission = comp.z * MAX_EMISSION;
+
+	// Fix roughness
+	const float MIN_ROUGHNESS = 0.5;
+	g.roughness = g.roughness * (1.0 - MIN_ROUGHNESS) + MIN_ROUGHNESS;
+
+	// Compute reflectance
+	vec3 F0 = mix(g.specular, g.diffuse, g.metallic);
+	g.specular = F0;
+
+	// Compute diffuse
+	g.diffuse = g.diffuse - g.diffuse * g.metallic;
 }
 
 #endif