Browse Source

New SSGI + SSAO

Panagiotis Christopoulos Charitos 4 years ago
parent
commit
1a3858c3f0

+ 0 - 1
AnKi/Renderer.h

@@ -22,7 +22,6 @@
 #include <AnKi/Renderer/Ssr.h>
 #include <AnKi/Renderer/ProbeReflections.h>
 #include <AnKi/Renderer/Dbg.h>
-#include <AnKi/Renderer/Ssao.h>
 #include <AnKi/Renderer/Drawer.h>
 #include <AnKi/Renderer/UiStage.h>
 #include <AnKi/Renderer/Tonemapping.h>

+ 3 - 5
AnKi/Renderer/ConfigDefs.h

@@ -22,11 +22,9 @@ ANKI_CONFIG_OPTION(r_ssrDepthLod, 2, 0, 1000)
 ANKI_CONFIG_OPTION(r_ssgiMaxSteps, 32, 1, 2048)
 ANKI_CONFIG_OPTION(r_ssgiDepthLod, 2, 0, 1000)
 
-ANKI_CONFIG_OPTION(r_indirectDiffuseSsgiMaxSteps, 16, 1, 2048)
-ANKI_CONFIG_OPTION(r_indirectDiffuseSsgiDepthLod, 1, 0, 1000)
-ANKI_CONFIG_OPTION(r_indirectDiffuseSsgiStepIncrement, 8, 1, 512)
-ANKI_CONFIG_OPTION(r_indirectDiffuseDenoiseMinSampleCount, 8, 1, 128)
-ANKI_CONFIG_OPTION(r_indirectDiffuseDenoiseMaxSampleCount, 32, 1, 128)
+ANKI_CONFIG_OPTION(r_indirectDiffuseSsgiSamples, 8, 1, 1024)
+ANKI_CONFIG_OPTION(r_indirectDiffuseSsgiRadius, 2.0, 0.1, 100.0)
+ANKI_CONFIG_OPTION(r_indirectDiffuseDenoiseSampleCount, 4, 1, 128)
 
 ANKI_CONFIG_OPTION(r_shadowMappingTileResolution, 128, 16, 2048)
 ANKI_CONFIG_OPTION(r_shadowMappingTileCountPerRowOrColumn, 16, 1, 256)

+ 0 - 1
AnKi/Renderer/FinalComposite.cpp

@@ -11,7 +11,6 @@
 #include <AnKi/Renderer/LightShading.h>
 #include <AnKi/Renderer/GBuffer.h>
 #include <AnKi/Renderer/Dbg.h>
-#include <AnKi/Renderer/Ssao.h>
 #include <AnKi/Renderer/Ssr.h>
 #include <AnKi/Renderer/DownscaleBlur.h>
 #include <AnKi/Renderer/UiStage.h>

+ 1 - 1
AnKi/Renderer/GlobalIllumination.cpp

@@ -484,7 +484,7 @@ void GlobalIllumination::prepareProbes(InternalContext& giCtx)
 		const Bool shouldInitTextures = !entry.m_volumeTex.isCreated() || entry.m_volumeSize != probe.m_cellCounts;
 		if(shouldInitTextures)
 		{
-			TextureInitInfo texInit;
+			TextureInitInfo texInit("GiProbeVolume");
 			texInit.m_type = TextureType::_3D;
 			texInit.m_format = Format::B10G11R11_UFLOAT_PACK32;
 			texInit.m_width = probe.m_cellCounts.x() * 6;

+ 27 - 52
AnKi/Renderer/IndirectDiffuse.cpp

@@ -10,7 +10,6 @@
 #include <AnKi/Renderer/DownscaleBlur.h>
 #include <AnKi/Renderer/MotionVectors.h>
 #include <AnKi/Renderer/GlobalIllumination.h>
-#include <AnKi/Renderer/Ssao.h>
 #include <AnKi/Core/ConfigSet.h>
 #include <AnKi/Shaders/Include/IndirectDiffuseTypes.h>
 
@@ -45,20 +44,10 @@ Error IndirectDiffuse::initInternal(const ConfigSet& cfg)
 	texInit.setName("IndirectDiffuse #2");
 	m_rts[1] = m_r->createAndClearRenderTarget(texInit);
 
-	texInit = m_r->create2DRenderTargetInitInfo(size.x(), size.y(), Format::R16G16B16A16_SFLOAT,
-												TextureUsageBit::IMAGE_COMPUTE_WRITE | TextureUsageBit::ALL_SAMPLED,
-												"IndirectDiffuseMoments #1");
-	texInit.m_initialUsage = TextureUsageBit::ALL_SAMPLED;
-	m_momentsAndHistoryLengthRts[0] = m_r->createAndClearRenderTarget(texInit);
-	texInit.setName("IndirectDiffuseMoments #2");
-	m_momentsAndHistoryLengthRts[1] = m_r->createAndClearRenderTarget(texInit);
-
 	// Init SSGI+probes pass
 	{
-		m_main.m_maxSteps = cfg.getNumberU32("r_indirectDiffuseSsgiMaxSteps");
-		m_main.m_depthLod =
-			min(cfg.getNumberU32("r_indirectDiffuseSsgiDepthLod"), m_r->getDepthDownscale().getMipmapCount() - 1);
-		m_main.m_stepIncrement = cfg.getNumberU32("r_indirectDiffuseSsgiStepIncrement");
+		m_main.m_radius = cfg.getNumberF32("r_indirectDiffuseSsgiRadius");
+		m_main.m_sampleCount = cfg.getNumberU32("r_indirectDiffuseSsgiSamples");
 
 		ANKI_CHECK(getResourceManager().loadResource("Shaders/IndirectDiffuse.ankiprog", m_main.m_prog));
 
@@ -69,9 +58,8 @@ Error IndirectDiffuse::initInternal(const ConfigSet& cfg)
 
 	// Init denoise
 	{
-		m_denoise.m_minSampleCount = F32(cfg.getNumberU32("r_indirectDiffuseDenoiseMinSampleCount"));
-		m_denoise.m_maxSampleCount =
-			max(F32(cfg.getNumberU32("r_indirectDiffuseDenoiseMaxSampleCount")), m_denoise.m_minSampleCount);
+		m_denoise.m_sampleCount = F32(cfg.getNumberU32("r_indirectDiffuseDenoiseSampleCount"));
+		m_denoise.m_sampleCount = max(1.0f, std::round(m_denoise.m_sampleCount / 2.0f));
 
 		ANKI_CHECK(getResourceManager().loadResource("Shaders/IndirectDiffuseDenoise.ankiprog", m_denoise.m_prog));
 
@@ -102,19 +90,11 @@ void IndirectDiffuse::populateRenderGraph(RenderingContext& ctx)
 		{
 			m_runCtx.m_mainRtHandles[0] = rgraph.importRenderTarget(m_rts[readRtIdx]);
 			m_runCtx.m_mainRtHandles[1] = rgraph.importRenderTarget(m_rts[writeRtIdx]);
-			m_runCtx.m_momentsAndHistoryLengthHandles[0] =
-				rgraph.importRenderTarget(m_momentsAndHistoryLengthRts[readRtIdx]);
-			m_runCtx.m_momentsAndHistoryLengthHandles[1] =
-				rgraph.importRenderTarget(m_momentsAndHistoryLengthRts[writeRtIdx]);
 		}
 		else
 		{
 			m_runCtx.m_mainRtHandles[0] = rgraph.importRenderTarget(m_rts[readRtIdx], TextureUsageBit::ALL_SAMPLED);
 			m_runCtx.m_mainRtHandles[1] = rgraph.importRenderTarget(m_rts[writeRtIdx], TextureUsageBit::ALL_SAMPLED);
-			m_runCtx.m_momentsAndHistoryLengthHandles[0] =
-				rgraph.importRenderTarget(m_momentsAndHistoryLengthRts[readRtIdx], TextureUsageBit::ALL_SAMPLED);
-			m_runCtx.m_momentsAndHistoryLengthHandles[1] =
-				rgraph.importRenderTarget(m_momentsAndHistoryLengthRts[writeRtIdx], TextureUsageBit::ALL_SAMPLED);
 			m_rtsImportedOnce = true;
 		}
 
@@ -123,20 +103,17 @@ void IndirectDiffuse::populateRenderGraph(RenderingContext& ctx)
 
 		rpass.newDependency(
 			RenderPassDependency(m_runCtx.m_mainRtHandles[WRITE], TextureUsageBit::IMAGE_COMPUTE_WRITE));
-		rpass.newDependency(RenderPassDependency(m_runCtx.m_momentsAndHistoryLengthHandles[WRITE],
-												 TextureUsageBit::IMAGE_COMPUTE_WRITE));
 
 		const TextureUsageBit readUsage = TextureUsageBit::SAMPLED_COMPUTE;
+		m_r->getGlobalIllumination().setRenderGraphDependencies(ctx, rpass, readUsage);
 		rpass.newDependency(RenderPassDependency(m_r->getGBuffer().getColorRt(2), readUsage));
 		TextureSubresourceInfo hizSubresource;
-		hizSubresource.m_firstMipmap = m_main.m_depthLod;
+		hizSubresource.m_mipmapCount = 1;
 		rpass.newDependency(RenderPassDependency(m_r->getDepthDownscale().getHiZRt(), readUsage, hizSubresource));
 		rpass.newDependency(RenderPassDependency(m_r->getDownscaleBlur().getRt(), readUsage));
 		rpass.newDependency(RenderPassDependency(m_r->getMotionVectors().getMotionVectorsRt(), readUsage));
 		rpass.newDependency(RenderPassDependency(m_r->getMotionVectors().getRejectionFactorRt(), readUsage));
 		rpass.newDependency(RenderPassDependency(m_runCtx.m_mainRtHandles[READ], readUsage));
-		rpass.newDependency(RenderPassDependency(m_runCtx.m_momentsAndHistoryLengthHandles[READ], readUsage));
-		rpass.newDependency(RenderPassDependency(m_r->getSsao().getRt(), readUsage));
 
 		rpass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) {
 			CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
@@ -149,32 +126,33 @@ void IndirectDiffuse::populateRenderGraph(RenderingContext& ctx)
 			bindStorage(cmdb, 0, 3, binning.m_clustersToken);
 
 			rgraphCtx.bindImage(0, 4, m_runCtx.m_mainRtHandles[WRITE]);
-			rgraphCtx.bindImage(0, 5, m_runCtx.m_momentsAndHistoryLengthHandles[WRITE]);
 
-			cmdb->bindSampler(0, 6, m_r->getSamplers().m_trilinearClamp);
-			rgraphCtx.bindColorTexture(0, 7, m_r->getGBuffer().getColorRt(2));
+			cmdb->bindSampler(0, 5, m_r->getSamplers().m_trilinearClamp);
+			rgraphCtx.bindColorTexture(0, 6, m_r->getGBuffer().getColorRt(2));
 
 			TextureSubresourceInfo hizSubresource;
-			hizSubresource.m_firstMipmap = m_main.m_depthLod;
-			rgraphCtx.bindTexture(0, 8, m_r->getDepthDownscale().getHiZRt(), hizSubresource);
-			rgraphCtx.bindColorTexture(0, 9, m_r->getDownscaleBlur().getRt());
-			rgraphCtx.bindColorTexture(0, 10, m_runCtx.m_mainRtHandles[READ]);
-			rgraphCtx.bindColorTexture(0, 11, m_r->getMotionVectors().getMotionVectorsRt());
-			rgraphCtx.bindColorTexture(0, 12, m_r->getMotionVectors().getRejectionFactorRt());
-			rgraphCtx.bindColorTexture(0, 13, m_runCtx.m_momentsAndHistoryLengthHandles[READ]);
-			rgraphCtx.bindColorTexture(0, 14, m_r->getSsao().getRt());
+			hizSubresource.m_mipmapCount = 1;
+			rgraphCtx.bindTexture(0, 7, m_r->getDepthDownscale().getHiZRt(), hizSubresource);
+			rgraphCtx.bindColorTexture(0, 8, m_r->getDownscaleBlur().getRt());
+			rgraphCtx.bindColorTexture(0, 9, m_runCtx.m_mainRtHandles[READ]);
+			rgraphCtx.bindColorTexture(0, 10, m_r->getMotionVectors().getMotionVectorsRt());
+			rgraphCtx.bindColorTexture(0, 11, m_r->getMotionVectors().getRejectionFactorRt());
 
 			// Bind uniforms
 			IndirectDiffuseUniforms unis;
-			unis.m_depthBufferSize = m_r->getInternalResolution() >> (m_main.m_depthLod + 1);
-			unis.m_maxSteps = m_main.m_maxSteps;
-			unis.m_stepIncrement = m_main.m_stepIncrement;
 			unis.m_viewportSize = m_r->getInternalResolution() / 2u;
 			unis.m_viewportSizef = Vec2(unis.m_viewportSize);
+			const Mat4& pmat = ctx.m_matrices.m_projection;
+			unis.m_projectionMat = Vec4(pmat(0, 0), pmat(1, 1), pmat(2, 2), pmat(2, 3));
+			unis.m_radius = m_main.m_radius;
+			unis.m_sampleCount = m_main.m_sampleCount;
+			unis.m_sampleCountf = F32(m_main.m_sampleCount);
+			unis.m_ssaoBias = m_main.m_ssaoBias;
+			unis.m_ssaoStrength = m_main.m_ssaoStrength;
 			cmdb->setPushConstants(&unis, sizeof(unis));
 
 			// Dispatch
-			dispatchPPCompute(cmdb, 8, 8, m_r->getInternalResolution().x() / 2, m_r->getInternalResolution().y() / 2);
+			dispatchPPCompute(cmdb, 8, 8, unis.m_viewportSize.x(), unis.m_viewportSize.y());
 		});
 	}
 
