Browse Source

Improvements in GI of reflection probes

Panagiotis Christopoulos Charitos 1 year ago
parent
commit
f7bfc31511

+ 2 - 2
AnKi/Gr/Vulkan/VkGraphicsState.cpp

@@ -11,7 +11,7 @@
 
 namespace anki {
 
-static VkViewport computeViewport(U32* viewport, U32 fbWidth, U32 fbHeight)
+static VkViewport computeViewport(const U32 viewport[], U32 fbWidth, U32 fbHeight)
 {
 	const U32 minx = viewport[0];
 	const U32 miny = viewport[1];
@@ -26,7 +26,7 @@ static VkViewport computeViewport(U32* viewport, U32 fbWidth, U32 fbHeight)
 	return s;
 }
 
-static VkRect2D computeScissor(U32* scissor, U32 fbWidth, U32 fbHeight)
+static VkRect2D computeScissor(const U32 scissor[], U32 fbWidth, U32 fbHeight)
 {
 	const U32 minx = scissor[0];
 	const U32 miny = scissor[1];

+ 31 - 0
AnKi/Math/Mat.h

@@ -1278,6 +1278,37 @@ public:
 		return m;
 	}
 
+	/// Calculate a perspective projection matrix. The z is reversed and mapped in [1, 0] range just like DX and Vulkan.
+	/// Same as D3DXMatrixPerspectiveFovRH but z reversed
+	[[nodiscard]] static TMat calculatePerspectiveProjectionMatrixReverseZ(T fovX, T fovY, T near, T far) requires(kSize == 16)
+	{
+		ANKI_ASSERT(fovX > T(0) && fovY > T(0) && near > T(0) && far > T(0));
+		const T g = near - far;
+		const T f = T(1) / tan(fovY / T(2)); // f = cot(fovY/2)
+
+		TMat proj;
+		proj(0, 0) = f * (fovY / fovX); // = f/aspectRatio;
+		proj(0, 1) = T(0);
+		proj(0, 2) = T(0);
+		proj(0, 3) = T(0);
+		proj(1, 0) = T(0);
+		proj(1, 1) = f;
+		proj(1, 2) = T(0);
+		proj(1, 3) = T(0);
+		proj(2, 0) = T(0);
+		proj(2, 1) = T(0);
+		proj(2, 2) = far / g;
+		proj(2, 3) = (far * near) / g;
+		proj(3, 0) = T(0);
+		proj(3, 1) = T(0);
+		proj(3, 2) = T(-1);
+		proj(3, 3) = T(0);
+
+		const TMat rev(T(1), T(0), T(0), T(0), T(0), T(1), T(0), T(0), T(0), T(0), T(-1), T(1), T(0), T(0), T(0), T(1));
+
+		return rev * proj;
+	}
+
 	/// Given the parameters that construct a projection matrix extract 4 values that can be used to unproject a point from NDC to view space.
 	/// @code
 	/// Vec4 unprojParams = calculatePerspectiveUnprojectionParams(...);

+ 2 - 0
AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -329,6 +329,8 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 
 					getRenderer().getRenderableDrawer().drawMdi(args, cmdb);
 
+					cmdb.setPolygonOffset(0.0, 0.0);
+
 					// It's secondary, no need to restore the state
 				});
 			}

+ 0 - 5
AnKi/Renderer/LightShading.cpp

@@ -266,11 +266,6 @@ void LightShading::populateRenderGraph(RenderingContext& ctx)
 	pass.newTextureDependency(getRenderer().getSsao().getRt(), readUsage);
 	pass.newTextureDependency(getRenderer().getReflections().getRt(), readUsage);
 
-	if(getRenderer().getProbeReflections().getHasCurrentlyRefreshedReflectionRt())
-	{
-		pass.newTextureDependency(getRenderer().getProbeReflections().getCurrentlyRefreshedReflectionRt(), readUsage);
-	}
-
 	// Fog
 	pass.newTextureDependency(getRenderer().getVolumetricFog().getRt(), readUsage);
 

+ 18 - 65
AnKi/Renderer/ProbeReflections.cpp

@@ -10,8 +10,10 @@
 #include <AnKi/Renderer/GBuffer.h>
 #include <AnKi/Renderer/Sky.h>
 #include <AnKi/Renderer/PrimaryNonRenderableVisibility.h>
+#include <AnKi/Renderer/IndirectDiffuseProbes.h>
 #include <AnKi/Renderer/Utils/MipmapGenerator.h>
 #include <AnKi/Renderer/Utils/Drawer.h>
+#include <AnKi/Renderer/Reflections.h>
 #include <AnKi/Util/CVarSet.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Core/StatsSet.h>
