Przeglądaj źródła

Add blurring inside the SSAO shader

Panagiotis Christopoulos Charitos 7 lat temu
rodzic
commit
54ef8a0efe

+ 1 - 0
programs/Ssao.ankiprog

@@ -7,6 +7,7 @@ http://www.anki3d.org/LICENSE
 <shaderProgram>
 	<mutators>
 		<mutator name="USE_NORMAL" values="0 1"/>
+		<mutator name="SOFT_BLUR" values="0 1"/>
 	</mutators>
 
 	<shaders>

+ 1 - 0
programs/SsaoCompute.ankiprog

@@ -7,6 +7,7 @@ http://www.anki3d.org/LICENSE
 <shaderProgram>
 	<mutators>
 		<mutator name="USE_NORMAL" values="0 1"/>
+		<mutator name="SOFT_BLUR" values="0 1"/>
 	</mutators>
 
 	<shaders>

+ 84 - 30
shaders/Ssao.glsl

@@ -11,6 +11,8 @@
 #include "shaders/Common.glsl"
 #include "shaders/Pack.glsl"
 #include "shaders/Functions.glsl"
+#define KERNEL_SIZE 3
+#include "shaders/GaussianBlurCommon.glsl"
 
 #if defined(ANKI_FRAGMENT_SHADER)
 #	define USE_COMPUTE 0
@@ -18,6 +20,9 @@
 #	define USE_COMPUTE 1
 #endif
 
+// Do a compute soft blur
+#define DO_SOFT_BLUR (USE_COMPUTE && SOFT_BLUR)
+
 #if !USE_COMPUTE
 layout(location = 0) in vec2 in_uv;
 layout(location = 0) out float out_color;
@@ -42,8 +47,8 @@ layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2D u_msRt;
 
 // To compute the normals we need some extra work on compute
 #define COMPLEX_NORMALS (!USE_NORMAL && USE_COMPUTE)
-#if COMPLEX_NORMALS
-shared vec3 s_positions[WORKGROUP_SIZE.y][WORKGROUP_SIZE.x];
+#if COMPLEX_NORMALS || DO_SOFT_BLUR
+shared vec3 s_scratch[WORKGROUP_SIZE.y][WORKGROUP_SIZE.x];
 #endif
 
 #if USE_NORMAL
@@ -88,33 +93,16 @@ vec4 project(vec4 point)
 	return projectPerspective(point, u_projectionMat.x, u_projectionMat.y, u_projectionMat.z, u_projectionMat.w);
 }
 