@@ -190,11 +168,10 @@ void IndirectDiffuse::populateRenderGraph(RenderingContext& ctx)
 		rpass.newDependency(RenderPassDependency(m_runCtx.m_mainRtHandles[readIdx], readUsage));
 
 		TextureSubresourceInfo hizSubresource;
-		hizSubresource.m_firstMipmap = 0;
+		hizSubresource.m_mipmapCount = 1;
 		rpass.newDependency(RenderPassDependency(m_r->getDepthDownscale().getHiZRt(), readUsage, hizSubresource));
 
 		rpass.newDependency(RenderPassDependency(m_r->getGBuffer().getColorRt(2), readUsage));
-		rpass.newDependency(RenderPassDependency(m_runCtx.m_momentsAndHistoryLengthHandles[readIdx], readUsage));
 
 		rpass.newDependency(
 			RenderPassDependency(m_runCtx.m_mainRtHandles[!readIdx], TextureUsageBit::IMAGE_COMPUTE_WRITE));
@@ -206,23 +183,21 @@ void IndirectDiffuse::populateRenderGraph(RenderingContext& ctx)
 			cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearClamp);
 			rgraphCtx.bindColorTexture(0, 1, m_runCtx.m_mainRtHandles[readIdx]);
 			TextureSubresourceInfo hizSubresource;
-			hizSubresource.m_firstMipmap = 0;
+			hizSubresource.m_mipmapCount = 1;
 			rgraphCtx.bindTexture(0, 2, m_r->getDepthDownscale().getHiZRt(), hizSubresource);
 			rgraphCtx.bindColorTexture(0, 3, m_r->getGBuffer().getColorRt(2));
-			rgraphCtx.bindColorTexture(0, 4, m_runCtx.m_momentsAndHistoryLengthHandles[readIdx]);
-			rgraphCtx.bindImage(0, 5, m_runCtx.m_mainRtHandles[!readIdx]);
+			rgraphCtx.bindImage(0, 4, m_runCtx.m_mainRtHandles[!readIdx]);
 
 			IndirectDiffuseDenoiseUniforms unis;
 			unis.m_invertedViewProjectionJitterMat = ctx.m_matrices.m_invertedViewProjectionJitter;
 			unis.m_viewportSize = m_r->getInternalResolution() / 2u;
 			unis.m_viewportSizef = Vec2(unis.m_viewportSize);
-			unis.m_minSampleCount = m_denoise.m_minSampleCount;
-			unis.m_maxSampleCount = m_denoise.m_maxSampleCount;
+			unis.m_sampleCountDiv2 = m_denoise.m_sampleCount;
 
 			cmdb->setPushConstants(&unis, sizeof(unis));
 
 			// Dispatch
-			dispatchPPCompute(cmdb, 8, 8, m_r->getInternalResolution().x() / 2, m_r->getInternalResolution().y() / 2);
+			dispatchPPCompute(cmdb, 8, 8, unis.m_viewportSize.x(), unis.m_viewportSize.y());
 		});
 	}
 }

+ 5 - 7
AnKi/Renderer/IndirectDiffuse.h

@@ -45,7 +45,6 @@ public:
 
 private:
 	Array<TexturePtr, 2> m_rts;
-	Array<TexturePtr, 2> m_momentsAndHistoryLengthRts;
 	Bool m_rtsImportedOnce = false;
 
 	static constexpr U32 READ = 0;
