Browse Source

Improving near filtering

Panagiotis Christopoulos Charitos 10 years ago
parent
commit
a30fb50ed5

+ 7 - 0
include/anki/renderer/Common.h

@@ -30,5 +30,12 @@ class Refl;
 /// GL with a huge job chain
 const U RENDERER_COMMAND_BUFFERS_COUNT = 2;
 
+/// Computes the 'a' and 'b' numbers for linearizeDepthOptimal
+inline void computeLinearizeDepthOptimal(F32 near, F32 far, F32& a, F32& b)
+{
+	a = (far + near) / (2.0 * near);
+	b = (near - far) / (2.0 * near);
+}
+
 } // end namespace anki
 

+ 5 - 5
shaders/LinearDepth.glsl

@@ -3,15 +3,15 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-// convert to linear depth
-
+// Convert to linear depth
 float linearizeDepth(in float depth, in float zNear, in float zFar)
 {
 	return (2.0 * zNear) / (zFar + zNear - depth * (zFar - zNear));
 }
 
-float readFromTextureAndLinearizeDepth(in sampler2D depthMap, in vec2 texCoord, 
-	in float zNear, in float zFar)
+// This is the optimal linearizeDepth where a=(f+n)/2n and b=(n-f)/2n
+float linearizeDepthOptimal(in float depth, in float a, in float b)
 {
-	return linearizeDepth(texture(depthMap, texCoord).r, zNear, zFar);
+	return 1.0 / (a + depth * b);
 }
+

+ 56 - 47
shaders/NearDepthUpscale.frag.glsl

@@ -5,73 +5,82 @@
 
 #pragma anki type frag
 #pragma anki include "shaders/Common.glsl"
+#pragma anki include "shaders/LinearDepth.glsl"
 
-layout(location = 0) in vec2 in_uv;
+layout(location = 0) in vec2 in_uvLow;
+layout(location = 1) in vec2 in_uvHigh;
 
 layout(location = 0) out vec3 out_color;
 
-layout(TEX_BINDING(0, 0)) uniform sampler2D u_depthTexHigh;
-layout(TEX_BINDING(0, 1)) uniform sampler2D u_depthTexLow;
-layout(TEX_BINDING(0, 2)) uniform sampler2D u_colorTexNearest;
-layout(TEX_BINDING(0, 3)) uniform sampler2D u_colorTexLinear;
+layout(TEX_BINDING(0, 0)) uniform sampler2D u_depthTex;
+layout(TEX_BINDING(0, 1)) uniform sampler2D u_colorTexNearest;
+layout(TEX_BINDING(0, 2)) uniform sampler2D u_colorTexLinear;
+
+layout(UBO_BINDING(0, 0)) uniform _u0
+{
+	vec4 u_linearizePad2;
+};
 
 const float DEPTH_THRESHOLD = 1.0 / 1000.0;
 
 const vec2 COLOR_TEX_TEXEL_SIZE = 1.0 / vec2(TEXTURE_WIDTH, TEXTURE_HEIGHT);
 