@@ -148,6 +150,12 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 {
 	ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
 
+	const Bool bRtReflections = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_rtReflectionsCVar;
+	if(bRtReflections)
+	{
+		return;
+	}
+
 	// Iterate the visible probes to find a candidate for update
 	WeakArray<ReflectionProbeComponent*> visibleProbes =
 		getRenderer().getPrimaryNonRenderableVisibility().getInterestingVisibleComponents().m_reflectionProbes;
@@ -161,7 +169,8 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		}
 	}
 
-	if(probeToRefresh == nullptr || ResourceManager::getSingleton().getAsyncLoader().getTasksInFlightCount() != 0) [[likely]]
+	if(probeToRefresh == nullptr || ResourceManager::getSingleton().getAsyncLoader().getTasksInFlightCount() != 0
+	   || getRenderer().getIndirectDiffuseProbes().hasCurrentlyRefreshedVolumeRt()) [[likely]]
 	{
 		// Nothing to update or can't update right now, early exit
 		m_runCtx = {};
@@ -327,6 +336,8 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 				args.fill(shadowVisOut);
 
 				getRenderer().getRenderableDrawer().drawMdi(args, cmdb);
+
+				cmdb.setPolygonOffset(0.0, 0.0);
 			});
 		}
 
@@ -369,6 +380,11 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 				pass.newTextureDependency(getRenderer().getGeneratedSky().getSkyLutRt(), TextureUsageBit::kSrvPixel);
 			}
 
+			if(getRenderer().getIndirectDiffuseProbes().hasCurrentlyRefreshedVolumeRt())
+			{
+				pass.newTextureDependency(getRenderer().getIndirectDiffuseProbes().getCurrentlyRefreshedVolumeRt(), TextureUsageBit::kSrvPixel);
+			}
+
 			pass.setWork([this, visResult = lightVis.m_visiblesBuffer, viewProjMat = frustum.getViewProjectionMatrix(),
 						  cascadeViewProjMat = cascadeViewProjMat, probeToRefresh, gbufferColorRts, gbufferDepthRt, shadowMapRt, faceIdx = f,
 						  &rctx](RenderPassWorkContext& rgraphCtx) {
@@ -380,6 +396,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 				dsInfo.m_cameraPosWSpace = probeToRefresh->getWorldPosition().xyz1();
 				dsInfo.m_viewport = UVec4(0, 0, m_lightShading.m_tileSize, m_lightShading.m_tileSize);
 				dsInfo.m_effectiveShadowDistance = probeToRefresh->getShadowsRenderRadius();
+				dsInfo.m_applyIndirectDiffuse = true;
 
 				const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
 				dsInfo.m_dirLightMatrix = biasMat4 * cascadeViewProjMat;
@@ -406,70 +423,6 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		}
 	} // For 6 faces
 
