Browse Source

Renderer: Improve quality on volumetrics

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
32c5a62e11

+ 8 - 0
shaders/Clusterer.glsl

@@ -50,4 +50,12 @@ float computeClusterFar(uint k, float near, float clustererMagic)
 	return 1.0 / clustererMagic * pow(float(k + 1u), 2.0) - near;
 }
 
+uint computeClusterKFromZViewSpace(float zViewSpace, float near, float far, float clustererMagic)
+{
+	float z = clamp(zViewSpace, -far, -near);
+	z = -z;
+	float kf = sqrt((z - near) * -clustererMagic);
+	return uint(kf);
+}
+
 #endif

+ 1 - 2
shaders/Pps.frag.glsl

@@ -148,8 +148,7 @@ void main()
 
 #if 0
 	{
-		out_color = textureCatmullRom4Samples(u_isRt, 
-				uv, vec2(2560. / 2., 1400. / 2.)).rgb;
+		out_color = textureLod(u_isRt, uv, 0.0).rgb;
 	}
 #endif
 

+ 61 - 47
shaders/Volumetric.frag.glsl

@@ -7,7 +7,7 @@
 #include "shaders/Functions.glsl"
 #include "shaders/Clusterer.glsl"
 
-#define LIGHT_TEX_BINDING 2
+#define LIGHT_TEX_BINDING 1
 #define LIGHT_UBO_BINDING 0
 #define LIGHT_SS_BINDING 0
 #define LIGHT_SET 0
@@ -16,7 +16,6 @@
 layout(location = 0) in vec2 in_uv;
 
 layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_msDepthRt;
-layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_prevResultTex;
 
 layout(std140, ANKI_UBO_BINDING(0, 3)) uniform ubo0_
 {
@@ -24,11 +23,13 @@ layout(std140, ANKI_UBO_BINDING(0, 3)) uniform ubo0_
 	vec4 u_fogColorFogFactor;
 };
 
-layout(location = 0) out vec3 out_color;
+layout(location = 0) out vec4 out_color;
 
 #define ENABLE_SHADOWS 0
+const uint MAX_SAMPLES_PER_CLUSTER = 4u;
 