+const vec2 OFFSETS[8] = vec2[](
+	vec2(-COLOR_TEX_TEXEL_SIZE.x, -COLOR_TEX_TEXEL_SIZE.y),
+	vec2( 0.0,                    -COLOR_TEX_TEXEL_SIZE.y),
+	vec2( COLOR_TEX_TEXEL_SIZE.x, -COLOR_TEX_TEXEL_SIZE.y),
+	vec2( COLOR_TEX_TEXEL_SIZE.x,  0.0),
+	vec2( COLOR_TEX_TEXEL_SIZE.x,  COLOR_TEX_TEXEL_SIZE.y),
+	vec2( 0.0,                     COLOR_TEX_TEXEL_SIZE.y),
+	vec2(-COLOR_TEX_TEXEL_SIZE.x,  COLOR_TEX_TEXEL_SIZE.y),
+	vec2(-COLOR_TEX_TEXEL_SIZE.x,  0.0));
+
 void main()
 {
-	// Gather the depths around the UV
-	vec4 depths = textureGather(u_depthTexLow, in_uv, 0);
-
 	// Get the depth of the current fragment
-	float depth = texture(u_depthTexHigh, in_uv).r;
+	float depth = textureLod(u_depthTex, in_uvHigh, 0.0).r;
+
+	// Gather the depths around the current fragment and:
+	// - Get the min difference compared to crnt depth
+	// - Get the new UV that is closer to the crnt depth
+	float lowDepth = textureLod(u_depthTex, in_uvLow, 1.0).r;
+	float minDiff = abs(depth - lowDepth);
+	float maxDiff = minDiff;
+	vec2 newUv = in_uvLow;
+	for(uint i = 0u; i < 8u; ++i)
+	{
+		// Read the low depth
+		vec2 uv = in_uvLow + OFFSETS[i];
+		float lowDepth = textureLod(u_depthTex, uv, 1.0).r;
+
+		// Update the max difference compared to the current fragment
+		float diff = abs(depth - lowDepth);
+		maxDiff = max(maxDiff, diff);
 
-	// Check for depth discontinuites. Use textureGrad because it's undefined
+		// Update the new UV
+		if(diff < minDiff)
+		{
+			minDiff = diff;
+			newUv = uv;
+		}
+	}
+
+	// Check for depth discontinuites. Use textureLod because it's undefined
 	// if you are sampling mipmaped in a conditional branch. See
 	// http://teknicool.tumblr.com/post/77263472964/glsl-dynamic-branching-and-texture-samplers
-	vec2 texDx = dFdx(in_uv);
-	vec2 texDy = dFdy(in_uv);
-	vec4 diffs = abs(depths - vec4(depth));
-	if(all(lessThan(diffs, vec4(DEPTH_THRESHOLD))))
+	float a = u_linearizePad2.x;
+	float b = u_linearizePad2.y;
+	float maxDiffLinear = abs(linearizeDepthOptimal(depth + maxDiff, a, b)
+		- linearizeDepthOptimal(depth, a, b));
+	if(maxDiffLinear < DEPTH_THRESHOLD)
 	{
 		// No major discontinuites, sample with bilinear
-		out_color = textureGrad(u_colorTexLinear, in_uv, texDx, texDy).rgb;
+		out_color = textureLod(u_colorTexLinear, in_uvLow, 0.0).rgb;
 	}
 	else
 	{
-		// Some discontinuites, need to do some work
-		// Note: Texture gather values are placed like this:
-		// xy
-		// wz
-		// and w is the current texel
-
-		float smallestDiff = diffs.w;
-		vec2 newUv = in_uv;
-
-		if(diffs.z < smallestDiff)
-		{
-			smallestDiff = diffs.z;
-			newUv.x += COLOR_TEX_TEXEL_SIZE.x;
-		}
-
-		if(diffs.y < smallestDiff)
-		{
-			smallestDiff = diffs.y;
-			newUv = in_uv + COLOR_TEX_TEXEL_SIZE;
-		}
-
-		if(diffs.x < smallestDiff)
-		{
-			newUv = in_uv + vec2(0.0, COLOR_TEX_TEXEL_SIZE.y);
-		}
-
-		out_color = textureGrad(u_colorTexNearest, newUv, texDx, texDy).rgb;
+		// Some discontinuites, need to use the newUv
+		out_color = textureLod(u_colorTexNearest, newUv, 0.0).rgb;
 	}
-
-	/*vec2 texDx = dFdx(in_uv);
-	vec2 texDy = dFdy(in_uv);
-	out_color = textureGrad(u_colorTexLinear, in_uv, texDx, texDy).rgb;*/
 }
 
-

+ 13 - 12
shaders/NearDepthUpscale.vert.glsl

@@ -11,7 +11,8 @@ out gl_PerVertex
 	vec4 gl_Position;
 };
 
-layout(location = 0) out vec2 out_uv;
+layout(location = 0) out vec2 out_uvLow;
+layout(location = 1) out vec2 out_uvHigh;
 
 void main()
 {
@@ -23,16 +24,16 @@ void main()
 	vec2 pos = POSITIONS[gl_VertexID];
 	gl_Position = vec4(pos, 0.0, 1.0);
 
-	// Add to the UV and place it at the middle of the texel and slightly
-	// top-right
-	// +----+
-	// |   o|
-	// |    |
-	// |    |
-	// +----+
-	const vec2 TEXEL_SIZE = vec2(1.0 / float(TEXTURE_WIDTH),
-		1.0 / float(TEXTURE_HEIGHT));
-	const vec2 UV_OFFSET = TEXEL_SIZE / 2.0 + EPSILON * 2.0;
-	out_uv = pos * 0.5 + (0.5 + UV_OFFSET);
+	// Compute some offset in order to align the texture coordinates to texel
+	// center
+	const vec2 TEXEL_SIZE_LOW =
+		vec2(1.0 / float(TEXTURE_WIDTH), 1.0 / float(TEXTURE_HEIGHT));
+	const vec2 UV_OFFSET_LOW = TEXEL_SIZE_LOW / 2.0;
+	out_uvLow = pos * 0.5 + (0.5 + UV_OFFSET_LOW);
+
+	const vec2 TEXEL_SIZE_HIGH =
+		vec2(1.0 / float(2 * TEXTURE_WIDTH), 1.0 / float(2 * TEXTURE_HEIGHT));
+	const vec2 UV_OFFSET_HIGH = TEXEL_SIZE_HIGH / 2.0;
+	out_uvHigh = pos * 0.5 + (0.5 + UV_OFFSET_HIGH);
 }
 

