Browse Source

Add probe validity checks

Panagiotis Christopoulos Charitos 7 tháng trước cách đây
mục cha
commit
50ba23fdb5

+ 39 - 6
AnKi/Renderer/IndirectDiffuseClipmaps.cpp

@@ -45,6 +45,15 @@ Error IndirectDiffuseClipmaps::init()
 		}
 	}
 
+	for(U32 i = 0; i < kIndirectDiffuseClipmapCount; ++i)
+	{
+		m_probeValidityRtDescs[i] = getRenderer().create2DRenderTargetDescription(
+			m_clipmapInfo[i].m_probeCounts.x(), m_clipmapInfo[i].m_probeCounts.z(), Format::kR8_Unorm, generateTempPassName("Probe validity #%u", i));
+		m_probeValidityRtDescs[i].m_depth = m_clipmapInfo[i].m_probeCounts.y();
+		m_probeValidityRtDescs[i].m_type = TextureType::k3D;
+		m_probeValidityRtDescs[i].bake();
+	}
+
 	// Create the lighting result texture
 	m_radianceDesc = getRenderer().create2DRenderTargetDescription(probesPerClipmap, kRaysPerProbePerFrame, Format::kB10G11R11_Ufloat_Pack32,
 																   "IndirectDiffuse light result");
@@ -140,6 +149,13 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 		}
 	}
 
+	Array<RenderTargetHandle, kIndirectDiffuseClipmapCount> probeValidityRts;
+	for(U32 i = 0; i < kIndirectDiffuseClipmapCount; ++i)
+	{
+		probeValidityRts[i] = rgraph.newRenderTarget(m_probeValidityRtDescs[i]);
+	}
+	m_runCtx.m_probeValidityRts = probeValidityRts;
+
 	// SBT build
 	BufferHandle sbtHandle;
 	BufferView sbtBuffer;
@@ -270,7 +286,7 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 		});
 	}
 