-vec3 computeLightColor(vec3 diffCol, vec3 fragPos, uint clusterIdx)
+// Return the diffuse color without taking into account the diffuse term of the particles.
+vec3 computeLightColor(vec3 fragPos[MAX_SAMPLES_PER_CLUSTER], uint iterCount, uint clusterIdx)
 {
 	vec3 outColor = vec3(0.0);
 
@@ -44,22 +45,23 @@ vec3 computeLightColor(vec3 diffCol, vec3 fragPos, uint clusterIdx)
 	{
 		PointLight light = u_pointLights[u_lightIndices[idxOffset++]];
 
-		vec3 diffC = computeDiffuseColor(diffCol, light.diffuseColorShadowmapId.rgb);
-
-		vec3 frag2Light = light.posRadius.xyz - fragPos;
-		float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
+		for(uint i = 0; i < iterCount; ++i)
+		{
+			vec3 frag2Light = light.posRadius.xyz - fragPos[i];
+			float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
 
-		float shadow = 1.0;
+			float shadow = 1.0;
 #if ENABLE_SHADOWS
-		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-		if(light.diffuseColorShadowmapId.w < 128.0)
-		{
-			shadow = computeShadowFactorOmni(
-				frag2Light, shadowmapLayerIdx, -1.0 / light.posRadius.w, u_lightingUniforms.viewMat, u_omniMapArr);
-		}
+			float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
+			if(light.diffuseColorShadowmapId.w < 128.0)
+			{
+				shadow = computeShadowFactorOmni(
+					frag2Light, shadowmapLayerIdx, -1.0 / light.posRadius.w, u_lightingUniforms.viewMat, u_omniMapArr);
+			}
 #endif
 
-		outColor += diffC * (att * shadow);
+			outColor += light.diffuseColorShadowmapId.rgb * (att * shadow);
+		}
 	}
 
 	// Spot lights
@@ -68,25 +70,27 @@ vec3 computeLightColor(vec3 diffCol, vec3 fragPos, uint clusterIdx)
 	{
 		SpotLight light = u_spotLights[u_lightIndices[idxOffset++]];
 
-		vec3 diffC = computeDiffuseColor(diffCol, light.diffuseColorShadowmapId.rgb);
-
-		vec3 frag2Light = light.posRadius.xyz - fragPos;
-		float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
+		for(uint i = 0; i < iterCount; ++i)
+		{
+			vec3 frag2Light = light.posRadius.xyz - fragPos[i];
+			float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
 
-		vec3 l = normalize(frag2Light);
+			vec3 l = normalize(frag2Light);
 
-		float spot = computeSpotFactor(l, light.outerCosInnerCos.x, light.outerCosInnerCos.y, light.lightDir.xyz);
+			float spot = computeSpotFactor(l, light.outerCosInnerCos.x, light.outerCosInnerCos.y, light.lightDir.xyz);
 
-		float shadow = 1.0;
+			float shadow = 1.0;
 #if ENABLE_SHADOWS
-		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-		if(shadowmapLayerIdx < 128.0)
-		{
-			shadow = computeShadowFactorSpot(light.texProjectionMat, fragPos, shadowmapLayerIdx, 1, u_spotMapArr);
-		}
+			float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
+			if(shadowmapLayerIdx < 128.0)
+			{
+				shadow =
+					computeShadowFactorSpot(light.texProjectionMat, fragPos[i], shadowmapLayerIdx, 1, u_spotMapArr);
+			}
 #endif
 
-		outColor += diffC * (att * spot * shadow);
+			outColor += light.diffuseColorShadowmapId.rgb * (att * spot * shadow);
+		}
 	}
 
 	return outColor;
@@ -104,44 +108,54 @@ void main()
 	float depth = textureLod(u_msDepthRt, in_uv, 0.0).r;
 	float farZ = u_lightingUniforms.projectionParams.z / (u_lightingUniforms.projectionParams.w + depth);
 
-	vec3 diffCol = fog(depth);
-	vec3 prevCol = texture(u_prevResultTex, in_uv).rgb;
+	// Compute the max cluster
+	uint maxK = computeClusterKFromZViewSpace(farZ,
+		u_lightingUniforms.nearFarClustererMagicPad1.x,
+		u_lightingUniforms.nearFarClustererMagicPad1.y,
+		u_lightingUniforms.nearFarClustererMagicPad1.z);
+	++maxK;
 
 	vec2 ndc = in_uv * 2.0 - 1.0;
 
 	uint i = uint(gl_FragCoord.x * 4.0) >> 6;
 	uint j = uint(gl_FragCoord.y * 4.0) >> 6;
 
+	const float DIST = 1.0 / float(MAX_SAMPLES_PER_CLUSTER);
 	float randFactor = rand(ndc + u_lightingUniforms.rendererSizeTimePad1.z);
-	// float randFactor = rand(in_uv);
+	float start = DIST * randFactor;
+	float factors[MAX_SAMPLES_PER_CLUSTER] = float[](start, DIST + start, 2.0 * DIST + start, 3.0 * DIST + start);
 
 	float kNear = -u_lightingUniforms.nearFarClustererMagicPad1.x;
-	uint k;
 	vec3 newCol = vec3(0.0);
-	for(k = 0u; k < CLUSTER_COUNT.z; ++k)
+	uint count = 0;
+	for(uint k = 0u; k < maxK; ++k)
 	{
 		float kFar = computeClusterFar(
 			k, u_lightingUniforms.nearFarClustererMagicPad1.x, u_lightingUniforms.nearFarClustererMagicPad1.z);
 
-		float zMedian = mix(kNear, kFar, randFactor);
-		if(zMedian < farZ)
+		vec3 fragPos[MAX_SAMPLES_PER_CLUSTER];
+
+		uint n;
+		for(n = 0u; n < MAX_SAMPLES_PER_CLUSTER; ++n)
 		{
-			break;
-		}
+			float zMedian = mix(kNear, kFar, factors[n]);
 
-		uint clusterIdx = k * (CLUSTER_COUNT.x * CLUSTER_COUNT.y) + j * CLUSTER_COUNT.x + i;
+			fragPos[n].z = zMedian;
+			fragPos[n].xy = ndc * u_lightingUniforms.projectionParams.xy * fragPos[n].z;
 
-		vec3 fragPos;
-		fragPos.z = zMedian;
-		fragPos.xy = ndc * u_lightingUniforms.projectionParams.xy * fragPos.z;
+			if(zMedian < farZ)
+			{
+				break;
+			}
+		}
 
-		newCol += computeLightColor(diffCol, fragPos, clusterIdx);
+		uint clusterIdx = k * (CLUSTER_COUNT.x * CLUSTER_COUNT.y) + j * CLUSTER_COUNT.x + i;
+		newCol += computeLightColor(fragPos, n, clusterIdx);
+		count += n;
 
 		kNear = kFar;
 	}
 
-	newCol = newCol / max(1.0, float(k));
-
-	out_color = mix(newCol, prevCol, 0.666);
-	// out_color = newCol;
+	newCol = newCol * fog(depth) / max(1.0, float(count));
+	out_color = vec4(newCol, 0.666);
 }

+ 16 - 75
src/anki/renderer/Volumetric.cpp

