Browse Source

Add gbuffer support in SSR

Panagiotis Christopoulos Charitos 1 năm trước cách đây
mục cha
commit
67cffa9812

+ 25 - 15
AnKi/Renderer/Reflections.cpp

@@ -25,6 +25,9 @@ namespace anki {
 Error Reflections::init()
 {
 	const Bool bRtReflections = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && g_rtReflectionsCVar;
+	const Bool bSsrSamplesGBuffer = bRtReflections;
+
+	std::initializer_list<SubMutation> mutation = {{"SSR_SAMPLE_GBUFFER", bSsrSamplesGBuffer}};
 
 	if(bRtReflections)
 	{
@@ -38,6 +41,7 @@ Error Reflections::init()
 
 		ShaderProgramResourceVariantInitInfo variantInitInfo(m_rtProg);
 		variantInitInfo.requestTechniqueAndTypes(ShaderTypeBit::kRayGen, "RtMaterialFetch");
+		variantInitInfo.addMutation("SSR_SAMPLE_GBUFFER", bSsrSamplesGBuffer);
 		const ShaderProgramResourceVariant* variant;
 		m_rtProg->getOrCreateVariant(variantInitInfo, variant);
 		m_libraryGrProg.reset(&variant->getProgram());
@@ -45,18 +49,19 @@ Error Reflections::init()
 
 		ShaderProgramResourceVariantInitInfo variantInitInfo2(m_rtProg);
 		variantInitInfo2.requestTechniqueAndTypes(ShaderTypeBit::kMiss, "RtMaterialFetch");
+		variantInitInfo2.addMutation("SSR_SAMPLE_GBUFFER", bSsrSamplesGBuffer);
 		m_rtProg->getOrCreateVariant(variantInitInfo2, variant);
 		m_missShaderGroupIdx = variant->getShaderGroupHandleIndex();
 	}
 
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Reflections.ankiprogbin", {}, m_rtProg, m_spatialDenoisingGrProg, "SpatialDenoise"));
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Reflections.ankiprogbin", {}, m_rtProg, m_temporalDenoisingGrProg, "TemporalDenoise"));
-	ANKI_CHECK(
-		loadShaderProgram("ShaderBinaries/Reflections.ankiprogbin", {}, m_rtProg, m_verticalBilateralDenoisingGrProg, "BilateralDenoiseVertical"));
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Reflections.ankiprogbin", {}, m_rtProg, m_horizontalBilateralDenoisingGrProg,
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Reflections.ankiprogbin", mutation, m_rtProg, m_spatialDenoisingGrProg, "SpatialDenoise"));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Reflections.ankiprogbin", mutation, m_rtProg, m_temporalDenoisingGrProg, "TemporalDenoise"));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Reflections.ankiprogbin", mutation, m_rtProg, m_verticalBilateralDenoisingGrProg,
+								 "BilateralDenoiseVertical"));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Reflections.ankiprogbin", mutation, m_rtProg, m_horizontalBilateralDenoisingGrProg,
 								 "BilateralDenoiseHorizontal"));
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Reflections.ankiprogbin", {}, m_rtProg, m_ssrGrProg, "Ssr"));
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Reflections.ankiprogbin", {}, m_rtProg, m_probeFallbackGrProg, "ReflectionProbeFallback"));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Reflections.ankiprogbin", mutation, m_rtProg, m_ssrGrProg, "Ssr"));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Reflections.ankiprogbin", mutation, m_rtProg, m_probeFallbackGrProg, "ReflectionProbeFallback"));
 
 	m_sbtRecordSize = getAlignedRoundUp(GrManager::getSingleton().getDeviceCapabilities().m_sbtRecordAlignment,
 										GrManager::getSingleton().getDeviceCapabilities().m_shaderGroupHandleSize + U32(sizeof(UVec4)));
@@ -168,11 +173,13 @@ void Reflections::populateRenderGraph(RenderingContext& ctx)
 		NonGraphicsRenderPass& rpass = rgraph.newNonGraphicsRenderPass("SSR");
 
 		rpass.newTextureDependency(getRenderer().getDepthDownscale().getRt(), TextureUsageBit::kSrvCompute);
+		rpass.newTextureDependency(getRenderer().getGBuffer().getColorRt(0), TextureUsageBit::kSrvCompute);
 		rpass.newTextureDependency(getRenderer().getGBuffer().getColorRt(1), TextureUsageBit::kSrvCompute);
 		rpass.newTextureDependency(getRenderer().getGBuffer().getColorRt(2), TextureUsageBit::kSrvCompute);
 		rpass.newTextureDependency(getRenderer().getGBuffer().getDepthRt(), TextureUsageBit::kSrvCompute);
 		rpass.newTextureDependency(getRenderer().getBloom().getPyramidRt(), TextureUsageBit::kSrvCompute);
 		rpass.newBufferDependency(getRenderer().getClusterBinning().getClustersBufferHandle(), BufferUsageBit::kSrvCompute);