@@ -56,9 +55,10 @@ private:
 	public:
 		ShaderProgramResourcePtr m_prog;
 		ShaderProgramPtr m_grProg;
-		U32 m_maxSteps = 32;
-		U32 m_stepIncrement = 16;
-		U32 m_depthLod = 0;
+		F32 m_radius;
+		U32 m_sampleCount = 8.0f;
+		F32 m_ssaoStrength = 2.5f;
+		F32 m_ssaoBias = -0.1f;
 	} m_main;
 
 	class
@@ -66,15 +66,13 @@ private:
 	public:
 		ShaderProgramResourcePtr m_prog;
 		Array<ShaderProgramPtr, 2> m_grProgs;
-		F32 m_minSampleCount = 1.0f;
-		F32 m_maxSampleCount = 1.0f;
+		F32 m_sampleCount = 1.0f;
 	} m_denoise;
 
 	class
 	{
 	public:
 		Array<RenderTargetHandle, 2> m_mainRtHandles;
-		Array<RenderTargetHandle, 2> m_momentsAndHistoryLengthHandles;
 	} m_runCtx;
 
 	ANKI_USE_RESULT Error initInternal(const ConfigSet& cfg);

+ 1 - 6
AnKi/Renderer/Renderer.cpp

@@ -20,7 +20,6 @@
 #include <AnKi/Renderer/LightShading.h>
 #include <AnKi/Renderer/ShadowMapping.h>
 #include <AnKi/Renderer/FinalComposite.h>
-#include <AnKi/Renderer/Ssao.h>
 #include <AnKi/Renderer/Bloom.h>
 #include <AnKi/Renderer/Tonemapping.h>
 #include <AnKi/Renderer/ForwardShading.h>
@@ -116,7 +115,7 @@ Error Renderer::initInternal(const ConfigSet& config)
 	}
 
 	{
-		TextureInitInfo texinit;
+		TextureInitInfo texinit("RendererDummy");
 		texinit.m_width = texinit.m_height = 4;
 		texinit.m_usage = TextureUsageBit::ALL_SAMPLED;
 		texinit.m_format = Format::R8G8B8A8_UNORM;
@@ -175,9 +174,6 @@ Error Renderer::initInternal(const ConfigSet& config)
 	m_lensFlare.reset(m_alloc.newInstance<LensFlare>(this));
 	ANKI_CHECK(m_lensFlare->init(config));
 
-	m_ssao.reset(m_alloc.newInstance<Ssao>(this));
-	ANKI_CHECK(m_ssao->init(config));
-
 	m_downscaleBlur.reset(getAllocator().newInstance<DownscaleBlur>(this));
 	ANKI_CHECK(m_downscaleBlur->init(config));
 
@@ -360,7 +356,6 @@ Error Renderer::populateRenderGraph(RenderingContext& ctx)
 		m_shadowmapsResolve->populateRenderGraph(ctx);
 	}
 	m_volumetricFog->populateRenderGraph(ctx);
-	m_ssao->populateRenderGraph(ctx);
 	m_lensFlare->populateRenderGraph(ctx);
 	m_ssr->populateRenderGraph(ctx);
 	m_indirectDiffuse->populateRenderGraph(ctx);

+ 0 - 1
AnKi/Renderer/RendererObjectDefs.h

@@ -9,7 +9,6 @@ ANKI_RENDERER_OBJECT_DEF(ShadowMapping, shadowMapping)
 ANKI_RENDERER_OBJECT_DEF(LightShading, lightShading)
 ANKI_RENDERER_OBJECT_DEF(ForwardShading, forwardShading)
 ANKI_RENDERER_OBJECT_DEF(LensFlare, lensFlare)
-ANKI_RENDERER_OBJECT_DEF(Ssao, ssao)
 ANKI_RENDERER_OBJECT_DEF(Tonemapping, tonemapping)
 ANKI_RENDERER_OBJECT_DEF(Bloom, bloom)
 ANKI_RENDERER_OBJECT_DEF(FinalComposite, finalComposite)

+ 0 - 259
AnKi/Renderer/Ssao.cpp