@@ -27,19 +27,12 @@ Error Volumetric::init(const ConfigSet& config)
 	m_r->createRenderTarget(width,
 		height,
 		IS_COLOR_ATTACHMENT_PIXEL_FORMAT,
-		TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
+		TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE | TextureUsageBit::CLEAR,
 		SamplingFilter::LINEAR,
 		1,
 		m_rt);
-	m_r->createRenderTarget(width,
-		height,
-		IS_COLOR_ATTACHMENT_PIXEL_FORMAT,
-		TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE | TextureUsageBit::CLEAR,
-		SamplingFilter::LINEAR,
-		1,
-		m_tmpRt);
 
-	m_r->clearRenderTarget(m_tmpRt, ClearValue(), TextureUsageBit::SAMPLED_FRAGMENT);
+	m_r->clearRenderTarget(m_rt, ClearValue(), TextureUsageBit::SAMPLED_FRAGMENT);
 
 	// Create shaders
 	ANKI_CHECK(m_r->createShader("shaders/Volumetric.frag.glsl",
@@ -52,40 +45,21 @@ Error Volumetric::init(const ConfigSet& config)
 		m_r->getIs().getLightBin().getClusterer().getClusterCountY(),
 		m_r->getIs().getLightBin().getClusterer().getClusterCountZ()));
 
-	ANKI_CHECK(m_r->createShader("shaders/GaussianBlurGeneric.frag.glsl",
-		m_hblurFrag,
-		"#define HPASS\n"
-		"#define COL_RGB\n"
-		"#define TEXTURE_SIZE vec2(%f, %f)\n"
-		"#define KERNEL_SIZE 11\n",
-		F32(width),
-		F32(height)));
-
-	ANKI_CHECK(m_r->createShader("shaders/GaussianBlurGeneric.frag.glsl",
-		m_vblurFrag,
-		"#define VPASS\n"
-		"#define COL_RGB\n"
-		"#define TEXTURE_SIZE vec2(%f, %f)\n"
-		"#define KERNEL_SIZE 11\n",
-		F32(width),
-		F32(height)));
-
 	// Create pplines
 	ColorStateInfo state;
 	state.m_attachmentCount = 1;
 	state.m_attachments[0].m_format = IS_COLOR_ATTACHMENT_PIXEL_FORMAT;
+	state.m_attachments[0].m_srcBlendMethod = BlendMethod::SRC_ALPHA;
+	state.m_attachments[0].m_dstBlendMethod = BlendMethod::ONE_MINUS_SRC_ALPHA;
 
 	m_r->createDrawQuadPipeline(m_frag->getGrShader(), state, m_ppline);
-	m_r->createDrawQuadPipeline(m_hblurFrag->getGrShader(), state, m_hblurPpline);
-	m_r->createDrawQuadPipeline(m_vblurFrag->getGrShader(), state, m_vblurPpline);
 
 	// Create the resource groups
 	ResourceGroupInitInfo rcInit;
 	rcInit.m_textures[0].m_texture = m_r->getHalfDepth().m_depthRt;
 	rcInit.m_textures[0].m_usage = TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ;
-	rcInit.m_textures[1].m_texture = m_tmpRt;
-	rcInit.m_textures[2].m_texture = m_r->getSm().getSpotTextureArray();
-	rcInit.m_textures[3].m_texture = m_r->getSm().getOmniTextureArray();
+	rcInit.m_textures[1].m_texture = m_r->getSm().getSpotTextureArray();
+	rcInit.m_textures[2].m_texture = m_r->getSm().getOmniTextureArray();
 	rcInit.m_uniformBuffers[0].m_uploadedMemory = true;
 	rcInit.m_uniformBuffers[0].m_usage = BufferUsageBit::UNIFORM_FRAGMENT;
 	rcInit.m_uniformBuffers[1].m_uploadedMemory = true;
@@ -100,37 +74,29 @@ Error Volumetric::init(const ConfigSet& config)
 	rcInit.m_storageBuffers[1].m_usage = BufferUsageBit::STORAGE_FRAGMENT_READ;
 	m_rc = getGrManager().newInstance<ResourceGroup>(rcInit);
 
-	rcInit = ResourceGroupInitInfo();
-	rcInit.m_textures[0].m_texture = m_rt;
-	m_hblurRc = getGrManager().newInstance<ResourceGroup>(rcInit);
-
-	rcInit.m_textures[0].m_texture = m_tmpRt;
-	m_vblurRc = getGrManager().newInstance<ResourceGroup>(rcInit);
-
 	// Create FBs
 	FramebufferInitInfo fbInit;
 	fbInit.m_colorAttachmentCount = 1;
-	fbInit.m_colorAttachments[0].m_texture = m_tmpRt;
-	fbInit.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::DONT_CARE;
-	fbInit.m_colorAttachments[0].m_usageInsideRenderPass = TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE;
-	m_hblurFb = getGrManager().newInstance<Framebuffer>(fbInit);
-
 	fbInit.m_colorAttachments[0].m_texture = m_rt;