+		rpass.newTextureDependency(getRenderer().getShadowMapping().getShadowmapRt(), TextureUsageBit::kSrvCompute);
 
 		rpass.newTextureDependency(transientRt1, TextureUsageBit::kUavCompute);
 		rpass.newTextureDependency(hitPosAndDepthRt, TextureUsageBit::kUavCompute);
@@ -185,14 +192,17 @@ void Reflections::populateRenderGraph(RenderingContext& ctx)
 			cmdb.bindShaderProgram(m_ssrGrProg.get());
 
 			cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
-
-			rgraphCtx.bindSrv(0, 0, getRenderer().getGBuffer().getColorRt(1));
-			rgraphCtx.bindSrv(1, 0, getRenderer().getGBuffer().getColorRt(2));
-			rgraphCtx.bindSrv(2, 0, getRenderer().getDepthDownscale().getRt());
-			rgraphCtx.bindSrv(3, 0, getRenderer().getGBuffer().getDepthRt());
-			rgraphCtx.bindSrv(4, 0, getRenderer().getBloom().getPyramidRt());
-			cmdb.bindSrv(5, 0, getRenderer().getClusterBinning().getPackedObjectsBuffer(GpuSceneNonRenderableObjectType::kGlobalIlluminationProbe));
-			cmdb.bindSrv(6, 0, getRenderer().getClusterBinning().getClustersBuffer());
+			cmdb.bindSampler(1, 0, getRenderer().getSamplers().m_trilinearClampShadow.get());
+
+			rgraphCtx.bindSrv(0, 0, getRenderer().getGBuffer().getColorRt(0));
+			rgraphCtx.bindSrv(1, 0, getRenderer().getGBuffer().getColorRt(1));
+			rgraphCtx.bindSrv(2, 0, getRenderer().getGBuffer().getColorRt(2));
+			rgraphCtx.bindSrv(3, 0, getRenderer().getDepthDownscale().getRt());
+			rgraphCtx.bindSrv(4, 0, getRenderer().getGBuffer().getDepthRt());
+			rgraphCtx.bindSrv(5, 0, getRenderer().getBloom().getPyramidRt());
+			cmdb.bindSrv(6, 0, getRenderer().getClusterBinning().getPackedObjectsBuffer(GpuSceneNonRenderableObjectType::kGlobalIlluminationProbe));
+			cmdb.bindSrv(7, 0, getRenderer().getClusterBinning().getClustersBuffer());
+			rgraphCtx.bindSrv(8, 0, getRenderer().getShadowMapping().getShadowmapRt());
 
 			rgraphCtx.bindUav(0, 0, transientRt1);
 			rgraphCtx.bindUav(1, 0, hitPosAndDepthRt);

+ 10 - 2
AnKi/Shaders/GBufferGeneric.ankiprog

@@ -36,7 +36,7 @@
 #pragma anki technique RtShadows ahit mutators ALPHA_TEST DIFFUSE_TEX
 #pragma anki technique RtShadows chit mutators
 
-#pragma anki technique RtMaterialFetch chit mutators DIFFUSE_TEX EMISSIVE_TEX
+#pragma anki technique RtMaterialFetch chit mutators DIFFUSE_TEX EMISSIVE_TEX ROUGHNESS_METALNESS_TEX
 
 #include <AnKi/Shaders/Include/MaterialTypes.h>
 #include <AnKi/Shaders/Include/GpuSceneFunctions.h>
