Index: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/combineSsao.cg
===================================================================
--- GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/combineSsao.cg	(revision 3197)
+++ GTP/trunk/App/Demos/Vis/FriendlyCulling/src/shaders/combineSsao.cg	(revision 3198)
@@ -122,5 +122,5 @@
 	for (int i = 0; i < NUM_SSAO_FILTER_SAMPLES; ++ i)
 	{
-		sampleTexCoord = float4(texCoord + filterOffs[i] * scale, 0, 0);
+		sampleTexCoord = float4(texCoord + filterOffs[i] * scale, .0f, .0f);
 
 		aoSample = tex2Dlod(ssaoTex, sampleTexCoord);
@@ -128,5 +128,6 @@
 
 		// check spatial discontinuity
-		// using the depth from the color texture is not 100% correct as depth was
+
+		// note: using the depth from the color texture is not 100% correct as depth was
 		// not scaled with the interpolated view vector depth yet ...
 		samplePos = ReconstructSamplePos(colorsTex, sampleTexCoord.xy, bl, br, tl, tr);
@@ -134,17 +135,12 @@
 
 		len = min(SqrLen(centerPos - samplePos), 1e2f);
-
 		spatialFactor = 1.0f / max(len, 1e-3f);
 
 		//normalFactor = max(step(.0f, dot(sampleNorm, centerNormal)), 1e-2f);
-		//normalFactor = max(dot(sampleNorm, samplePos), 1e-3f);
 		convergenceFactor = aoSample.y + 1.0f;
-		//convergenceFactor = max(step(0.5f + NUM_SAMPLES, aoSample.y), 1e-2f);
-		//convergenceFactor = aoSample.y;
-
+		
 		// combine the weights
 		w = convergenceFactor * convergenceFactor * spatialFactor;// * normalFactor;
-		//w = spatialFactor * normalFactor;
-
+		
 		average += aoSample.x * w;
 		total_w += w;
@@ -178,20 +174,25 @@
 	float4 ao = tex2Dlod(ssaoTex, float4(IN.texCoord, 0, 0));
 
-	float4 dummy;
-	//const float xoffs = .5f / 1024.0f;	const float yoffs = .5f / 768.0f;
-	const float xoffs = 1.0f / 1024.0f;	const float yoffs = 1.0f / 768.0f;
-
-	dummy.x = tex2Dlod(ssaoTex, float4(IN.texCoord + float2(xoffs, yoffs), 0, 0)).w;
-	dummy.y = tex2Dlod(ssaoTex, float4(IN.texCoord + float2(xoffs, -yoffs), 0, 0)).w;
-	dummy.z = tex2Dlod(ssaoTex, float4(IN.texCoord + float2(-xoffs, yoffs), 0, 0)).w;
-	dummy.w = tex2Dlod(ssaoTex, float4(IN.texCoord + float2(-yoffs, -yoffs), 0, 0)).w;
-
-	/*dummy.x = tex2Dlod(ssaoTex, float4(IN.texCoord + float2(xoffs, 0), 0, 0)).y;
-	dummy.y = tex2Dlod(ssaoTex, float4(IN.texCoord + float2(0, yoffs), 0, 0)).y;
-	dummy.z = tex2Dlod(ssaoTex, float4(IN.texCoord + float2(-xoffs, 0), 0, 0)).y;
-	dummy.w = tex2Dlod(ssaoTex, float4(IN.texCoord + float2(0, -yoffs), 0, 0)).y;
-*/
-	const float convergence = min(min(dummy.x, dummy.y), min(dummy.z, dummy.w));
-	//const float convergence = max(max(dummy.x, dummy.y), max(dummy.z, dummy.w));
+	// get the minimum convergence by exactly sampling the 4 surrounding
+	// texels in the old texture, otherwise flickering because convergence
+	// will be interpolated when upsampling and filter size does not match!
+	float4 texelCenterConv;
+	const float w = 512.0f; const float h = 384.0f;
+	const float xoffs = .5f / w; const float yoffs = .5f / h;
+
+	// get position exactly between old texel centers
+	float2 center;
+	center.x = float(floor(IN.texCoord.x * w - .5f) + 1.0f) / w;
+	center.y = float(floor(IN.texCoord.y * h - .5f) + 1.0f) / h;
+
+	texelCenterConv.x = tex2Dlod(ssaoTex, float4(center + float2(xoffs, yoffs), 0, 0)).y;
+	texelCenterConv.y = tex2Dlod(ssaoTex, float4(center + float2(xoffs, -yoffs), 0, 0)).y;
+	texelCenterConv.z = tex2Dlod(ssaoTex, float4(center + float2(-xoffs, yoffs), 0, 0)).y;
+	texelCenterConv.w = tex2Dlod(ssaoTex, float4(center + float2(-xoffs, -yoffs), 0, 0)).y;
+
+	const float m1 = min(texelCenterConv.x, texelCenterConv.y);
+	const float m2 = min(texelCenterConv.z, texelCenterConv.w);
+
+	const float convergence = min(m1, m2);
 	//const float convergence = ao.y;
 
@@ -201,17 +202,13 @@
 	// filter up to a certain convergance value and leave out background (sky) by checking depth
 	if ((convergence < thres) && (col.w < 1e10f))
-	//if (col.w < 1e10f)
 	{
-		//const float eyeSpaceDepth = col.w; const float distanceScaleWeight = 2.0f;
-		//const float distanceScale = distanceScaleWeight / (eyeSpaceDepth + distanceScaleWeight);
 		const float distanceScale = 1.0f;
 
 		const float convergenceWeight = thres / (SSAO_FILTER_WIDTH - 1.0f);
 		const float convergenceScale = convergenceWeight / (convergence + convergenceWeight);
-
 		const float scale = SSAO_FILTER_WIDTH * convergenceScale * distanceScale;
 
 		// the filtered ssao value
-		//ao.x = DiscontinuityFilter2(IN.texCoord, ao, col, ssaoTex, normalsTex, colorsTex, filterOffs, scale, bl, br, tl, tr);
+		ao.x = DiscontinuityFilter2(IN.texCoord, ao, col, ssaoTex, normalsTex, colorsTex, filterOffs, scale, bl, br, tl, tr);
 	}
 
@@ -221,7 +218,6 @@
 		OUT.illum_col.xyz = col.xyz;
 
-	//OUT.illum_col.xyz = float3(0, clamp(1.0f - ao.y * 1e-3f, 0, 1), 1);
-	//const float mydummy = ao.w * 1e-3f;
-	OUT.illum_col.xyz = float3(ao.x, ao.x, ao.x);
+	//OUT.illum_col.xyz = float3(ao.x, ao.x, step(thres, convergence));
+	//OUT.illum_col.xyz = float3(ao.x, ao.x, ao.x);
 	//OUT.illum_col.xyz = float3(0, clamp(1.0f - ao.y * 1e-3f, 0, 1), 1);
 	//OUT.illum_col.xyz = float3(0, 1.0f - step(0.5f + NUM_SAMPLES, convergence), 1);
@@ -230,2 +226,31 @@
 	return OUT;
 }