-	// Compute Irradiance
-	{
-		NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("Cube refl: Irradiance");
-
-		pass.newTextureDependency(probeTexture, TextureUsageBit::kSrvCompute);
-
-		pass.newBufferDependency(irradianceDiceValuesBuffHandle, BufferUsageBit::kUavCompute);
-
-		pass.setWork([this, probeTexture](RenderPassWorkContext& rgraphCtx) {
-			ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
-
-			CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-
-			cmdb.bindShaderProgram(m_irradiance.m_grProg.get());
-
-			cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
-
-			rgraphCtx.bindSrv(0, 0, probeTexture);
-
-			cmdb.bindUav(0, 0, BufferView(m_irradiance.m_diceValuesBuff.get()));
-
-			cmdb.dispatchCompute(1, 1, 1);
-		});
-	}
-
-	// Append irradiance back to refl cubemap
-	{
-		NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("Cube refl: Apply indirect");
-
-		for(U i = 0; i < kGBufferColorRenderTargetCount - 1; ++i)
-		{
-			pass.newTextureDependency(gbufferColorRts[i], TextureUsageBit::kSrvCompute);
-		}
-
-		pass.newTextureDependency(probeTexture, TextureUsageBit::kUavCompute);
-
-		pass.newBufferDependency(irradianceDiceValuesBuffHandle, BufferUsageBit::kSrvCompute);
-
-		pass.setWork([this, gbufferColorRts, probeTexture](RenderPassWorkContext& rgraphCtx) {
-			ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
-
-			CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-
-			cmdb.bindShaderProgram(m_irradianceToRefl.m_grProg.get());
-
-			// Bind resources
-			cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
-
-			for(U32 i = 0; i < kGBufferColorRenderTargetCount - 1; ++i)
-			{
-				rgraphCtx.bindSrv(i, 0, gbufferColorRts[i]);
-			}
-
-			cmdb.bindSrv(3, 0, BufferView(m_irradiance.m_diceValuesBuff.get()));
-
-			for(U8 f = 0; f < 6; ++f)
-			{
-				rgraphCtx.bindUav(f, 0, probeTexture, TextureSubresourceDesc::surface(0, f, 0));
-			}
-
-			dispatchPPCompute(cmdb, 8, 8, m_lightShading.m_tileSize, m_lightShading.m_tileSize);
-		});
-	}
-
 	// Mipmapping "passes"
 	{
 		const MipmapGeneratorTargetArguments desc = {

+ 6 - 0
AnKi/Renderer/Reflections.cpp

@@ -13,6 +13,7 @@
 #include <AnKi/Renderer/DepthDownscale.h>
 #include <AnKi/Renderer/ShadowMapping.h>
 #include <AnKi/Renderer/ClusterBinning.h>
+#include <AnKi/Renderer/ProbeReflections.h>
 #include <AnKi/Core/GpuMemory/GpuVisibleTransientMemoryPool.h>
 #include <AnKi/Core/GpuMemory/UnifiedGeometryBuffer.h>
 #include <AnKi/Scene/Components/SkyboxComponent.h>
@@ -405,6 +406,11 @@ void Reflections::populateRenderGraph(RenderingContext& ctx)
 			rpass.newTextureDependency(getRenderer().getGeneratedSky().getEnvironmentMapRt(), TextureUsageBit::kSrvCompute);
 		}
 
+		if(getRenderer().getProbeReflections().getHasCurrentlyRefreshedReflectionRt())
+		{
+			rpass.newTextureDependency(getRenderer().getProbeReflections().getCurrentlyRefreshedReflectionRt(), TextureUsageBit::kSrvCompute);
+		}
+
 		rpass.setWork([this, pixelsFailedSsrBuff, &ctx, transientRt1, hitPosAndDepthRt](RenderPassWorkContext& rgraphCtx) {
 			ANKI_TRACE_SCOPED_EVENT(Reflections);
 			CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;

+ 2 - 0
AnKi/Renderer/ShadowMapping.cpp

@@ -676,6 +676,8 @@ void ShadowMapping::createDrawShadowsPass(ConstWeakArray<ShadowSubpassInfo> subp
 			args.fill(visOut);
 
 			getRenderer().getRenderableDrawer().drawMdi(args, cmdb);
+
+			cmdb.setPolygonOffset(0.0, 0.0);
 		}
 	});
 }

+ 14 - 3
AnKi/Renderer/Utils/TraditionalDeferredShading.cpp

@@ -20,8 +20,12 @@ Error TraditionalDeferredLightShading::init()
 	// Init progs
 	for(MutatorValue specular = 0; specular <= 1; ++specular)
 	{
-		ANKI_CHECK(loadShaderProgram("ShaderBinaries/TraditionalDeferredShading.ankiprogbin", {{"SPECULAR", specular}}, m_lightProg,
-									 m_lightGrProg[specular]));
+		for(MutatorValue applyIndirectDiffuse = 0; applyIndirectDiffuse <= 1; ++applyIndirectDiffuse)
+		{
+			ANKI_CHECK(loadShaderProgram("ShaderBinaries/TraditionalDeferredShading.ankiprogbin",
+										 {{"SPECULAR", specular}, {"INDIRECT_DIFFUSE", applyIndirectDiffuse}}, m_lightProg,
+										 m_lightGrProg[specular][applyIndirectDiffuse]));
+		}
 	}
 
 	// Shadow sampler
@@ -134,9 +138,16 @@ void TraditionalDeferredLightShading::drawLights(TraditionalDeferredLightShading
 			rgraphCtx.bindSrv(6, 0, info.m_gbufferDepthRenderTarget, info.m_gbufferDepthRenderTargetSubresource);
 		}
 
+		const Bool indirectDiffuse = info.m_applyIndirectDiffuse && GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount();
+		if(indirectDiffuse)
+		{
+			cmdb.bindSrv(7, 0, GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getBufferView());
+			cmdb.bindSampler(2, 0, getRenderer().getSamplers().m_trilinearClamp.get());
+		}
+
 		cmdb.bindConstantBuffer(1, 0, info.m_globalRendererConsts);
 
-		cmdb.bindShaderProgram(m_lightGrProg[info.m_computeSpecular].get());
+		cmdb.bindShaderProgram(m_lightGrProg[info.m_computeSpecular][indirectDiffuse].get());
 
 		drawQuad(cmdb);
 	}

+ 2 - 1
AnKi/Renderer/Utils/TraditionalDeferredShading.h

