Browse Source

Align PBR to unreal's

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
5cc99f10fc

+ 4 - 5
programs/DeferredShading.ankiprog

@@ -122,20 +122,19 @@ void main()
 	vec3 l = normalize(frag2Light);
 	vec3 l = normalize(frag2Light);
 	float nol = max(0.0, dot(gbuffer.normal, l));
 	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 att = computeAttenuationFactor(u_light.posRadius.w, frag2Light);
 	float lambert = nol;
 	float lambert = nol;
 
 
 #if LIGHT_TYPE == POINT_LIGHT_TYPE
 #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
 #else
 	float spot =
 	float spot =
 		computeSpotFactor(l, u_light.diffuseColorOuterCos.w, u_light.specularColorInnerCos.w, u_light.lightDirPad1.xyz);
 		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
 #endif
 }
 }
 			]]></source>
 			]]></source>

+ 4 - 4
programs/LightShading.ankiprog

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

+ 10 - 12
programs/Reflections.ankiprog

@@ -239,19 +239,9 @@ void main()
 	vec4 worldPos4 = u_invViewProjMat * vec4(ndc, depth, 1.0);
 	vec4 worldPos4 = u_invViewProjMat * vec4(ndc, depth, 1.0);
 	vec3 worldPos = worldPos4.xyz / worldPos4.w;
 	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
 	// Try SSR
 	float sslrFactor = 0.0;
 	float sslrFactor = 0.0;
 	vec3 sslrCol = vec3(0.0);
 	vec3 sslrCol = vec3(0.0);
-	if(runSslr)
 	{
 	{
 		// Get view pos
 		// Get view pos
 		vec4 viewPos4 = u_invProjMat * vec4(UV_TO_NDC(uv), depth, 1.0);
 		vec4 viewPos4 = u_invProjMat * vec4(UV_TO_NDC(uv), depth, 1.0);
@@ -297,8 +287,16 @@ void main()
 	vec3 finalRefl = mix(probeCol, sslrCol, sslrFactor);
 	vec3 finalRefl = mix(probeCol, sslrCol, sslrFactor);
 
 
 	// Compute the final color
 	// 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
 	// Store the color for the resolve
 	s_pixels[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = outColor;
 	s_pixels[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = outColor;

+ 1 - 1
programs/VolumetricFog.ankiprog

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

+ 2 - 2
shaders/ForwardShadingCommonFrag.glsl

@@ -58,7 +58,7 @@ vec3 computeLightColor(vec3 diffCol, vec3 worldPos)
 	{
 	{
 		PointLight light = u_pointLights[u_lightIndices[idxOffset++]];
 		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;
 		vec3 frag2Light = light.posRadius.xyz - worldPos;
 		float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
 		float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
@@ -86,7 +86,7 @@ vec3 computeLightColor(vec3 diffCol, vec3 worldPos)
 	{
 	{
 		SpotLight light = u_spotLights[u_lightIndices[idxOffset++]];
 		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;
 		vec3 frag2Light = light.posRadius.xyz - worldPos;
 		float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
 		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 uint SHADOW_SAMPLE_COUNT = 16;
 const float ESM_CONSTANT = 40.0;
 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
 // 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)
 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;
 	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
 #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
 // 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)
 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;
 	g.diffuse = comp.xyz;
 	vec2 comp2 = unpackUnorm1ToUnorm2(comp.w);
 	vec2 comp2 = unpackUnorm1ToUnorm2(comp.w);
 	g.subsurface = comp2.x;
 	g.subsurface = comp2.x;
 	g.metallic = comp2.y;
 	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.normal = signedOctDecode(comp.xyw);
 	g.emission = comp.z * MAX_EMISSION;
 	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
 #endif