@@ -1,259 +0,0 @@
-// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <AnKi/Renderer/Ssao.h>
-#include <AnKi/Renderer/Renderer.h>
-#include <AnKi/Renderer/GBuffer.h>
-#include <AnKi/Renderer/RenderQueue.h>
-#include <AnKi/Renderer/DepthDownscale.h>
-#include <AnKi/Util/Functions.h>
-#include <AnKi/Core/ConfigSet.h>
-
-namespace anki
-{
-
-Ssao::~Ssao()
-{
-}
-
-Error Ssao::initMain(const ConfigSet& config)
-{
-	// Noise
-	ANKI_CHECK(getResourceManager().loadResource("EngineAssets/BlueNoise_Rgba8_64x64.png", m_main.m_noiseImage));
-
-	// Shader
-	if(m_useCompute)
-	{
-		ANKI_CHECK(getResourceManager().loadResource("Shaders/SsaoCompute.ankiprog", m_main.m_prog));
-	}
-	else
-	{
-		ANKI_CHECK(getResourceManager().loadResource("Shaders/Ssao.ankiprog", m_main.m_prog));
-	}
-
-	ShaderProgramResourceVariantInitInfo variantInitInfo(m_main.m_prog);
-	variantInitInfo.addMutation("USE_NORMAL", (m_useNormal) ? 1u : 0u);
-	variantInitInfo.addMutation("SOFT_BLUR", (m_useSoftBlur) ? 1u : 0u);
-	variantInitInfo.addConstant("NOISE_MAP_SIZE", U32(m_main.m_noiseImage->getWidth()));
-	variantInitInfo.addConstant("FB_SIZE", UVec2(m_width, m_height));
-	variantInitInfo.addConstant("RADIUS", 2.5f);
-	variantInitInfo.addConstant("BIAS", 0.0f);
-	variantInitInfo.addConstant("STRENGTH", 2.5f);
-	variantInitInfo.addConstant("SAMPLE_COUNT", 8u);
-	const ShaderProgramResourceVariant* variant;
-	m_main.m_prog->getOrCreateVariant(variantInitInfo, variant);
-	m_main.m_workgroupSize[0] = variant->getWorkgroupSizes()[0];
-	m_main.m_workgroupSize[1] = variant->getWorkgroupSizes()[1];
-	m_main.m_grProg = variant->getProgram();
-
-	return Error::NONE;
-}
-
-Error Ssao::initBlur(const ConfigSet& config)
-{
-	// shader
-	if(m_blurUseCompute)
-	{
-		ANKI_CHECK(m_r->getResourceManager().loadResource("Shaders/GaussianBlurCompute.ankiprog", m_blur.m_prog));
-
-		ShaderProgramResourceVariantInitInfo variantInitInfo(m_blur.m_prog);
-		variantInitInfo.addMutation("ORIENTATION", 2);
-		variantInitInfo.addMutation("KERNEL_SIZE", 3);
-		variantInitInfo.addMutation("COLOR_COMPONENTS", 1);
-		variantInitInfo.addConstant("TEXTURE_SIZE", UVec2(m_width, m_height));
-
-		const ShaderProgramResourceVariant* variant;
-		m_blur.m_prog->getOrCreateVariant(variantInitInfo, variant);
-
-		m_blur.m_workgroupSize[0] = variant->getWorkgroupSizes()[0];
-		m_blur.m_workgroupSize[1] = variant->getWorkgroupSizes()[1];
-
-		m_blur.m_grProg = variant->getProgram();
-	}
-	else
-	{
-		ANKI_CHECK(m_r->getResourceManager().loadResource("Shaders/GaussianBlur.ankiprog", m_blur.m_prog));
-
-		ShaderProgramResourceVariantInitInfo variantInitInfo(m_blur.m_prog);
-		variantInitInfo.addMutation("ORIENTATION", 2);
-		variantInitInfo.addMutation("KERNEL_SIZE", 3);
-		variantInitInfo.addMutation("COLOR_COMPONENTS", 1);
-		variantInitInfo.addConstant("TEXTURE_SIZE", UVec2(m_width, m_height));
-
-		const ShaderProgramResourceVariant* variant;
-		m_blur.m_prog->getOrCreateVariant(variantInitInfo, variant);
-
-		m_blur.m_grProg = variant->getProgram();
-	}
-
-	return Error::NONE;
-}
-
-Error Ssao::init(const ConfigSet& config)
-{
-	m_width = m_r->getInternalResolution().x() / SSAO_FRACTION;
-	m_height = m_r->getInternalResolution().y() / SSAO_FRACTION;
-
-	ANKI_R_LOGI("Initializing SSAO. Size %ux%u", m_width, m_height);
-
-	// RT
-	m_rtDescrs[0] = m_r->create2DRenderTargetDescription(m_width, m_height, RT_PIXEL_FORMAT, "SSAOMain");
-	m_rtDescrs[0].bake();
-
-	m_rtDescrs[1] = m_r->create2DRenderTargetDescription(m_width, m_height, RT_PIXEL_FORMAT, "SSAOBlur");
-	m_rtDescrs[1].bake();
-
-	// FB descr
-	m_fbDescr.m_colorAttachmentCount = 1;
-	m_fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::DONT_CARE;
-	m_fbDescr.bake();
-
-	Error err = initMain(config);
-
-	if(!err)
-	{
-		err = initBlur(config);
-	}
-
-	if(err)
-	{
-		ANKI_R_LOGE("Failed to init PPS SSAO");
-	}
-
-	return err;
-}
-
-void Ssao::runMain(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx)
-{
-	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-
-	cmdb->bindShaderProgram(m_main.m_grProg);
-
-	// Bind resources
-	cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearClamp);
-	cmdb->bindSampler(0, 1, m_r->getSamplers().m_trilinearRepeat);
-
-	rgraphCtx.bindTexture(0, 2, m_r->getDepthDownscale().getHiZRt(), HIZ_HALF_DEPTH);
-	cmdb->bindTexture(0, 3, m_main.m_noiseImage->getTextureView());
-
-	if(m_useNormal)
-	{
-		rgraphCtx.bindColorTexture(0, 4, m_r->getGBuffer().getColorRt(2));
-	}
-
-	struct Unis
-	{
-		Vec4 m_unprojectionParams;
-		Vec4 m_projectionMat;
-		Mat3x4 m_viewRotMat;
-	} unis;
-
-	const Mat4& pmat = ctx.m_renderQueue->m_projectionMatrix;
-	unis.m_unprojectionParams = ctx.m_matrices.m_unprojectionParameters;
-	unis.m_projectionMat = Vec4(pmat(0, 0), pmat(1, 1), pmat(2, 2), pmat(2, 3));
-	unis.m_viewRotMat = Mat3x4(Vec3(0.0f), ctx.m_renderQueue->m_viewMatrix.getRotationPart());
-	cmdb->setPushConstants(&unis, sizeof(unis));
-
-	if(m_useCompute)
-	{
-		rgraphCtx.bindImage(0, 5, m_runCtx.m_rts[0], TextureSubresourceInfo());
-		dispatchPPCompute(cmdb, m_main.m_workgroupSize[0], m_main.m_workgroupSize[1], m_width, m_height);
-	}
-	else
-	{
-		cmdb->setViewport(0, 0, m_width, m_height);
-		drawQuad(cmdb);
-	}
-}
-
-void Ssao::runBlur(RenderPassWorkContext& rgraphCtx)
-{
-	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-
-	cmdb->bindShaderProgram(m_blur.m_grProg);
-
-	cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearClamp);
-	rgraphCtx.bindColorTexture(0, 1, m_runCtx.m_rts[0]);
-
-	if(m_blurUseCompute)
-	{
-		rgraphCtx.bindImage(0, 2, m_runCtx.m_rts[1], TextureSubresourceInfo());
-		dispatchPPCompute(cmdb, m_blur.m_workgroupSize[0], m_blur.m_workgroupSize[1], m_width, m_height);
-	}
-	else
-	{
-		cmdb->setViewport(0, 0, m_width, m_height);
-		drawQuad(cmdb);
-	}
-}
-
-void Ssao::populateRenderGraph(RenderingContext& ctx)
-{
-	RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
-
-	// Create RTs
-	m_runCtx.m_rts[0] = rgraph.newRenderTarget(m_rtDescrs[0]);
-	m_runCtx.m_rts[1] = rgraph.newRenderTarget(m_rtDescrs[1]);
-
-	// Create main render pass
-	{
-		if(m_useCompute)
-		{
-			ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("SSAO main");
-
-			if(m_useNormal)
-			{
-				pass.newDependency({m_r->getGBuffer().getColorRt(2), TextureUsageBit::SAMPLED_COMPUTE});
-			}
-
-			pass.newDependency({m_r->getDepthDownscale().getHiZRt(), TextureUsageBit::SAMPLED_COMPUTE, HIZ_HALF_DEPTH});
-			pass.newDependency({m_runCtx.m_rts[0], TextureUsageBit::IMAGE_COMPUTE_WRITE});
-
-			pass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) { runMain(ctx, rgraphCtx); });
-		}
-		else
-		{
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("SSAO main");
-
-			pass.setFramebufferInfo(m_fbDescr, {{m_runCtx.m_rts[0]}}, {});
-
-			if(m_useNormal)
-			{
-				pass.newDependency({m_r->getGBuffer().getColorRt(2), TextureUsageBit::SAMPLED_FRAGMENT});
-			}
-
-			pass.newDependency(
-				{m_r->getDepthDownscale().getHiZRt(), TextureUsageBit::SAMPLED_FRAGMENT, HIZ_HALF_DEPTH});
-			pass.newDependency({m_runCtx.m_rts[0], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
-
-			pass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) { runMain(ctx, rgraphCtx); });
-		}
-	}
-
-	// Create Blur pass
-	{
-		if(m_blurUseCompute)
-		{
-			ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("SSAO blur");
-
-			pass.setWork([this](RenderPassWorkContext& rgraphCtx) { runBlur(rgraphCtx); });
-
-			pass.newDependency({m_runCtx.m_rts[1], TextureUsageBit::IMAGE_COMPUTE_WRITE});
-			pass.newDependency({m_runCtx.m_rts[0], TextureUsageBit::SAMPLED_COMPUTE});
-		}
-		else
-		{
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("SSAO blur");
-
-			pass.setWork([this](RenderPassWorkContext& rgraphCtx) { runBlur(rgraphCtx); });
-			pass.setFramebufferInfo(m_fbDescr, {{m_runCtx.m_rts[1]}}, {});
-
-			pass.newDependency({m_runCtx.m_rts[1], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
-			pass.newDependency({m_runCtx.m_rts[0], TextureUsageBit::SAMPLED_FRAGMENT});
-		}
-	}
-}
-
-} // end namespace anki

+ 0 - 90
AnKi/Renderer/Ssao.h

@@ -1,90 +0,0 @@
-// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <AnKi/Renderer/RendererObject.h>
-#include <AnKi/Resource/ImageResource.h>
-#include <AnKi/Gr.h>
-
-namespace anki
-{
-
-/// @addtogroup renderer
-/// @{
-
-/// Screen space ambient occlusion pass
-class Ssao : public RendererObject
-{
-public:
-	static const Format RT_PIXEL_FORMAT = Format::R8_UNORM;
-
-	Ssao(Renderer* r)
-		: RendererObject(r)
-	{
-		registerDebugRenderTarget("SsaoFinal");
-	}
-
-	~Ssao();
-
-	ANKI_USE_RESULT Error init(const ConfigSet& config);
-
-	/// Populate the rendergraph.
-	void populateRenderGraph(RenderingContext& ctx);
-
-	RenderTargetHandle getRt() const
-	{
-		return m_runCtx.m_rts[1];
-	}
-
-	void getDebugRenderTarget(CString rtName, RenderTargetHandle& handle,
-							  ShaderProgramPtr& optionalShaderProgram) const override
-	{
-		ANKI_ASSERT(rtName == "SsaoFinal");
-		handle = getRt();
-	}
-
-private:
-	static const Bool m_useNormal = false;
-	static const Bool m_useCompute = true;
-	static const Bool m_useSoftBlur = true;
-	static const Bool m_blurUseCompute = true;
-	U32 m_width, m_height;
-
-	class
-	{
-	public:
-		ShaderProgramResourcePtr m_prog;
-		ShaderProgramPtr m_grProg;
-		ImageResourcePtr m_noiseImage;
-		Array<U32, 2> m_workgroupSize = {};
-	} m_main; ///< Main noisy pass.
-
-	class
-	{
-	public:
-		ShaderProgramResourcePtr m_prog;
-		ShaderProgramPtr m_grProg;
-		Array<U32, 2> m_workgroupSize = {};
-	} m_blur; ///< Box blur.
-
-	class
-	{
-	public:
-		Array<RenderTargetHandle, 2> m_rts;
-	} m_runCtx; ///< Runtime context.
-
-	Array<RenderTargetDescription, 2> m_rtDescrs;
-	FramebufferDescription m_fbDescr;
-
-	ANKI_USE_RESULT Error initMain(const ConfigSet& set);
-	ANKI_USE_RESULT Error initBlur(const ConfigSet& set);
-
-	void runMain(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx);
-	void runBlur(RenderPassWorkContext& rgraphCtx);
-};
-/// @}
-
-} // end namespace anki