-	// Update caches
+	// Populate caches
 	{
 		const U32 clipmap = 0; // TODO
 
@@ -278,14 +294,17 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 
 		pass.newTextureDependency(radianceRt, TextureUsageBit::kSrvCompute);
 		pass.newTextureDependency(radianceVolumes[clipmap], TextureUsageBit::kUavCompute);
+		pass.newTextureDependency(probeValidityRts[clipmap], TextureUsageBit::kUavCompute);
 
-		pass.setWork([this, &ctx, clipmap, radianceRt, radianceVolume = radianceVolumes[clipmap]](RenderPassWorkContext& rgraphCtx) {
+		pass.setWork([this, &ctx, clipmap, radianceRt, radianceVolume = radianceVolumes[clipmap],
+					  validityVolume = probeValidityRts[clipmap]](RenderPassWorkContext& rgraphCtx) {
 			CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
 
 			cmdb.bindShaderProgram(m_populateCachesGrProg.get());
 
 			rgraphCtx.bindSrv(0, 0, radianceRt);
 			rgraphCtx.bindUav(0, 0, radianceVolume);
+			rgraphCtx.bindUav(1, 0, validityVolume);
 			cmdb.bindConstantBuffer(0, 0, ctx.m_globalRenderingConstantsBuffer);
 
 			const UVec4 consts(clipmap, g_indirectDiffuseClipmapRadianceCacheProbeSize, 0, 0);
@@ -323,6 +342,7 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 		});
 	}
 
+	// Test
 	{
 		NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("IndirectDiffuseClipmaps test");
 
@@ -331,10 +351,11 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 		for(U32 i = 0; i < kIndirectDiffuseClipmapCount; ++i)
 		{
 			pass.newTextureDependency(irradianceVolumes[i], TextureUsageBit::kSrvCompute);
+			pass.newTextureDependency(probeValidityRts[i], TextureUsageBit::kSrvCompute);
 		}
 		pass.newTextureDependency(m_runCtx.m_tmpRt, TextureUsageBit::kUavCompute);
 
-		pass.setWork([this, &ctx, irradianceVolumes](RenderPassWorkContext& rgraphCtx) {
+		pass.setWork([this, &ctx, irradianceVolumes, probeValidityRts](RenderPassWorkContext& rgraphCtx) {
 			CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
 
 			cmdb.bindShaderProgram(m_tmpVisGrProg.get());
@@ -348,6 +369,11 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 				rgraphCtx.bindSrv(3 + i, 0, irradianceVolumes[i]);
 			}
 
+			for(U32 i = 0; i < kIndirectDiffuseClipmapCount; ++i)
+			{
+				rgraphCtx.bindSrv(3 + kIndirectDiffuseClipmapCount + i, 0, probeValidityRts[i]);
+			}
+
 			rgraphCtx.bindUav(0, 0, m_runCtx.m_tmpRt);
 
 			cmdb.bindConstantBuffer(0, 0, ctx.m_globalRenderingConstantsBuffer);
@@ -359,8 +385,12 @@ void IndirectDiffuseClipmaps::populateRenderGraph(RenderingContext& ctx)
 	}
 }
 
-void IndirectDiffuseClipmaps::drawDebugProbes(const RenderingContext& ctx, CommandBuffer& cmdb) const
+void IndirectDiffuseClipmaps::drawDebugProbes(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx) const
 {
+	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+
+	const U32 clipmap = 0;
+
 	cmdb.bindShaderProgram(m_visProbesGrProg.get());
 
 	const Bool visualizeIrradiance = true;
@@ -370,10 +400,13 @@ void IndirectDiffuseClipmaps::drawDebugProbes(const RenderingContext& ctx, Comma
 	cmdb.setFastConstants(&consts, sizeof(consts));
 
 	cmdb.bindConstantBuffer(0, 0, ctx.m_globalRenderingConstantsBuffer);
-	cmdb.bindSrv(0, 0, TextureView((visualizeIrradiance) ? m_irradianceVolumes[0].get() : m_radianceVolumes[0].get(), TextureSubresourceDesc::all()));
+	cmdb.bindSrv(
+		0, 0,
+		TextureView((visualizeIrradiance) ? m_irradianceVolumes[clipmap].get() : m_radianceVolumes[clipmap].get(), TextureSubresourceDesc::all()));
+	rgraphCtx.bindSrv(1, 0, m_runCtx.m_probeValidityRts[clipmap]);
 	cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearRepeat.get());
 
-	cmdb.draw(PrimitiveTopology::kTriangles, 36, m_clipmapInfo[0].m_probeCountsTotal);
+	cmdb.draw(PrimitiveTopology::kTriangles, 36, m_clipmapInfo[clipmap].m_probeCountsTotal);
 }
 
 } // end namespace anki

+ 4 - 1
AnKi/Renderer/IndirectDiffuseClipmaps.h

@@ -61,7 +61,7 @@ public:
 		return m_clipmapInfo;
 	}
 
-	void drawDebugProbes(const RenderingContext& ctx, CommandBuffer& cmdb) const;
+	void drawDebugProbes(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx) const;
 
 private:
 	static constexpr U32 kRaysPerProbePerFrame = 32;
@@ -82,6 +82,8 @@ private:
 	ShaderProgramPtr m_sbtBuildGrProg;
 	ShaderProgramPtr m_visProbesGrProg;
 
+	Array<RenderTargetDesc, kIndirectDiffuseClipmapCount> m_probeValidityRtDescs;
+
 	RenderTargetDesc m_tmpRtDesc; // TODO rm
 
 	ImageResourcePtr m_blueNoiseImg;
@@ -96,6 +98,7 @@ private:
 	{
 	public:
 		RenderTargetHandle m_tmpRt;
+		Array<RenderTargetHandle, kIndirectDiffuseClipmapCount> m_probeValidityRts;
 	} m_runCtx;
 };
 /// @}

+ 1 - 1
AnKi/Renderer/LightShading.cpp

@@ -212,7 +212,7 @@ void LightShading::run(const RenderingContext& ctx, RenderPassWorkContext& rgrap
 	// Debug stuff
 	if(g_visualizeGiProbesCVar && getRenderer().isIndirectDiffuseClipmapsEnabled())
 	{
-		getRenderer().getIndirectDiffuseClipmaps().drawDebugProbes(ctx, cmdb);
+		getRenderer().getIndirectDiffuseClipmaps().drawDebugProbes(ctx, rgraphCtx);
 	}
 
 	// Forward shading last

+ 44 - 5
AnKi/Shaders/IndirectDiffuseClipmaps.ankiprog

@@ -184,6 +184,7 @@ ANKI_FAST_CONSTANTS(Consts, g_consts)
 Texture2D<Vec4> g_lightResultTex : register(t0);
 
 RWTexture3D<Vec4> g_radianceVolume : register(u0);
+RWTexture3D<Vec4> g_probeValidiryVolume : register(u1);
 
 ConstantBuffer<GlobalRendererConstants> g_globalRendererConstants : register(b0);
 
@@ -197,8 +198,9 @@ struct Consts
 ANKI_FAST_CONSTANTS(Consts, g_consts)
 
 groupshared U32 g_octCoordValueSet[128]; // TODO
+groupshared U32 g_invalideRayCount;
 
-[NumThreads(RAYS_PER_PROBE_PER_FRAME, 1, 1)] void main(U32 svGroupIndex : SV_GroupIndex, UVec3 svGroupId : SV_GroupID)
+[NumThreads(RAYS_PER_PROBE_PER_FRAME, 1, 1)] void main(COMPUTE_ARGS)
 {
 	const Clipmap clipmap = g_globalRendererConstants.m_indirectDiffuseClipmaps[g_consts.m_clipmapIdx];
 
@@ -216,6 +218,11 @@ groupshared U32 g_octCoordValueSet[128]; // TODO
 		}
 	}
 
+	if(svGroupIndex == 0)
+	{
+		g_invalideRayCount = 0;
+	}
+
 	GroupMemoryBarrierWithGroupSync();
 
 	const U32 sampleIdx = svGroupIndex;
@@ -240,7 +247,12 @@ groupshared U32 g_octCoordValueSet[128]; // TODO
 	UVec3 volumeTexCoord = frac(probeWorldPos.xzy / clipmap.m_size.xzy) * clipmap.m_probeCounts.xzy;
 	volumeTexCoord = min(volumeTexCoord, clipmap.m_probeCounts.xzy - 1u);
 
-	const HVec3 radiance = TEX(g_lightResultTex, UVec2(probeIdx, sampleIdx));
+	HVec3 radiance = TEX(g_lightResultTex, UVec2(probeIdx, sampleIdx));
+	if(all(radiance == HVec3(1.0, 0.0, 1.0)))
+	{
+		InterlockedAdd(g_invalideRayCount, 1);
+		radiance = 0.0;
+	}
 
 	const Vec2 octUv = generateRandomUv(sampleIdx, U32(RAYS_PER_PROBE_PER_FRAME), g_globalRendererConstants.m_frame);
 	const UVec2 octCoord = min(octUv * g_consts.m_radianceProbeSize, g_consts.m_radianceProbeSize - 1);
@@ -295,6 +307,16 @@ groupshared U32 g_octCoordValueSet[128]; // TODO
 
 		TEX(g_radianceVolume, actualVolumeTexCoord).xyz = avgRadiance;
 	}