@@ -714,6 +714,14 @@ GBufferPixelOut main(
 	const Vec2 uv = vert0.m_uv * bary.x + vert1.m_uv * bary.y + vert2.m_uv * bary.z;
 	ANKI_MAYBE_UNUSED(uv);
 
+	// Metallness
+#		if ROUGHNESS_METALNESS_TEX
+	const RVec3 comp = getBindlessTexture2DRVec4(localConstants.m_roughnessMetalnessTex).SampleLevel(g_globalSampler, uv, payload.m_textureLod).xyz;
+	const RF32 metallic = comp.b * localConstants.m_metalnessScale;
+#		else
+	const RF32 metallic = localConstants.m_metalnessScale;
+#		endif
+
 	// Diffuse
 #		if DIFFUSE_TEX
 	RVec3 diffColor = getBindlessTexture2DRVec4(localConstants.m_diffuseTex).SampleLevel(g_globalSampler, uv, payload.m_textureLod).xyz;
@@ -721,7 +729,7 @@ GBufferPixelOut main(
 	RVec3 diffColor = 1.0;
 #		endif
 	diffColor *= localConstants.m_diffuseScale;
-	payload.m_diffuseColor = diffColor;
+	payload.m_diffuseColor = diffColor * (1.0 - metallic);
 
 	// Emissive
 #		if EMISSIVE_TEX

+ 92 - 39
AnKi/Shaders/Reflections.ankiprog

@@ -3,13 +3,15 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
+#pragma anki mutator SSR_SAMPLE_GBUFFER 0 1
+
 #pragma anki technique Ssr comp
-#pragma anki technique ReflectionProbeFallback comp
-#pragma anki technique RtMaterialFetch rgen miss
-#pragma anki technique SpatialDenoise comp
-#pragma anki technique TemporalDenoise comp
-#pragma anki technique BilateralDenoiseVertical comp
-#pragma anki technique BilateralDenoiseHorizontal comp
+#pragma anki technique ReflectionProbeFallback comp mutators
+#pragma anki technique RtMaterialFetch rgen miss mutators
+#pragma anki technique SpatialDenoise comp mutators
+#pragma anki technique TemporalDenoise comp mutators
+#pragma anki technique BilateralDenoiseVertical comp mutators
+#pragma anki technique BilateralDenoiseHorizontal comp mutators
 
 #include <AnKi/Shaders/RtMaterialFetch.hlsl>
 #include <AnKi/Shaders/Include/GpuSceneTypes.h>
@@ -30,6 +32,9 @@ constexpr Bool kTryShadowmapFirst = true;
 constexpr Bool kDisableDenoising = false;
 constexpr F32 kTMinBias = -1.0;
 constexpr Bool kExtraSsrRejection = true;
+constexpr Bool kDebugSsr = false;
+constexpr Bool kSsrHallucinate = true;
+constexpr Bool kSsrHallucinateDebug = false;
 
 // Functions
 Vec3 getDiffuseIndirect(StructuredBuffer<GpuSceneGlobalIlluminationProbe> giProbes, Vec3 worldPos, Vec3 worldNormal,
@@ -90,14 +95,17 @@ void decodeColorDepthAndSampleCount(Vec4 rgba, out Vec3 color, out F32 depth, ou
 constexpr F32 kLowAttenuation = 0.01;
 
 SamplerState g_trilinearClampSampler : register(s0);
-
-Texture2D<Vec4> g_gbufferRt1 : register(t0);
-Texture2D<Vec4> g_gbufferRt2 : register(t1);
-Texture2D<Vec4> g_downscaledDepthTex : register(t2);
-Texture2D<Vec4> g_depthTex : register(t3);
-Texture2D<Vec4> g_lightBufferRt : register(t4);
-StructuredBuffer<GlobalIlluminationProbe> g_giProbes : register(t5);
-StructuredBuffer<Cluster> g_clusters : register(t6);
+SamplerComparisonState g_shadowSampler : register(s1);
+
+Texture2D<Vec4> g_gbufferRt0 : register(t0);
+Texture2D<Vec4> g_gbufferRt1 : register(t1);
+Texture2D<Vec4> g_gbufferRt2 : register(t2);
+Texture2D<Vec4> g_downscaledDepthTex : register(t3);
+Texture2D<Vec4> g_depthTex : register(t4);
+Texture2D<Vec4> g_lightBufferRt : register(t5);
+StructuredBuffer<GlobalIlluminationProbe> g_giProbes : register(t6);
+StructuredBuffer<Cluster> g_clusters : register(t7);
+Texture2D<Vec4> g_shadowAtlasTex : register(t8);
 
 RWTexture2D<Vec4> g_colorAndPdfTex : register(u0);
 RWTexture2D<Vec4> g_hitPosAndDepthTex : register(u1);
@@ -111,10 +119,50 @@ ANKI_FAST_CONSTANTS(ReflectionConstants, g_consts)
 #	define NUM_THREADS_SQRT 8
 
 groupshared Vec4 g_viewHitPointAndAttenuation[NUM_THREADS_SQRT][NUM_THREADS_SQRT];
-groupshared Vec4 g_viewPosAndDepth[NUM_THREADS_SQRT][NUM_THREADS_SQRT];
+groupshared Vec4 g_colorAndDepth[NUM_THREADS_SQRT][NUM_THREADS_SQRT];
+
+Vec3 doLightShading(Vec3 worldPos, Vec3 viewPos, UVec2 coord, F32 depth)
+{
+	// Read
+	GbufferInfo<RF32> gbuffer = (GbufferInfo<RF32>)0;
+	unpackGBufferNoVelocity<RF32>(g_gbufferRt0[coord], g_gbufferRt1[coord], g_gbufferRt2[coord], gbuffer);
+
+	Vec3 outColor = gbuffer.m_emission;
+	Cluster cluster = getClusterFragCoord(g_clusters, g_globalRendererConstants, Vec3(coord.xy + 0.5, depth));
+
+	// GI
+	outColor += sampleGiProbes<F32>(cluster, g_giProbes, gbuffer.m_normal, worldPos.xyz, g_trilinearClampSampler) * gbuffer.m_diffuse;
+
+	// Dir light
+	const DirectionalLight dirLight = g_globalRendererConstants.m_directionalLight;
+	if(dirLight.m_shadowCascadeCount_31bit_active_1bit & 1u)
+	{
+		const U32 shadowCascadeCount = dirLight.m_shadowCascadeCount_31bit_active_1bit >> 1u;
+		F32 shadowFactor;
+		if(shadowCascadeCount >> 1u)
+		{
+			const F32 negativeZViewSpace = -viewPos.z;
+
+			const U32 cascadeIdx = computeShadowCascadeIndex(negativeZViewSpace, dirLight.m_shadowCascadeDistances, shadowCascadeCount);
+
+			shadowFactor = computeShadowFactorDirLight(dirLight, cascadeIdx, worldPos, g_shadowAtlasTex, g_shadowSampler);
+		}
+		else
+		{
+			shadowFactor = 1.0;
+		}
+
+		const Vec3 l = -dirLight.m_direction;
+		const F32 lambert = max(0.0, dot(l, gbuffer.m_normal));
+		const Vec3 diffC = diffuseLobe(gbuffer.m_diffuse);
+		outColor += diffC * dirLight.m_diffuseColor * lambert * shadowFactor;
+	}
+
+	return outColor;
+}
 
-void doSsr(UVec2 realCoord, UVec2 logicalCoord, Vec2 uv, Vec3 viewPos, F32 depth, F32 randFactor, inout Vec3 viewReflDir, out F32 attenuation,
-		   out Vec3 outColor, out Vec3 viewHitPoint)
+void doSsr(UVec2 logicalViewportSize, UVec2 realCoord, UVec2 logicalCoord, Vec2 uv, Vec3 viewPos, F32 depth, F32 randFactor, inout Vec3 viewReflDir,
+		   out F32 attenuation, out Vec3 outColor, out Vec3 viewHitPoint)
 {
 	attenuation = 0.0;
 	outColor = 0.0;
@@ -172,15 +220,21 @@ void doSsr(UVec2 realCoord, UVec2 logicalCoord, Vec2 uv, Vec3 viewPos, F32 depth
 
 	// Read the reflection
 	{
-		// Reproject the hit point because you are reading the previous frame
-		const Vec4 v4 = mul(g_globalRendererConstants.m_matrices.m_reprojection, Vec4(uvToNdc(hitPoint.xy), hitPoint.z, 1.0));
-		hitPoint.xy = ndcToUv(v4.xy / v4.w);
-
-		// Read the light buffer
-		Vec3 ssrColor = g_lightBufferRt.SampleLevel(g_trilinearClampSampler, hitPoint.xy, 0.0).rgb;
-		ssrColor = clamp(ssrColor, 0.0, kMaxRF32); // Fix the value just in case
+		if(!SSR_SAMPLE_GBUFFER)
+		{
+			// Reproject the hit point because you are reading the previous frame
+			const Vec4 v4 = mul(g_globalRendererConstants.m_matrices.m_reprojection, Vec4(uvToNdc(hitPoint.xy), hitPoint.z, 1.0));
+			hitPoint.xy = ndcToUv(v4.xy / v4.w);
 
-		outColor = ssrColor;
+			// Read the light buffer
+			const Vec3 ssrColor = g_lightBufferRt.SampleLevel(g_trilinearClampSampler, hitPoint.xy, 0.0).rgb;
+			outColor = clamp(ssrColor, 0.0, kMaxRF32); // Fix the value just in case
+		}
+		else
+		{
+			outColor = doLightShading(mul(g_globalRendererConstants.m_matrices.m_cameraTransform, Vec4(viewHitPoint, 1.0)), viewHitPoint,
+									  hitPoint.xy * logicalViewportSize, depth1);
+		}
 	}
 }
 
@@ -197,7 +251,7 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 
 	candidateCount += 1.0;
 
-	const F32 weight = calculateBilateralWeightDepth(depth, g_viewPosAndDepth[svGroupThreadId2.x][svGroupThreadId2.y].w, 1.0);
+	const F32 weight = calculateBilateralWeightDepth(depth, g_colorAndDepth[svGroupThreadId2.x][svGroupThreadId2.y].w, 1.0);
 	if(weight > depthWeight)
 	{
 		depthWeight = weight;
@@ -273,12 +327,13 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 			viewReflDir = reflect(-viewDir, viewNormal);
 		}
 
-		doSsr(realCoord, logicalCoord, uv, viewPos, depth, randFactors.x, viewReflDir, ssrAttenuation, outColor, viewHitPoint);
+		doSsr(halfViewportSize * UVec2(2, 1), realCoord, logicalCoord, uv, viewPos, depth, randFactors.x, viewReflDir, ssrAttenuation, outColor,
+			  viewHitPoint);
 	}
 
 	// Stash to groupshared
 	g_viewHitPointAndAttenuation[svGroupThreadId.x][svGroupThreadId.y] = Vec4(viewHitPoint, ssrAttenuation);
-	g_viewPosAndDepth[svGroupThreadId.x][svGroupThreadId.y] = Vec4(viewPos, depth);
+	g_colorAndDepth[svGroupThreadId.x][svGroupThreadId.y] = Vec4(outColor, depth);
 	GroupMemoryBarrierWithGroupSync();
 
 	if(depth == 1.0)
@@ -290,7 +345,7 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 	}
 
 	// Hallucinate if needed
-	if(ssrAttenuation <= kLowAttenuation)
+	if(ssrAttenuation <= kLowAttenuation && kSsrHallucinate)
 	{
 		IVec2 neighbourOffset = -100;
 		F32 depthWeight = 0.0;
@@ -307,10 +362,7 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 
 			const UVec2 neighbourSvGroupThreadId = svGroupThreadId + neighbourOffset;
 
-			const Vec3 neighbourViewPos = g_viewPosAndDepth[neighbourSvGroupThreadId.x][neighbourSvGroupThreadId.y].xyz;
-
 			viewHitPoint = g_viewHitPointAndAttenuation[neighbourSvGroupThreadId.x][neighbourSvGroupThreadId.y].xyz;
-			viewHitPoint += viewPos - g_viewPosAndDepth[neighbourSvGroupThreadId.x][neighbourSvGroupThreadId.y].xyz;
 
 			viewReflDir = normalize(viewHitPoint - viewPos);
 			const Vec3 viewDir = normalize(-viewPos);
@@ -319,9 +371,12 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 
 			ssrAttenuation = g_viewHitPointAndAttenuation[neighbourSvGroupThreadId.x][neighbourSvGroupThreadId.y].w;
 
-			const Vec4 v4 = cheapPerspectiveProjection(g_globalRendererConstants.m_matrices.m_projMat00_11_22_23, Vec4(viewHitPoint, 1.0));
-			const Vec2 uv = ndcToUv(v4.xy / v4.w);
-			outColor = g_lightBufferRt.SampleLevel(g_trilinearClampSampler, uv, 0.0).rgb;
+			outColor = g_colorAndDepth[neighbourSvGroupThreadId.x][neighbourSvGroupThreadId.y].xyz;
+
+			if(kSsrHallucinateDebug)
+			{
+				outColor *= Vec3(0.0, 10.0, 0.0);
+			}
 		}
 	}
 
@@ -330,8 +385,6 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 	{
 		// Write to the image
 
-		pdf = max(0.0, pdf) * ssrAttenuation;
-
 		g_colorAndPdfTex[realCoord] = Vec4(outColor, pdf);
 
 		Vec3 worldHitPos = mul(g_globalRendererConstants.m_matrices.m_cameraTransform, Vec4(viewHitPoint, 1.0));
@@ -342,7 +395,7 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 	}
 	else
 	{
-		if(false)
+		if(kDebugSsr)
 		{
 			g_colorAndPdfTex[realCoord] = Vec4(1.0, 0.0, 1.0, 0.0);
 			g_hitPosAndDepthTex[realCoord] = Vec4(1.0, 0.0, 1.0, 0.0);
@@ -561,7 +614,7 @@ ANKI_FAST_CONSTANTS(Consts, g_consts)
 	outColor += payload.m_diffuseColor * indirectDiffuse;
 
 	const Vec3 l = -dirLight.m_direction;
-	const F32 lambert = dot(l, payload.m_worldNormal);
+	const F32 lambert = max(0.0, dot(l, payload.m_worldNormal));
 	const Vec3 diffC = diffuseLobe(payload.m_diffuseColor);
 	outColor += diffC * dirLight.m_diffuseColor * lambert * shadow;