+ 1 - 1
AnKi/Shaders/ImportanceSampling.glsl

@@ -74,4 +74,4 @@ U32 hashPcg(U32 u)
 	const U32 state = u * 747796405u + 2891336453u;
 	const U32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
 	return (word >> 22u) ^ word;
-}
+}

+ 7 - 1
AnKi/Shaders/Include/ClusteredShadingTypes.h

@@ -182,7 +182,13 @@ struct CommonMatrices
 	/// using the current frame's jitter matrix.
 	Mat4 m_reprojection ANKI_CPP_CODE(= Mat4::getIdentity());
 
-	Vec4 m_unprojectionParameters ANKI_CPP_CODE(= Vec4(0.0f)); ///< To unproject to view space. Jitter not considered.
+	/// To unproject to view space. Jitter not considered.
+	/// @code
+	/// const F32 z = m_unprojectionParameters.z / (m_unprojectionParameters.w + depth);
+	/// const Vec2 xy = ndc * m_unprojectionParameters.xy * z;
+	/// pos = Vec3(xy, z);
+	/// @endcode
+	Vec4 m_unprojectionParameters ANKI_CPP_CODE(= Vec4(0.0f));
 };
 const U32 _ANKI_SIZEOF_CommonMatrices =
 	12u * ANKI_SIZEOF(Mat4) + ANKI_SIZEOF(Vec4) + ANKI_SIZEOF(Mat3) + ANKI_SIZEOF(F32) * 3u;

+ 9 - 6
AnKi/Shaders/Include/IndirectDiffuseTypes.h

@@ -11,11 +11,15 @@ ANKI_BEGIN_NAMESPACE
 
 struct IndirectDiffuseUniforms
 {
-	UVec2 m_depthBufferSize;
 	UVec2 m_viewportSize;
 	Vec2 m_viewportSizef;
-	U32 m_maxSteps;
-	U32 m_stepIncrement;
+	Vec4 m_projectionMat;
+	F32 m_radius; ///< In meters.
+	U32 m_sampleCount;
+	F32 m_sampleCountf;
+	F32 m_ssaoBias;
+	F32 m_ssaoStrength;
+	F32 m_padding[3u];
 };
 
 struct IndirectDiffuseDenoiseUniforms
@@ -23,9 +27,8 @@ struct IndirectDiffuseDenoiseUniforms
 	Mat4 m_invertedViewProjectionJitterMat;
 	UVec2 m_viewportSize;
 	Vec2 m_viewportSizef;
-	F32 m_minSampleCount;
-	F32 m_maxSampleCount;
-	F32 m_padding[2u];
+	F32 m_sampleCountDiv2;
+	F32 m_padding[3u];
 };
 
 ANKI_END_NAMESPACE

+ 88 - 142
AnKi/Shaders/IndirectDiffuse.ankiprog

@@ -5,16 +5,15 @@
 
 // Does SSGI and GI probe sampling
 
-#define RECALCULATE_NORMAL false
-#define REJECT_FAR_FROM_HITPOINT true
-#define REJECT_BACKFACING false
+ANKI_SPECIALIZATION_CONSTANT_U32(SAMPLE_COUNT, 6u);
+
 #define ENABLE_SSGI true
 #define ENABLE_PROBES true
-#define REMOVE_FIREFLIES true
-#define SSGI_PROBE_COMBINE(ssgiColor, probeColor) max((ssgiColor), (probeColor))
+#define REMOVE_FIREFLIES false
+#define REPROJECT_LIGHTBUFFER false
+#define SSGI_PROBE_COMBINE(ssgiColor, probeColor) ((ssgiColor) + (probeColor))
 
 #pragma anki start comp
-#include <AnKi/Shaders/SsRaymarching.glsl>
 #include <AnKi/Shaders/Functions.glsl>
 #include <AnKi/Shaders/PackFunctions.glsl>
 #include <AnKi/Shaders/ImportanceSampling.glsl>
@@ -31,23 +30,26 @@ layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y) in;
 #include <AnKi/Shaders/ClusteredShadingCommon.glsl>
 
 layout(set = 0, binding = 4) writeonly uniform image2D u_outImage;
-layout(set = 0, binding = 5) writeonly uniform image2D u_momentsAndHistoryLengthImage;
-
-layout(set = 0, binding = 6) uniform sampler u_trilinearClampSampler;
-layout(set = 0, binding = 7) uniform texture2D u_gbufferRt2;
-layout(set = 0, binding = 8) uniform texture2D u_depthRt;
-layout(set = 0, binding = 9) uniform texture2D u_lightBufferRt;
-layout(set = 0, binding = 10) uniform texture2D u_historyTex;
-layout(set = 0, binding = 11) uniform texture2D u_motionVectorsTex;
-layout(set = 0, binding = 12) uniform texture2D u_motionVectorsRejectionTex;
-layout(set = 0, binding = 13) uniform texture2D u_prevMomentsAndHistoryLengthTex;
-layout(set = 0, binding = 14) uniform texture2D u_ssaoTex;
+
+layout(set = 0, binding = 5) uniform sampler u_linearAnyClampSampler;
+layout(set = 0, binding = 6) uniform texture2D u_gbufferRt2;
+layout(set = 0, binding = 7) uniform texture2D u_depthRt;
+layout(set = 0, binding = 8) uniform texture2D u_lightBufferRt;
+layout(set = 0, binding = 9) uniform texture2D u_historyTex;
+layout(set = 0, binding = 10) uniform texture2D u_motionVectorsTex;
+layout(set = 0, binding = 11) uniform texture2D u_motionVectorsRejectionTex;
 
 layout(push_constant, std430) uniform b_pc
 {
 	IndirectDiffuseUniforms u_unis;
 };
 