+ 18 - 10
src/renderer/Refl.cpp

@@ -180,24 +180,21 @@ Error Refl::init2ndPass()
 	GrManager& gr = getGrManager();
 
 	// Create RC group
-	SamplerInitializer sinit;
 	ResourceGroupInitializer rcInit;
 
-	sinit.m_mipmapFilter = SamplingFilter::NEAREST;
 	rcInit.m_textures[0].m_texture = m_r->getMs().getDepthRt();
-	rcInit.m_textures[0].m_sampler = gr.newInstance<Sampler>(sinit);
 
-	sinit.m_minLod = 1.0;
-	rcInit.m_textures[1].m_texture = m_r->getMs().getDepthRt();
+	SamplerInitializer sinit;
+	sinit.m_repeat = false;
+	sinit.m_mipmapFilter = SamplingFilter::NEAREST;
+	rcInit.m_textures[1].m_texture = m_rt;
 	rcInit.m_textures[1].m_sampler = gr.newInstance<Sampler>(sinit);
 
-	sinit.m_minLod = 0.0;
+	sinit.m_minMagFilter = SamplingFilter::LINEAR;
 	rcInit.m_textures[2].m_texture = m_rt;
 	rcInit.m_textures[2].m_sampler = gr.newInstance<Sampler>(sinit);
 
-	sinit.m_minMagFilter = SamplingFilter::LINEAR;
-	rcInit.m_textures[3].m_texture = m_rt;
-	rcInit.m_textures[3].m_sampler = gr.newInstance<Sampler>(sinit);
+	rcInit.m_uniformBuffers[0].m_dynamic = true;
 
 	m_blitRcGroup = getGrManager().newInstance<ResourceGroup>(rcInit);
 
@@ -277,10 +274,21 @@ void Refl::run2(CommandBufferPtr cmdb)
 
 	// Write the reflection back to IS RT
 	//
+	DynamicBufferToken token;
+	Vec4* linearDepth = static_cast<Vec4*>(
+		getGrManager().allocateFrameHostVisibleMemory(
+		sizeof(Vec4), BufferUsage::UNIFORM, token));
+	const Frustum& fr = m_r->getActiveFrustumComponent().getFrustum();
+	computeLinearizeDepthOptimal(
+		fr.getNear(), fr.getFar(), linearDepth->x(), linearDepth->y());
+
+	DynamicBufferInfo dyn1;
+	dyn1.m_uniformBuffers[0] = token;
+
 	cmdb->bindFramebuffer(m_isFb);
 	cmdb->bindPipeline(m_blitPpline);
 	cmdb->setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
-	cmdb->bindResourceGroup(m_blitRcGroup, 0, nullptr);
+	cmdb->bindResourceGroup(m_blitRcGroup, 0, &dyn1);
 
 	m_r->drawQuad(cmdb);
 }

+ 5 - 5
testapp/Main.cpp

@@ -43,7 +43,7 @@ ModelNode* horse;
 PerspectiveCamera* cam;
 
 #define PLAYER 0
-#define MOUSE 0
+#define MOUSE 1
 
 Bool profile = false;
 
@@ -89,8 +89,8 @@ Error init()
 	cam->getComponent<MoveComponent>().
 		setLocalTransform(Transform(
 		//Vec4(147.392776, -10.132728, 16.607138, 0.0),
-		Vec4(120.124107, -12.032735, 12.564746, 0),
-		Mat3x4(Euler(toRad(0.0), toRad(0.0), toRad(0.0))),
+		Vec4(102.984535, -11.532733, 16.394911, 0),
+		Mat3x4(Euler(toRad(0.0), toRad(-10.0), toRad(0.0))),
 		//Mat3x4::getIdentity(),
 		1.0));
 #endif
@@ -506,7 +506,7 @@ Error initSubsystems(int argc, char* argv[])
 	config.set("pps.sharpen", true);
 	config.set("renderingQuality", 1.0);
 	config.set("width", 1920);
-	config.set("height", 1080);
+	config.set("height", 1088);
 	config.set("lodDistance", 20.0);
 	config.set("samples", 1);
 	config.set("tessellation", true);
@@ -517,7 +517,7 @@ Error initSubsystems(int argc, char* argv[])
 	config.set("sslr.enabled", false);
 	config.set("ir.rendererSize", 64);
 	config.set("ir.clusterSizeZ", 16);
-	config.set("fullscreenDesktopResolution", true);
+	config.set("fullscreenDesktopResolution", false);
 	//config.set("clusterSizeZ", 16);
 	config.set("debugContext", false);
 	if(getenv("ANKI_DATA_PATH"))