+
+	// Update probe validity
+	GroupMemoryBarrierWithGroupSync();
+	F16 valid = 1.0 - min(1.0, g_invalideRayCount / F32(RAYS_PER_PROBE_PER_FRAME / 4));
+	if(blendWithHistory)
+	{
+		const F16 prev = TEX(g_probeValidiryVolume, volumeTexCoord).x;
+		valid = lerp(prev, valid, 0.05);
+	}
+	TEX(g_probeValidiryVolume, volumeTexCoord).x = valid;
 }
 #endif
 
@@ -308,6 +330,7 @@ Texture2D<Vec4> g_gbufferRt2 : register(t1);
 Texture2D<Vec4> g_blueNoiseTex : register(t2);
 
 Texture3D<Vec4> g_clipmapVolumes[kIndirectDiffuseClipmapCount] : register(t3);
+Texture3D<Vec4> g_probeValidityVolumes[kIndirectDiffuseClipmapCount] : register(t6); // WARNING: Adjust if kIndirectDiffuseClipmapCount changed
 
 RWTexture2D<Vec4> g_outTex : register(u0);
 
@@ -391,7 +414,7 @@ SamplerState g_linearAnyRepeatSampler : register(s0);
 
 	// Some calculations are in the real volume size and some in some fake one that doesn't include the octahedron and the y and z are swapped
 