+Vec4 cheapProject(Vec4 point)
+{
+	return projectPerspective(point, u_unis.m_projectionMat.x, u_unis.m_projectionMat.y, u_unis.m_projectionMat.z,
+							  u_unis.m_projectionMat.w);
+}
+
 void main()
 {
 	const UVec2 fixedGlobalInvocationId = min(gl_GlobalInvocationID.xy, u_unis.m_viewportSize);
@@ -56,104 +58,78 @@ void main()
 	const Vec2 ndc = UV_TO_NDC(uv);
 
 	// Get normal
-	const Vec3 worldNormal = readNormalFromGBuffer(u_gbufferRt2, u_trilinearClampSampler, uv);
+	const Vec3 worldNormal = readNormalFromGBuffer(u_gbufferRt2, u_linearAnyClampSampler, uv);
 	const Vec3 viewNormal = u_clusteredShading.m_matrices.m_viewRotation * worldNormal;
 
-	// Get depth
-	const F32 depth = textureLod(u_depthRt, u_trilinearClampSampler, uv, 0.0).r;
+	// Get origin
+	const F32 depth = textureLod(u_depthRt, u_linearAnyClampSampler, uv, 0.0).r;
+	Vec4 v4 = u_clusteredShading.m_matrices.m_invertedViewProjectionJitter * Vec4(ndc, depth, 1.0);
+	const Vec3 worldPos = v4.xyz / v4.w;
+	v4 = u_clusteredShading.m_matrices.m_invertedProjectionJitter * Vec4(ndc, depth, 1.0);
+	const Vec3 viewPos = v4.xyz / v4.w;
 
-	// Compute view pos
-	const Vec4 viewPos4 = u_clusteredShading.m_matrices.m_invertedProjectionJitter * Vec4(ndc, depth, 1.0);
-	const Vec3 viewPos = viewPos4.xyz / viewPos4.w;
-
-	// Get a random point inside the hemisphere. Use hemisphereSampleCos to avoid perpendicular vecs to viewNormal
-	const UVec2 random = rand3DPCG16(UVec3(fixedGlobalInvocationId, u_clusteredShading.m_frame)).xy;
-	Vec2 randomCircle = hammersleyRandom16(0u, 0xFFFFu, random);
-	randomCircle.x *= 0.9; // Reduce the cone angle a bit to avoid self-collisions
-	randomCircle.x = pow(randomCircle.x, 4.0); // Get more samples closer to the normal
-	const Vec3 randomHemisphere = rotationFromDirection(viewNormal) * hemisphereSampleCos(randomCircle);
-
-	// Trace
-	Vec3 hitPoint;
-	F32 hitAttenuation;
+	// SSGI
+	Vec3 outColor = Vec3(0.0);
+	F32 ssao = 0.0;
 	if(ENABLE_SSGI)
 	{
-		const U32 lod = 0u;
-		const F32 minStepf = 4.0;
-		const F32 noise = F32(random.x) * (1.0 / 65536.0);
-		const U32 initialStep = U32(mix(minStepf, F32(u_unis.m_stepIncrement), noise));
-		raymarchGroundTruth(viewPos, randomHemisphere, uv, depth, u_clusteredShading.m_matrices.m_projectionJitter,
-							u_unis.m_maxSteps, u_depthRt, u_trilinearClampSampler, F32(lod), u_unis.m_depthBufferSize,
-							u_unis.m_stepIncrement, initialStep, hitPoint, hitAttenuation);
-	}
-	else
-	{
-		hitAttenuation = 0.0;
-	}
-
-	// Reject backfacing
-	ANKI_BRANCH if(REJECT_BACKFACING && hitAttenuation > 0.0)
-	{
-		const Vec3 hitNormal = u_clusteredShading.m_matrices.m_viewRotation
-							   * readNormalFromGBuffer(u_gbufferRt2, u_trilinearClampSampler, hitPoint.xy);
-		F32 backFaceAttenuation;
-		rejectBackFaces(randomHemisphere, hitNormal, backFaceAttenuation);
-
-		hitAttenuation *= backFaceAttenuation;
-	}
+		// Find the projected radius
+		const Vec3 sphereLimit = viewPos + Vec3(u_unis.m_radius, 0.0, 0.0);
+		const Vec4 projSphereLimit = cheapProject(Vec4(sphereLimit, 1.0));
+		const Vec2 projSphereLimit2 = projSphereLimit.xy / projSphereLimit.w;
+		const F32 projRadius = length(projSphereLimit2 - ndc);
+
+		// Loop to compute
+		const UVec2 random = rand3DPCG16(UVec3(gl_GlobalInvocationID.xy, u_clusteredShading.m_frame)).xy;
+		for(U32 i = 0u; i < u_unis.m_sampleCount; ++i)
+		{
+			const Vec2 point = UV_TO_NDC(hammersleyRandom16(i, u_unis.m_sampleCount, random));
+			const Vec2 finalDiskPoint = ndc + point * projRadius;
+
+			// Do a cheap unproject in view space
+			const F32 d = textureLod(u_depthRt, u_linearAnyClampSampler, NDC_TO_UV(finalDiskPoint), 0.0).r;
+			const F32 z = u_clusteredShading.m_matrices.m_unprojectionParameters.z
+						  / (u_clusteredShading.m_matrices.m_unprojectionParameters.w + d);
+			const Vec2 xy = finalDiskPoint * u_clusteredShading.m_matrices.m_unprojectionParameters.xy * z;
+			const Vec3 s = Vec3(xy, z);
+
+			// Compute factor
+			const Vec3 dir = s - viewPos;
+			const F32 len = length(dir);
+			const Vec3 n = dir / len;
+			const F32 NoL = max(0.0, dot(viewNormal, n));
+			// const F32 distFactor = 1.0 - sin(min(1.0, len / u_unis.m_radius) * PI / 2.0);
+			const F32 distFactor = 1.0 - min(1.0, len / u_unis.m_radius);
+
+			// Compute the UV for sampling the pyramid
+			const Vec2 crntFrameUv = NDC_TO_UV(finalDiskPoint);
+			Vec2 lastFrameUv;
+			if(REPROJECT_LIGHTBUFFER)
+			{
+				lastFrameUv =
+					crntFrameUv + textureLod(u_motionVectorsTex, u_linearAnyClampSampler, crntFrameUv, 0.0).xy;
+			}
+			else
+			{
+				lastFrameUv = crntFrameUv;
+			}
 
-	// Reject far from hit point
-	ANKI_BRANCH if(REJECT_FAR_FROM_HITPOINT && hitAttenuation > 0.0)
-	{
-		const F32 depth = textureLod(u_depthRt, u_trilinearClampSampler, hitPoint.xy, 0.0).r;
-		Vec4 viewPos4 =
-			u_clusteredShading.m_matrices.m_invertedProjectionJitter * Vec4(UV_TO_NDC(hitPoint.xy), depth, 1.0);
-		const F32 actualZ = viewPos4.z / viewPos4.w;
-
-		viewPos4 =
-			u_clusteredShading.m_matrices.m_invertedProjectionJitter * Vec4(UV_TO_NDC(hitPoint.xy), hitPoint.z, 1.0);
-		const F32 hitZ = viewPos4.z / viewPos4.w;
-
-		const F32 rejectionMeters = 1.0;
-		const F32 diff = abs(actualZ - hitZ);
-		const F32 distAttenuation = (diff < rejectionMeters) ? 1.0 : 0.0;
-		hitAttenuation *= distAttenuation;
-	}
+			// Append color
+			const F32 w = distFactor * NoL;
+			const Vec3 c = textureLod(u_lightBufferRt, u_linearAnyClampSampler, lastFrameUv, 100.0).xyz;
+			outColor += c * w;
 
-	// Read the light buffer
-	Vec3 outColor = Vec3(0.0);
-	ANKI_BRANCH if(hitAttenuation > 0.0)
-	{
-		// Reproject the UV because you are reading the previous frame
-		const Vec4 v4 = u_clusteredShading.m_matrices.m_reprojection * Vec4(UV_TO_NDC(hitPoint.xy), hitPoint.z, 1.0);
-		hitPoint.xy = NDC_TO_UV(v4.xy / v4.w);
-
-		// Read the light buffer
-		outColor = textureLod(u_lightBufferRt, u_trilinearClampSampler, hitPoint.xy, 2.0).rgb;
-		outColor = clamp(outColor, 0.0, FLT_MAX); // Fix the value just in case
-		outColor *= hitAttenuation;
-
-		// Compute a new normal based on the new hit point
-		Vec3 newViewNormal;
-		if(RECALCULATE_NORMAL)
-		{
-			const F32 depth = textureLod(u_depthRt, u_trilinearClampSampler, hitPoint.xy, 0.0).r;
-			const Vec4 viewPos4 =
-				u_clusteredShading.m_matrices.m_invertedProjectionJitter * Vec4(UV_TO_NDC(hitPoint.xy), depth, 1.0);
-			const Vec3 hitViewPos = viewPos4.xyz / viewPos4.w;
-			newViewNormal = normalize(hitViewPos - viewPos);
-		}
-		else
-		{
-			newViewNormal = viewNormal;
+			// Compute SSAO as well
+			ssao += max(dot(viewNormal, dir) + u_unis.m_ssaoBias, EPSILON) / max(len * len, EPSILON);
 		}
 
-		// Modulate
-		const F32 NoL = max(0.0, dot(randomHemisphere, newViewNormal));
-		outColor *= NoL;
-		outColor *= 2.0 * PI;
+		const F32 scount = 1.0 / u_unis.m_sampleCountf;
+		outColor *= scount * 2.0 * PI;
+		ssao *= scount;
 	}
 
+	ssao = min(1.0, 1.0 - ssao * u_unis.m_ssaoStrength);
+
 	if(ENABLE_PROBES)
 	{
 		// Sample probes
@@ -175,7 +151,7 @@ void main()
 
 			// Sample
 			probeColor = sampleGlobalIllumination(worldPos, worldNormal, probe, u_globalIlluminationTextures,
-												  u_trilinearClampSampler);
+												  u_linearAnyClampSampler);
 		}
 		else
 		{
@@ -198,7 +174,7 @@ void main()
 
 				// Sample
 				const Vec3 c = sampleGlobalIllumination(worldPos, worldNormal, probe, u_globalIlluminationTextures,
-														u_trilinearClampSampler);
+														u_linearAnyClampSampler);
 				probeColor += c * blendWeight;
 			}
 
@@ -219,53 +195,23 @@ void main()
 	}
 
 	// Apply SSAO