-	m_vblurFb = getGrManager().newInstance<Framebuffer>(fbInit);
+	fbInit.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::DONT_CARE;
+	fbInit.m_colorAttachments[0].m_usageInsideRenderPass = TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE;
+	m_fb = getGrManager().newInstance<Framebuffer>(fbInit);
 
 	return ErrorCode::NONE;
 }
 
 void Volumetric::setPreRunBarriers(RenderingContext& ctx)
 {
-	ctx.m_commandBuffer->setTextureSurfaceBarrier(
-		m_rt, TextureUsageBit::NONE, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, TextureSurfaceInfo(0, 0, 0, 0));
+	ctx.m_commandBuffer->setTextureSurfaceBarrier(m_rt,
+		TextureUsageBit::NONE,
+		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE,
+		TextureSurfaceInfo(0, 0, 0, 0));
 }
 
 void Volumetric::setPostRunBarriers(RenderingContext& ctx)
 {
 	ctx.m_commandBuffer->setTextureSurfaceBarrier(m_rt,
-		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
+		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE,
 		TextureUsageBit::SAMPLED_FRAGMENT,
 		TextureSurfaceInfo(0, 0, 0, 0));
 }
@@ -145,41 +111,16 @@ void Volumetric::run(RenderingContext& ctx)
 	Vec4* uniforms = static_cast<Vec4*>(getGrManager().allocateFrameTransientMemory(
 		sizeof(Vec4) * 2, BufferUsageBit::UNIFORM_ALL, dyn.m_uniformBuffers[3]));
 	computeLinearizeDepthOptimal(frc.getNear(), frc.getFar(), uniforms[0].x(), uniforms[0].y());
+
 	uniforms[1] = Vec4(m_fogColor, m_fogFactor);
 
 	// pass 0
 	cmdb->setViewport(0, 0, m_r->getWidth() / VOLUMETRIC_FRACTION, m_r->getHeight() / VOLUMETRIC_FRACTION);
-	cmdb->beginRenderPass(m_vblurFb);
+	cmdb->beginRenderPass(m_fb);
 	cmdb->bindPipeline(m_ppline);
 	cmdb->bindResourceGroup(m_rc, 0, &dyn);
 	m_r->drawQuad(cmdb);
 	cmdb->endRenderPass();
-
-	// hpass
-	cmdb->setTextureSurfaceBarrier(m_rt,
-		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
-		TextureUsageBit::SAMPLED_FRAGMENT,
-		TextureSurfaceInfo(0, 0, 0, 0));
-	cmdb->setTextureSurfaceBarrier(
-		m_tmpRt, TextureUsageBit::NONE, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, TextureSurfaceInfo(0, 0, 0, 0));
-	cmdb->beginRenderPass(m_hblurFb);
-	cmdb->bindPipeline(m_hblurPpline);
-	cmdb->bindResourceGroup(m_hblurRc, 0, nullptr);
-	m_r->drawQuad(cmdb);
-	cmdb->endRenderPass();
-
-	// vpass
-	cmdb->setTextureSurfaceBarrier(m_tmpRt,
-		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
-		TextureUsageBit::SAMPLED_FRAGMENT,
-		TextureSurfaceInfo(0, 0, 0, 0));
-	cmdb->setTextureSurfaceBarrier(
-		m_rt, TextureUsageBit::NONE, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, TextureSurfaceInfo(0, 0, 0, 0));
-	cmdb->beginRenderPass(m_vblurFb);
-	cmdb->bindPipeline(m_vblurPpline);
-	cmdb->bindResourceGroup(m_vblurRc, 0, nullptr);
-	m_r->drawQuad(cmdb);
-	cmdb->endRenderPass();
 }
 
 } // end namespace anki

+ 1 - 13
src/anki/renderer/Volumetric.h

@@ -40,22 +40,10 @@ anki_internal:
 	void setPostRunBarriers(RenderingContext& ctx);
 
 private:
-	TexturePtr m_tmpRt;
-
 	ResourceGroupPtr m_rc;
-	ResourceGroupPtr m_hblurRc;
-	ResourceGroupPtr m_vblurRc;
-
 	ShaderResourcePtr m_frag;
-	ShaderResourcePtr m_vblurFrag;
-	ShaderResourcePtr m_hblurFrag;
-
 	PipelinePtr m_ppline;
-	PipelinePtr m_hblurPpline;
-	PipelinePtr m_vblurPpline;
-
-	FramebufferPtr m_vblurFb;
-	FramebufferPtr m_hblurFb;
+	FramebufferPtr m_fb;
 
 	Vec3 m_fogColor = Vec3(1.0);
 	F32 m_fogFactor = 1.0;