@@ -26,6 +26,7 @@ public:
 	BufferView m_visibleLightsBuffer;
 
 	Bool m_computeSpecular = false;
+	Bool m_applyIndirectDiffuse = false; ///< Apply GI using the indirect diffuse probes.
 
 	// Render targets
 	Array<RenderTargetHandle, kGBufferColorRenderTargetCount - 1> m_gbufferRenderTargets;
@@ -55,7 +56,7 @@ public:
 
 private:
 	ShaderProgramResourcePtr m_lightProg;
-	Array<ShaderProgramPtr, 2> m_lightGrProg;
+	Array2d<ShaderProgramPtr, 2, 2> m_lightGrProg;
 
 	ShaderProgramResourcePtr m_skyboxProg;
 	Array<ShaderProgramPtr, 3> m_skyboxGrProgs;

+ 5 - 1
AnKi/Shaders/Reflections.ankiprog

@@ -60,7 +60,11 @@ Vec3 getDiffuseIndirect(StructuredBuffer<GpuSceneGlobalIlluminationProbe> giProb
 	U32 i;
 	for(i = 0; i < probeCount; ++i)
 	{
-		if(all(worldPos < giProbes[i].m_aabbMax) && all(worldPos > giProbes[i].m_aabbMin))
+		if(any(worldPos >= giProbes[i].m_aabbMax) || any(worldPos <= giProbes[i].m_aabbMin))
+		{
+			continue;
+		}
+		else
 		{
 			break;
 		}

+ 36 - 0
AnKi/Shaders/TraditionalDeferredShading.ankiprog

@@ -6,6 +6,7 @@
 // Classic deferred lighting shader
 
 #pragma anki mutator SPECULAR 0 1
+#pragma anki mutator INDIRECT_DIFFUSE 0 1
 
 #pragma anki technique vert pixel
 
@@ -32,8 +33,39 @@ Texture2D<Vec4> g_depthTex : register(t5);
 SamplerComparisonState g_shadowMapSampler : register(s1);
 Texture2D<Vec4> g_shadowMap : register(t6);
 
+#	if INDIRECT_DIFFUSE
+StructuredBuffer<GpuSceneGlobalIlluminationProbe> g_giProbes : register(t7);
+SamplerState g_linearAnyClampSampler : register(s2);
+#	endif
+
 ConstantBuffer<GlobalRendererConstants> g_globalRendererConsts : register(b1);
 
+#	if INDIRECT_DIFFUSE
+Vec3 getDiffuseIndirect(Vec3 worldPos, Vec3 worldNormal)
+{
+	const U32 probeCount = getStructuredBufferElementCount(g_giProbes);
+	U32 i;
+	for(i = 0; i < probeCount; ++i)
+	{
+		if(all(worldPos < g_giProbes[i].m_aabbMax) && all(worldPos > g_giProbes[i].m_aabbMin))
+		{
+			break;
+		}
+	}
+
+	const Bool probeFound = (i != probeCount);
+	if(probeFound)
+	{
+		const GpuSceneGlobalIlluminationProbe probe = g_giProbes[i];
+		return sampleGlobalIllumination<F32>(worldPos, worldNormal, probe, getBindlessTexture3DVec4(probe.m_volumeTexture), g_linearAnyClampSampler);
+	}
+	else
+	{
+		return 0.0;
+	}
+}
+#	endif
+
 Vec4 main(VertOut input) : SV_TARGET0
 {
 	const Vec2 uv = input.m_uv;
@@ -59,6 +91,10 @@ Vec4 main(VertOut input) : SV_TARGET0
 	const Vec3 viewDir = normalize(g_consts.m_cameraPos - worldPos);
 	ANKI_MAYBE_UNUSED(viewDir);
 
+#	if INDIRECT_DIFFUSE
+	outColor += getDiffuseIndirect(worldPos, gbuffer.m_normal) * gbuffer.m_diffuse;
+#	endif
+
 	// Dir light
 	if(g_globalRendererConsts.m_directionalLight.m_shadowCascadeCount_31bit_active_1bit & 1u)
 	{

+ 7 - 0
AnKi/Shaders/VisibilityAndCollisionFunctions.hlsl

@@ -216,6 +216,13 @@ void projectAabb(Vec3 aabbMin, Vec3 aabbMax, Mat4 viewProjMat, out Vec2 minNdc,
 		aabbMinDepth = min(aabbMinDepth, p.z);
 	}
 
+	if(aabbMinDepth < 0.0)
+	{
+		// Behind the camera so we can't be sure about our calculations
+		minNdc = -1.0;
+		maxNdc = 1.0;
+	}
+
 	aabbMinDepth = saturate(aabbMinDepth);
 }