+
+
+
+/** Function combining image and indirect illumination buffer using a 
+	depth and normal aware discontinuity filter.
+*/
+pixel SmoothSsao(fragment IN, 
+				 uniform sampler2D ssaoTex)
+{
+	pixel OUT;
+
+	float4 ao = tex2Dlod(ssaoTex, float4(IN.texCoord, 0, 0));
+
+	float4 dummy;
+	const float xoffs = .5f / 1024.0f; const float yoffs = .5f / 768.0f;
+
+	// get positions exactly between old texel centers
+	dummy.x = tex2Dlod(ssaoTex, float4(IN.texCoord + float2(xoffs, 0), 0, 0)).y;
+	dummy.y = tex2Dlod(ssaoTex, float4(IN.texCoord + float2(0, -yoffs), 0, 0)).y;
+	dummy.z = tex2Dlod(ssaoTex, float4(IN.texCoord + float2(-xoffs, 0), 0, 0)).y;
+	dummy.w = tex2Dlod(ssaoTex, float4(IN.texCoord + float2(0, yoffs), 0, 0)).y;
+
+	const float m1 = min(dummy.x, dummy.y);
+	const float m2 = min(dummy.z, dummy.w);
+
+	ao.y = min(ao.y, min(m1, m2));
+
+	return OUT;
+}