-	outColor *= textureLod(u_ssaoTex, u_trilinearClampSampler, uv, 0.0).x;
-
-	// Compute history length
-	const Vec2 historyUv = uv + textureLod(u_motionVectorsTex, u_trilinearClampSampler, uv, 0.0).xy;
-	const F32 historyRejectionFactor = textureLod(u_motionVectorsRejectionTex, u_trilinearClampSampler, uv, 0.0).x;
-	const Vec3 prevMomentsAndHistoryLength =
-		textureLod(u_prevMomentsAndHistoryLengthTex, u_trilinearClampSampler, historyUv, 0.0).xyz;
-	F32 historyLength;
-	if(historyRejectionFactor >= 0.5)
-	{
-		// Rejection factor too high, reset the temporal history
-		historyLength = 0.0;
-	}
-	else
-	{
-		// Sample seems stable, increment its temporal history
-		historyLength = min(prevMomentsAndHistoryLength.z + 1.0, 128.0);
-	}
+	outColor *= ssao;
 
 	// Blend color with history
 	{
-		// Compute blend fractor. Use nearest sampler because it's an integer texture
+		const Vec2 historyUv = uv + textureLod(u_motionVectorsTex, u_linearAnyClampSampler, uv, 0.0).xy;
+		const F32 historyRejectionFactor = textureLod(u_motionVectorsRejectionTex, u_linearAnyClampSampler, uv, 0.0).x;
+
 		const F32 lowestBlendFactor = 0.1;
-		const F32 stableFrames = 4.0;
-		const F32 lerp = min(1.0, (historyLength + 1.0) / stableFrames);
-		const F32 blendFactor = mix(1.0, lowestBlendFactor, lerp);
+		const F32 blendFactor = mix(lowestBlendFactor, 1.0, historyRejectionFactor);
 
 		// Blend with history
-		const Vec3 history = textureLod(u_historyTex, u_trilinearClampSampler, historyUv, 0.0).rgb;
+		const Vec3 history = textureLod(u_historyTex, u_linearAnyClampSampler, historyUv, 0.0).rgb;
 		outColor = mix(history, outColor, blendFactor);
 	}
 
 	// Store color
 	imageStore(u_outImage, IVec2(fixedGlobalInvocationId), Vec4(outColor, 1.0));
-
-	// Compute the moments that will give temporal variance
-	Vec2 moments;
-	moments.x = computeLuminance(outColor);
-	moments.y = moments.x * moments.x;
-
-	// Blend the moments with history
-	F32 momentsBlendFactor = 0.2;
-	momentsBlendFactor = mix(momentsBlendFactor, 1.0, historyRejectionFactor);
-	moments = mix(prevMomentsAndHistoryLength.xy, moments, momentsBlendFactor);
-
-	// Store the moments + history len
-	imageStore(u_momentsAndHistoryLengthImage, IVec2(fixedGlobalInvocationId), Vec4(moments, historyLength, 0.0));
 }
 
 #pragma anki end

+ 4 - 59
AnKi/Shaders/IndirectDiffuseDenoise.ankiprog

@@ -19,8 +19,7 @@ layout(set = 0, binding = 0) uniform sampler u_linearAnyClampSampler;
 layout(set = 0, binding = 1) uniform texture2D u_toDenoiseTex;
 layout(set = 0, binding = 2) uniform texture2D u_depthTex;
 layout(set = 0, binding = 3) uniform texture2D u_gbuffer2Tex;
-layout(set = 0, binding = 4) uniform texture2D u_momentsAndHistoryLengthTex;
-layout(set = 0, binding = 5) writeonly uniform image2D u_outImg;
+layout(set = 0, binding = 4) writeonly uniform image2D u_outImg;
 
 layout(push_constant, std430, row_major) uniform b_pc
 {
@@ -34,29 +33,6 @@ Vec3 unproject(Vec2 ndc, F32 depth)
 	return worldPos;
 }
 