-void main(void)
+// Compute the normal depending on some defines
+vec3 computeNormal(vec2 uv, vec3 origin)
 {
-#if USE_COMPUTE
-	if(gl_GlobalInvocationID.x >= FB_SIZE.x || gl_GlobalInvocationID.y >= FB_SIZE.y)
-	{
-		// Skip if it's out of bounds
-		return;
-	}
-
-	vec2 uv = vec2(gl_GlobalInvocationID.xy) / vec2(FB_SIZE);
-#else
-	vec2 uv = in_uv;
-#endif
-
-	vec2 ndc = UV_TO_NDC(uv);
-
-	// Compute origin
-	vec3 origin = readPosition(uv);
-
-	// Get normal
 #if USE_NORMAL
 	vec3 normal = readNormal(uv);
 #elif !COMPLEX_NORMALS
 	vec3 normal = normalize(cross(dFdx(origin), dFdy(origin)));
 #else
 	// Every thread stores its position
-	s_positions[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = origin;
+	s_scratch[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = origin;
 
 	memoryBarrierShared();
 	barrier();
@@ -126,24 +114,54 @@ void main(void)
 
 		vec3 center, right, top;
 		center = origin;
-		right = s_positions[gl_LocalInvocationID.y][gl_LocalInvocationID.x + 1u];
-		top = s_positions[gl_LocalInvocationID.y + 1u][gl_LocalInvocationID.x + 1u];
+		right = s_scratch[gl_LocalInvocationID.y][gl_LocalInvocationID.x + 1u];
+		top = s_scratch[gl_LocalInvocationID.y + 1u][gl_LocalInvocationID.x + 1u];
 
 		vec3 normal = normalize(cross(right - center, top - center));
 
 		// Broadcast the normal
-		s_positions[gl_LocalInvocationID.y + 0u][gl_LocalInvocationID.x + 0u] = normal;
-		s_positions[gl_LocalInvocationID.y + 0u][gl_LocalInvocationID.x + 1u] = normal;
-		s_positions[gl_LocalInvocationID.y + 1u][gl_LocalInvocationID.x + 0u] = normal;
-		s_positions[gl_LocalInvocationID.y + 1u][gl_LocalInvocationID.x + 1u] = normal;
+		s_scratch[gl_LocalInvocationID.y + 0u][gl_LocalInvocationID.x + 0u] = normal;
+		s_scratch[gl_LocalInvocationID.y + 0u][gl_LocalInvocationID.x + 1u] = normal;
+		s_scratch[gl_LocalInvocationID.y + 1u][gl_LocalInvocationID.x + 0u] = normal;
+		s_scratch[gl_LocalInvocationID.y + 1u][gl_LocalInvocationID.x + 1u] = normal;
 	}
 
 	memoryBarrierShared();
 	barrier();
 
-	vec3 normal = s_positions[gl_LocalInvocationID.y][gl_LocalInvocationID.x];
+	vec3 normal = s_scratch[gl_LocalInvocationID.y][gl_LocalInvocationID.x];
+#endif
+
+	return normal;
+}
+
+void main(void)
+{
+#if USE_COMPUTE
+	if(gl_GlobalInvocationID.x >= FB_SIZE.x || gl_GlobalInvocationID.y >= FB_SIZE.y)
+	{
+#	if DO_SOFT_BLUR
+		// Store something anyway because alive threads might read it when SOFT_BLUR is enabled
+		s_scratch[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = vec3(1.0);
+#	endif
+
+		// Skip if it's out of bounds
+		return;
+	}
+
+	vec2 uv = vec2(gl_GlobalInvocationID.xy) / vec2(FB_SIZE);
+#else
+	vec2 uv = in_uv;
 #endif
 
+	vec2 ndc = UV_TO_NDC(uv);
+
+	// Compute origin
+	vec3 origin = readPosition(uv);
+
+	// Get normal
+	vec3 normal = computeNormal(uv, origin);
+
 	// Find the projected radius
 	vec3 sphereLimit = origin + vec3(RADIUS, 0.0, 0.0);
 	vec4 projSphereLimit = project(vec4(sphereLimit, 1.0));
@@ -156,7 +174,7 @@ void main(void)
 	{
 		// Compute disk
 		vec3 randFactors = readRandom(uv, float(i));
-		vec2 dir = normalize(randFactors.xy * 2.0 - 1.0);
+		vec2 dir = normalize(UV_TO_NDC(randFactors.xy));
 		float radius = projRadius * (randFactors.z * 0.85 + 0.15);
 		vec2 finalDiskPoint = ndc + dir * radius;
 
@@ -169,6 +187,42 @@ void main(void)
 	ssao *= (1.0 / float(SAMPLE_COUNT));
 	ssao = 1.0 - ssao * STRENGTH;
 
+	// Maybe do soft blur
+#if DO_SOFT_BLUR
+	// Everyone stores its result
+	s_scratch[gl_LocalInvocationID.y][gl_LocalInvocationID.x].x = ssao;
+
+	// Do some pre-work to find out the neighbours
+	uint left = (gl_LocalInvocationID.x != 0u) ? (gl_LocalInvocationID.x - 1u) : 0u;
+	uint right =
+		(gl_LocalInvocationID.x != WORKGROUP_SIZE.x - 1u) ? (gl_LocalInvocationID.x + 1u) : (WORKGROUP_SIZE.x - 1u);
+	uint bottom = (gl_LocalInvocationID.y != 0u) ? (gl_LocalInvocationID.y - 1u) : 0u;
+	uint top =
+		(gl_LocalInvocationID.y != WORKGROUP_SIZE.y - 1u) ? (gl_LocalInvocationID.y + 1u) : (WORKGROUP_SIZE.y - 1u);
+
+	// Wait for all threads
+	memoryBarrierShared();
+	barrier();
+
+	// Sample neighbours
+	ssao *= BOX_WEIGHTS[0];
+
+	float cross;
+	cross = s_scratch[gl_LocalInvocationID.y][left].x;
+	cross += s_scratch[gl_LocalInvocationID.y][right].x;
+	cross += s_scratch[bottom][gl_LocalInvocationID.x].x;
+	cross += s_scratch[top][gl_LocalInvocationID.x].x;
+
+	ssao += cross * BOX_WEIGHTS[1];
+
+	cross = s_scratch[bottom][left].x;
+	cross += s_scratch[bottom][right].x;
+	cross += s_scratch[top][left].x;
+	cross += s_scratch[top][right].x;
+
+	ssao += cross * BOX_WEIGHTS[2];
+#endif
+
 	// Store the result
 #if USE_COMPUTE
 	imageStore(out_img, ivec2(gl_GlobalInvocationID.xy), vec4(ssao));

+ 3 - 3
src/anki/renderer/Ssao.cpp

@@ -33,8 +33,8 @@ Error Ssao::initMain(const ConfigSet& config)
 		ANKI_CHECK(getResourceManager().loadResource("programs/Ssao.ankiprog", m_main.m_prog));
 	}
 
-	ShaderProgramResourceMutationInitList<1> mutators(m_main.m_prog);
-	mutators.add("USE_NORMAL", (m_useNormal) ? 1u : 0u);
+	ShaderProgramResourceMutationInitList<2> mutators(m_main.m_prog);
+	mutators.add("USE_NORMAL", (m_useNormal) ? 1u : 0u).add("SOFT_BLUR", (m_useSoftBlur) ? 1u : 0u);
 
 	ShaderProgramResourceConstantValueInitList<7> consts(m_main.m_prog);
 	consts.add("NOISE_MAP_SIZE", U32(m_main.m_noiseTex->getWidth()))
@@ -42,7 +42,7 @@ Error Ssao::initMain(const ConfigSet& config)
 		.add("RADIUS", 2.5f)
 		.add("BIAS", 0.0f)
 		.add("STRENGTH", 2.5f)
-		.add("SAMPLE_COUNT", 4u)
+		.add("SAMPLE_COUNT", 8u)
 		.add("WORKGROUP_SIZE", UVec2(m_workgroupSize[0], m_workgroupSize[1]));
 	const ShaderProgramResourceVariant* variant;
 	m_main.m_prog->getOrCreateVariant(mutators.get(), consts.get(), variant);

+ 1 - 0
src/anki/renderer/Ssao.h

@@ -41,6 +41,7 @@ anki_internal:
 private:
 	static const Bool m_useNormal = false;
 	static const Bool m_useCompute = true;
+	static const Bool m_useSoftBlur = true;
 	U32 m_width, m_height;
 	Array<U32, 2> m_workgroupSize = {{16, 16}};