-	const Clipmap clipmap = g_globalRendererConstants.m_indirectDiffuseClipmaps[clipmapIdx];
+	const Clipmap clipmap = g_globalRendererConstants.m_indirectDiffuseClipmaps[clipmapIdx]; // TODO: Dynamically indexing cbuffer
 	const Vec3 probeSize = clipmap.m_size / clipmap.m_probeCounts;
 	const Vec3 fakeVolumeSize = clipmap.m_probeCounts; // Volume size without the octahedron
 
@@ -421,6 +444,12 @@ SamplerState g_linearAnyRepeatSampler : register(s0);
 		coords = select(coords >= 0.0, coords, fakeVolumeSize + coords);
 		coords = select(coords < fakeVolumeSize, coords, coords - fakeVolumeSize);
 
+		const Bool valid = g_probeValidityVolumes[NonUniformResourceIndex(clipmapIdx)][coords.xzy].x > 0.8;
+		if(!valid)
+		{
+			continue;
+		}
+
 		// Filtering weight
 		const Vec3 w3 = select(xyz == 0.0, 1.0 - fcoord, fcoord);
 		F32 w = w3.x * w3.y * w3.z;
@@ -439,7 +468,7 @@ SamplerState g_linearAnyRepeatSampler : register(s0);
 		uvw.z += 0.5;
 		uvw /= realVolumeSize;
 
-		const Vec3 ir = g_clipmapVolumes[clipmapIdx].SampleLevel(g_linearAnyRepeatSampler, uvw, 0.0);
+		const Vec3 ir = g_clipmapVolumes[NonUniformResourceIndex(clipmapIdx)].SampleLevel(g_linearAnyRepeatSampler, uvw, 0.0);
 		irradiance += ir * w;
 		weightSum += w;
 	}
@@ -648,6 +677,7 @@ ANKI_FAST_CONSTANTS(Consts, g_consts)
 ConstantBuffer<GlobalRendererConstants> g_globalRendererConstants : register(b0);
 
 Texture3D<Vec4> g_volume : register(t0);
+Texture3D<Vec4> g_probeValidityVolume : register(t1);
 
 SamplerState g_linearAnyRepeatSampler : register(s0);
 
@@ -731,7 +761,16 @@ FragOut main(VertOut input)
 
 	uvw.z = (texelCoord.z + 0.5) / clipmap.m_probeCounts.y;
 
-	Vec3 radiance = g_volume.SampleLevel(g_linearAnyRepeatSampler, uvw, 0.0).xyz;
+	const Bool valid = g_probeValidityVolume[texelCoord].x > 0.9;
+	Vec3 radiance;
+	if(valid)
+	{
+		radiance = g_volume.SampleLevel(g_linearAnyRepeatSampler, uvw, 0.0).xyz;
+	}
+	else
+	{
+		radiance = Vec3(1.0, 0.0, 1.0);
+	}
 
 	output.m_color = Vec4(radiance, 0.0);
 	return output;