-F32 computeSpatialVariance(Vec2 uv)
-{
-	const F32 radius = 2.0;
-	const F32 step = 1.5;
-	const Vec2 texelSize = 1.0 / u_unis.m_viewportSizef;
-	Vec2 sumMoments = Vec2(0.0);
-
-	for(F32 i = -radius * step; i <= radius * step; i += step)
-	{
-		Vec2 newUv = uv;
-#if BLUR_ORIENTATION == 0
-		newUv.x += i * texelSize.x;
-#else
-		newUv.y += i * texelSize.y;
-#endif
-		sumMoments += textureLod(u_momentsAndHistoryLengthTex, u_linearAnyClampSampler, newUv, 0.0).xy;
-	}
-
-	sumMoments *= 1.0 / (radius * 2.0 + 1.0);
-
-	return abs(sumMoments.y - sumMoments.x * sumMoments.x);
-}
-
 void main()
 {
 	if(skipOutOfBoundsInvocations(WORKGROUP_SIZE, u_unis.m_viewportSize))
@@ -77,44 +53,11 @@ void main()
 	const Vec3 positionCenter = unproject(UV_TO_NDC(uv), depthCenter);
 	const Vec3 normalCenter = readNormalFromGBuffer(u_gbuffer2Tex, u_linearAnyClampSampler, uv);
 
-	// Decide the amount of blurring
-	const F32 historyLength = textureLod(u_momentsAndHistoryLengthTex, u_linearAnyClampSampler, uv, 0.0).z;
-
-	const F32 stableFrameCount = 4.0;
-	F32 sampleCount;
-	if(historyLength < stableFrameCount)
-	{
-		// Worst case
-		sampleCount = u_unis.m_maxSampleCount;
-	}
-	else
-	{
-		const F32 varianceCenter = computeSpatialVariance(uv);
-
-		if(historyLength > stableFrameCount && varianceCenter < 0.01)
-		{
-			// Best case
-			sampleCount = u_unis.m_minSampleCount;
-		}
-		else
-		{
-			// Every other case
-
-			F32 blur = varianceCenter * 10.0;
-			blur = min(1.0, blur);
-
-			sampleCount = mix(u_unis.m_minSampleCount, u_unis.m_maxSampleCount, blur);
-		}
-	}
-
-	sampleCount = sampleCount / 2.0;
-	sampleCount = floor(sampleCount);
-
 	// Sample
 	F32 weight = EPSILON;
 	Vec3 color = Vec3(0.0);
 
-	for(F32 i = -sampleCount; i <= sampleCount; i += 1.0)
+	for(F32 i = -u_unis.m_sampleCountDiv2; i <= u_unis.m_sampleCountDiv2; i += 1.0)
 	{
 		const Vec2 texelSize = 1.0 / u_unis.m_viewportSizef;
 #if BLUR_ORIENTATION == 0
@@ -138,6 +81,8 @@ void main()
 	// Normalize and store
 	color /= weight;
 	imageStore(u_outImg, IVec2(gl_GlobalInvocationID.xy), Vec4(color, 0.0));
+	// imageStore(u_outImg, IVec2(gl_GlobalInvocationID.xy), textureLod(u_toDenoiseTex, u_linearAnyClampSampler, uv,
+	// 0.0));
 }
 
 #pragma anki end

+ 0 - 12
AnKi/Shaders/Ssao.ankiprog

@@ -1,12 +0,0 @@
-// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma anki start vert
-#include <AnKi/Shaders/QuadVert.glsl>
-#pragma anki end
-
-#pragma anki start frag
-#include <AnKi/Shaders/Ssao.glsl>
-#pragma anki end

+ 0 - 226
AnKi/Shaders/Ssao.glsl

@@ -1,226 +0,0 @@
-// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-// Contains the complete code for a SSAO pass. It requires some variables to be defined before this file is included.
-
-#pragma anki mutator USE_NORMAL 0 1
-#pragma anki mutator SOFT_BLUR 0 1
-
-ANKI_SPECIALIZATION_CONSTANT_U32(NOISE_MAP_SIZE, 0u);
-ANKI_SPECIALIZATION_CONSTANT_UVEC2(FB_SIZE, 1u);
-ANKI_SPECIALIZATION_CONSTANT_F32(RADIUS, 3u);
-ANKI_SPECIALIZATION_CONSTANT_F32(BIAS, 4u);
-ANKI_SPECIALIZATION_CONSTANT_F32(STRENGTH, 5u);
-ANKI_SPECIALIZATION_CONSTANT_U32(SAMPLE_COUNT, 6u);
-
-#pragma once
-
-#include <AnKi/Shaders/Common.glsl>
-#include <AnKi/Shaders/PackFunctions.glsl>
-#include <AnKi/Shaders/Functions.glsl>
-#define KERNEL_SIZE 3
-#include <AnKi/Shaders/GaussianBlurCommon.glsl>
-
-#if defined(ANKI_FRAGMENT_SHADER)
-#	define USE_COMPUTE 0
-#else
-#	define USE_COMPUTE 1
-const UVec2 WORKGROUP_SIZE = UVec2(16, 16);
-#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 F32 out_color;
-#else
-layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
-
-layout(set = 0, binding = 5) writeonly uniform image2D out_img;
-#endif
-
-layout(push_constant, std140, row_major) uniform b_pc
-{
-	Vec4 u_unprojectionParams;
-	Vec4 u_projectionMat;
-	Mat3 u_viewRotMat;
-};
-
-layout(set = 0, binding = 0) uniform sampler u_linearAnyClampSampler;
-layout(set = 0, binding = 1) uniform sampler u_trilinearRepeatSampler;
-
-layout(set = 0, binding = 2) uniform texture2D u_depthRt;
-layout(set = 0, binding = 3) uniform texture2D u_noiseMap;
-#if USE_NORMAL
-layout(set = 0, binding = 4) uniform texture2D u_msRt;
-#endif
-
-// To compute the normals we need some extra work on compute
-#define COMPLEX_NORMALS (!USE_NORMAL && USE_COMPUTE)
-#if DO_SOFT_BLUR
-shared Vec3 s_scratch[WORKGROUP_SIZE.y][WORKGROUP_SIZE.x];
-#endif
-
-#if USE_NORMAL
-// Get normal
-Vec3 readNormal(Vec2 uv)
-{
-	Vec3 normal = readNormalFromGBuffer(u_msRt, u_linearAnyClampSampler, uv);
-	normal = u_viewRotMat * normal;
-	return normal;
-}
-#endif
-
-// Read the noise tex
-Vec3 readRandom(Vec2 uv, F32 layer)
-{
-	const Vec2 tmp = Vec2(F32(FB_SIZE.x) / F32(NOISE_MAP_SIZE), F32(FB_SIZE.y) / F32(NOISE_MAP_SIZE));
-	const Vec3 r = textureLod(u_noiseMap, u_trilinearRepeatSampler, tmp * uv, 0.0).rgb;
-	return r;
-}
-
-Vec4 project(Vec4 point)
-{
-	return projectPerspective(point, u_projectionMat.x, u_projectionMat.y, u_projectionMat.z, u_projectionMat.w);
-}
-
-Vec3 unproject(Vec2 ndc, F32 depth)
-{
-	const F32 z = u_unprojectionParams.z / (u_unprojectionParams.w + depth);
-	const Vec2 xy = ndc * u_unprojectionParams.xy * z;
-	return Vec3(xy, z);
-}
-
-F32 smallerDelta(F32 left, F32 mid, F32 right)
-{
-	const F32 a = mid - left;
-	const F32 b = right - mid;
-
-	return (abs(a) < abs(b)) ? a : b;
-}
-
-// Compute the normal depending on some defines
-Vec3 computeNormal(Vec2 uv, Vec3 origin, F32 depth)
-{
-#if USE_NORMAL
-	const Vec3 normal = readNormal(uv);
-#elif !COMPLEX_NORMALS
-	const Vec3 normal = normalize(cross(dFdx(origin), dFdy(origin)));
-#else
-	const F32 depthLeft = textureLodOffset(sampler2D(u_depthRt, u_linearAnyClampSampler), uv, 0.0, ivec2(-2, 0)).r;
-	const F32 depthRight = textureLodOffset(sampler2D(u_depthRt, u_linearAnyClampSampler), uv, 0.0, ivec2(2, 0)).r;
-	const F32 depthTop = textureLodOffset(sampler2D(u_depthRt, u_linearAnyClampSampler), uv, 0.0, ivec2(0, 2)).r;
-	const F32 depthBottom = textureLodOffset(sampler2D(u_depthRt, u_linearAnyClampSampler), uv, 0.0, ivec2(0, -2)).r;
-
-	const F32 ddx = smallerDelta(depthLeft, depth, depthRight);
-	const F32 ddy = smallerDelta(depthBottom, depth, depthTop);
-
-	const Vec2 ndc = UV_TO_NDC(uv);
-	const Vec2 TEXEL_SIZE = 1.0 / Vec2(FB_SIZE);
-	const Vec2 NDC_TEXEL_SIZE = 2.0 * TEXEL_SIZE;
-	const Vec3 right = unproject(ndc + Vec2(NDC_TEXEL_SIZE.x, 0.0), depth + ddx);
-	const Vec3 top = unproject(ndc + Vec2(0.0, NDC_TEXEL_SIZE.y), depth + ddy);
-
-	Vec3 normal = cross(origin - top, right - origin);
-	normal = normalize(normal);
-#endif
-
-	return normal;
-}
-
-void main(void)
-{
-#if USE_COMPUTE
-	const UVec2 globalInvocationID = min(gl_GlobalInvocationID.xy, FB_SIZE - 1u);
-	const Vec2 uv = (Vec2(globalInvocationID) + 0.5) / Vec2(FB_SIZE);
-#else
-	const Vec2 uv = in_uv;
-#endif
-
-	const Vec2 ndc = UV_TO_NDC(uv);
-
-	// Compute origin
-	const F32 depth = textureLod(u_depthRt, u_linearAnyClampSampler, uv, 0.0).r;
-	const Vec3 origin = unproject(ndc, depth);
-
-	// Get normal
-	const Vec3 normal = computeNormal(uv, origin, depth);
-
-	// Find the projected radius
-	const Vec3 sphereLimit = origin + Vec3(RADIUS, 0.0, 0.0);
-	const Vec4 projSphereLimit = project(Vec4(sphereLimit, 1.0));
-	const Vec2 projSphereLimit2 = projSphereLimit.xy / projSphereLimit.w;
-	const F32 projRadius = length(projSphereLimit2 - ndc);
-
-	// Loop to compute
-	const F32 randFactor = readRandom(uv, 0.0).r;
-	F32 ssao = 0.0;
-	const F32 SAMPLE_COUNTF = F32(SAMPLE_COUNT);
-	ANKI_UNROLL for(U32 i = 0u; i < SAMPLE_COUNT; ++i)
-	{
-		// Compute disk. Basically calculate a point in a spiral. See how it looks here
-		// https://shadertoy.com/view/Md3fDr
-		const F32 fi = F32(i);
-		const F32 TURNS = F32(SAMPLE_COUNT) / 2.0; // Calculate the number of the spiral turns
-		const F32 ANG = (PI * 2.0 * TURNS) / (SAMPLE_COUNTF - 1.0); // The angle distance between samples
-		F32 ang = ANG * fi;
-		ang += randFactor * PI; // Turn the angle a bit
-
-		F32 radius = (1.0 / SAMPLE_COUNTF) * (fi + 1.0);
-		radius = sqrt(radius); // Move the points a bit away from the center of the spiral
-
-		const Vec2 point = Vec2(cos(ang), sin(ang)) * radius; // In NDC
-
-		const Vec2 finalDiskPoint = ndc + point * projRadius;
-
-		// Compute factor
-		const Vec3 s =
-			unproject(finalDiskPoint, textureLod(u_depthRt, u_linearAnyClampSampler, NDC_TO_UV(finalDiskPoint), 0.0).r);
-		const Vec3 u = s - origin;
-		ssao += max(dot(normal, u) + BIAS, EPSILON) / max(dot(u, u), EPSILON);
-	}
-
-	ssao *= (1.0 / F32(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
-	const U32 left = (gl_LocalInvocationID.x != 0u) ? (gl_LocalInvocationID.x - 1u) : 0u;
-	const U32 right =
-		(gl_LocalInvocationID.x != WORKGROUP_SIZE.x - 1u) ? (gl_LocalInvocationID.x + 1u) : (WORKGROUP_SIZE.x - 1u);
-	const U32 bottom = (gl_LocalInvocationID.y != 0u) ? (gl_LocalInvocationID.y - 1u) : 0u;
-	const U32 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 += s_scratch[gl_LocalInvocationID.y][left].x;
-	ssao += s_scratch[gl_LocalInvocationID.y][right].x;
-	ssao += s_scratch[bottom][gl_LocalInvocationID.x].x;
-	ssao += s_scratch[top][gl_LocalInvocationID.x].x;
-
-	ssao += s_scratch[bottom][left].x;
-	ssao += s_scratch[bottom][right].x;
-	ssao += s_scratch[top][left].x;
-	ssao += s_scratch[top][right].x;
-
-	ssao *= (1.0 / 9.0);
-#endif
-
-	// Store the result
-#if USE_COMPUTE
-	imageStore(out_img, IVec2(globalInvocationID), Vec4(ssao));
-#else
-	out_color = ssao;
-#endif
-}

+ 0 - 8
AnKi/Shaders/SsaoCompute.ankiprog

@@ -1,8 +0,0 @@
-// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma anki start comp
-#include <AnKi/Shaders/Ssao.glsl>
-#pragma anki end

+ 2 - 1
Sandbox/Main.cpp

@@ -227,7 +227,8 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 
 	if(in.getKey(KeyCode::U) == 1)
 	{
-		renderer.setCurrentDebugRenderTarget((renderer.getCurrentDebugRenderTarget() == "SSGI") ? "" : "SSGI");
+		renderer.setCurrentDebugRenderTarget(
+			(renderer.getCurrentDebugRenderTarget() == "IndirectDiffuse") ? "" : "IndirectDiffuse");
 	}
 
 	if(in.getKey(KeyCode::I) == 1)