Browse Source

WIP - Deferred MSAA
- Tiled deferred direct lighting and image based lighting now make sure of the MSAA coverage texture
- Fixed an issue with pixel precision that caused aliasing and other visual artifacts

BearishSun 8 years ago
parent
commit
8e451ac36f

+ 1 - 1
Data/Raw/Engine/Includes/PerCameraData.bslinc

@@ -84,7 +84,7 @@ mixin PerCameraData
 		/** Converts position in UV coordinates mapped to the screen, to screen coordinates in pixels. */
 		uint2 UVToScreen(float2 uv)
 		{
-			return (uint2)(uv * (float2)gViewportRectangle.zw - ((float2)gViewportRectangle.xy + 0.5f));
+			return (uint2)(uv * (float2)gViewportRectangle.zw - ((float2)gViewportRectangle.xy));
 		}
 		
 		/** Converts position in NDC to screen coordinates in pixels. */

+ 0 - 30
Data/Raw/Engine/Includes/SurfaceData.bslinc

@@ -10,35 +10,5 @@ mixin SurfaceData
 			float roughness;
 			float metalness;
 		};
-		
-#ifdef MSAA_COUNT
-#if MSAA_COUNT > 1
-		bool needsPerSampleShading(SurfaceData samples[MSAA_COUNT])
-		{
-			// Always shade all samples, otherwise there is visible aliasing. It could be enabled if HDR is not used.
-			return true;
-		
-			float3 albedo = samples[0].albedo.xyz;
-			float3 normal = samples[0].worldNormal.xyz;
-			float depth = samples[0].depth;
-
-			[unroll]
-			for(int i = 1; i < MSAA_COUNT; i++)
-			{
-				float3 otherAlbedo = samples[i].albedo.xyz;
-				float3 otherNormal = samples[i].worldNormal.xyz;
-				float otherDepth = samples[i].depth;
-
-				[branch]
-				if((abs(depth - otherDepth) > 0.01f) || (dot(normal, otherNormal) < 0.99f) || (abs(dot(albedo - otherAlbedo, float3(1, 1, 1))) > 0.01f))
-				{
-					return true;
-				}
-			}
-			
-			return false;
-		}
-#endif
-#endif
 	};
 };

+ 7 - 1
Data/Raw/Engine/Shaders/TiledDeferredImageBasedLighting.bsl

@@ -24,6 +24,7 @@ technique TiledDeferredImageBasedLighting
 		#if MSAA_COUNT > 1
 		Texture2DMS<float4> gInColor;
 		RWBuffer<float4> gOutput;
+		Texture2D gMSAACoverage;
 		
 		uint getLinearAddress(uint2 coord, uint sampleIndex)
 		{
@@ -258,10 +259,12 @@ technique TiledDeferredImageBasedLighting
 			if (all(dispatchThreadId.xy < viewportMax))
 			{
 				#if MSAA_COUNT > 1
+				float coverage = gMSAACoverage.Load(int3(pixelPos, 0)).r;
+				
 				float4 lighting = getLighting(pixelPos, 0, clipSpacePos.xy, surfaceData[0], 0, sNumProbes);
 				writeBufferSample(pixelPos, 0, lighting);
 
-				bool doPerSampleShading = needsPerSampleShading(surfaceData);
+				bool doPerSampleShading = coverage > 0.5f;
 				if(doPerSampleShading)
 				{
 					[unroll]
@@ -273,6 +276,9 @@ technique TiledDeferredImageBasedLighting
 				}
 				else // Splat same information to all samples
 				{
+					// Note: The splatting step can be skipped if we account for coverage when resolving. However
+					// the coverage texture potentially becomes invalid after transparent geometry is renedered, 
+					// so we need to resolve all samples. Consider getting around this issue somehow.				
 					[unroll]
 					for(uint i = 1; i < MSAA_COUNT; ++i)
 						writeBufferSample(pixelPos, i, lighting);

+ 9 - 3
Data/Raw/Engine/Shaders/TiledDeferredLighting.bsl

@@ -29,7 +29,8 @@ technique TiledDeferredLighting
 		}
 	
 		#if MSAA_COUNT > 1
-		RWBuffer<float4> gOutput : register(u0);
+		RWBuffer<float4> gOutput;
+		Texture2D gMSAACoverage;
 		
 		uint getLinearAddress(uint2 coord, uint sampleIndex)
 		{
@@ -43,7 +44,7 @@ technique TiledDeferredLighting
 		}
 
 		#else
-		RWTexture2D<float4>	gOutput : register(u0);
+		RWTexture2D<float4>	gOutput;
 		#endif
 					
 		groupshared uint sTileMinZ;
@@ -256,10 +257,12 @@ technique TiledDeferredLighting
 			if (all(dispatchThreadId.xy < viewportMax))
 			{
 				#if MSAA_COUNT > 1
+				float coverage = gMSAACoverage.Load(int3(pixelPos, 0)).r;
+				
 				float4 lighting = getLighting(clipSpacePos.xy, surfaceData[0]);
 				writeBufferSample(pixelPos, 0, lighting);
 
-				bool doPerSampleShading = needsPerSampleShading(surfaceData);
+				bool doPerSampleShading = coverage > 0.5f;
 				if(doPerSampleShading)
 				{
 					[unroll]
@@ -271,6 +274,9 @@ technique TiledDeferredLighting
 				}
 				else // Splat same information to all samples
 				{
+					// Note: The splatting step can be skipped if we account for coverage when resolving. However
+					// the coverage texture potentially becomes invalid after transparent geometry is renedered, 
+					// so we need to resolve all samples. Consider getting around this issue somehow.
 					[unroll]
 					for(uint i = 1; i < MSAA_COUNT; ++i)
 						writeBufferSample(pixelPos, i, lighting);

+ 6 - 0
Source/RenderBeast/BsImageBasedLighting.cpp

@@ -210,7 +210,10 @@ namespace bs { namespace ct
 
 		params->getTextureParam(GPT_COMPUTE_PROGRAM, "gInColor", mInColorTextureParam);
 		if (mSampleCount > 1)
+		{
+			params->getTextureParam(GPT_COMPUTE_PROGRAM, "gMSAACoverage", mMSAACoverageTexParam);
 			params->getBufferParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputBufferParam);
+		}
 		else
 			params->getLoadStoreTextureParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputTextureParam);
 
@@ -268,7 +271,10 @@ namespace bs { namespace ct
 
 		mInColorTextureParam.set(inputs.lightAccumulation);
 		if (mSampleCount > 1)
+		{
 			mOutputBufferParam.set(inputs.sceneColorBuffer);
+			mMSAACoverageTexParam.set(inputs.msaaCoverage);
+		}
 		else
 			mOutputTextureParam.set(inputs.sceneColorTex);
 

+ 2 - 0
Source/RenderBeast/BsImageBasedLighting.h

@@ -141,6 +141,7 @@ namespace bs { namespace ct
 			SPtr<Texture> preIntegratedGF;
 			SPtr<Texture> ambientOcclusion;
 			SPtr<Texture> ssr;
+			SPtr<Texture> msaaCoverage;
 		};
 
 		TiledDeferredImageBasedLightingMat();
@@ -161,6 +162,7 @@ namespace bs { namespace ct
 		GpuParamTexture mGBufferDepth;
 
 		GpuParamTexture mInColorTextureParam;
+		GpuParamTexture mMSAACoverageTexParam;
 
 		ImageBasedLightingParams mImageBasedParams;
 

+ 8 - 1
Source/RenderBeast/BsLightRendering.cpp

@@ -267,6 +267,9 @@ namespace bs { namespace ct
 		if (params->hasBuffer(GPT_COMPUTE_PROGRAM, "gOutput"))
 			params->getBufferParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputBufferParam);
 
+		if (mSampleCount > 1)
+			params->getTextureParam(GPT_COMPUTE_PROGRAM, "gMSAACoverage", mMSAACoverageTexParam);
+
 		mParamBuffer = gTiledLightingParamDef.createBuffer();
 		mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
 	}
@@ -280,7 +283,8 @@ namespace bs { namespace ct
 	}
 
 	void TiledDeferredLightingMat::execute(const RendererView& view, const VisibleLightData& lightData, 
-		const GBufferTextures& gbuffer, const SPtr<Texture>& lightAccumTex, const SPtr<GpuBuffer>& lightAccumBuffer)
+		const GBufferTextures& gbuffer, const SPtr<Texture>& lightAccumTex, const SPtr<GpuBuffer>& lightAccumBuffer,
+		const SPtr<Texture>& msaaCoverage)
 	{
 		const RendererViewProperties& viewProps = view.getProperties();
 		const RenderSettings& settings = view.getRenderSettings();
@@ -342,7 +346,10 @@ namespace bs { namespace ct
 		mParamsSet->setParamBlockBuffer("PerCamera", view.getPerViewBuffer(), true);
 
 		if (mSampleCount > 1)
+		{
 			mOutputBufferParam.set(lightAccumBuffer);
+			mMSAACoverageTexParam.set(msaaCoverage);
+		}
 		else
 			mOutputTextureParam.set(lightAccumTex);
 

+ 2 - 1
Source/RenderBeast/BsLightRendering.h

@@ -152,7 +152,7 @@ namespace bs { namespace ct
 
 		/** Binds the material for rendering, sets up parameters and executes it. */
 		void execute(const RendererView& view, const VisibleLightData& lightData, const GBufferTextures& gbuffer,
-			const SPtr<Texture>& lightAccumTex, const SPtr<GpuBuffer>& lightAccumBuffer);
+			const SPtr<Texture>& lightAccumTex, const SPtr<GpuBuffer>& lightAccumBuffer, const SPtr<Texture>& msaaCoverage);
 
 		/** Returns the material variation matching the provided parameters. */
 		static TiledDeferredLightingMat* getVariation(UINT32 msaaCount);
@@ -164,6 +164,7 @@ namespace bs { namespace ct
 		GpuParamBuffer mLightBufferParam;
 		GpuParamLoadStoreTexture mOutputTextureParam;
 		GpuParamBuffer mOutputBufferParam;
+		GpuParamTexture mMSAACoverageTexParam;
 
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 

+ 30 - 3
Source/RenderBeast/BsRenderCompositor.cpp

@@ -512,6 +512,13 @@ namespace bs { namespace ct
 		RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[2]);
 
 		const RendererViewProperties& viewProps = inputs.view.getProperties();
+		SPtr<Texture> msaaCoverage;
+		if(viewProps.numSamples > 1)
+		{
+			RCNodeMSAACoverage* coverageNode = static_cast<RCNodeMSAACoverage*>(inputs.inputNodes[3]);
+			msaaCoverage = coverageNode->output->texture;
+		}
+
 		TiledDeferredLightingMat* tiledDeferredMat = TiledDeferredLightingMat::getVariation(viewProps.numSamples);
 
 		GBufferTextures gbuffer;
@@ -529,7 +536,7 @@ namespace bs { namespace ct
 			flattenedLightAccumBuffer = output->flattenedLightAccumBuffer->buffer;
 
 		tiledDeferredMat->execute(inputs.view, lightData, gbuffer, output->lightAccumulationTex->texture, 
-			flattenedLightAccumBuffer);
+			flattenedLightAccumBuffer, msaaCoverage);
 	}
 
 	void RCNodeTiledDeferredLighting::clear()
@@ -539,7 +546,15 @@ namespace bs { namespace ct
 
 	SmallVector<StringID, 4> RCNodeTiledDeferredLighting::getDependencies(const RendererView& view)
 	{
-		return { RCNodeLightAccumulation::getNodeId(), RCNodeGBuffer::getNodeId(), RCNodeSceneDepth::getNodeId() };
+		SmallVector<StringID, 4> deps;
+		deps.push_back(RCNodeLightAccumulation::getNodeId());
+		deps.push_back(RCNodeGBuffer::getNodeId());
+		deps.push_back(RCNodeSceneDepth::getNodeId());
+
+		if(view.getProperties().numSamples > 1)
+			deps.push_back(RCNodeMSAACoverage::getNodeId());
+
+		return deps;
 	}
 
 	void RCNodeStandardDeferredLighting::render(const RenderCompositorNodeInputs& inputs)
@@ -789,16 +804,24 @@ namespace bs { namespace ct
 		else
 			ssr = Texture::BLACK;
 
+		UINT32 nodeIdx = 6;
 		SPtr<Texture> ssao;
 		if (rs.ambientOcclusion.enabled)
 		{
-			RCNodeSSAO* ssaoNode = static_cast<RCNodeSSAO*>(inputs.inputNodes[6]);
+			RCNodeSSAO* ssaoNode = static_cast<RCNodeSSAO*>(inputs.inputNodes[nodeIdx++]);
 			ssao = ssaoNode->output->texture;
 		}
 		else
 			ssao = Texture::WHITE;
 
 		const RendererViewProperties& viewProps = inputs.view.getProperties();
+		SPtr<Texture> msaaCoverage;
+		if(viewProps.numSamples > 1)
+		{
+			RCNodeMSAACoverage* coverageNode = static_cast<RCNodeMSAACoverage*>(inputs.inputNodes[nodeIdx++]);
+			msaaCoverage = coverageNode->output->texture;
+		}
+
 		TiledDeferredImageBasedLightingMat* material = TiledDeferredImageBasedLightingMat::getVariation(viewProps.numSamples);
 
 		TiledDeferredImageBasedLightingMat::Inputs iblInputs;
@@ -811,6 +834,7 @@ namespace bs { namespace ct
 		iblInputs.preIntegratedGF = RendererTextures::preintegratedEnvGF;
 		iblInputs.ambientOcclusion = ssao;
 		iblInputs.ssr = ssr;
+		iblInputs.msaaCoverage = msaaCoverage;
 
 		if(sceneColorNode->flattenedSceneColorBuffer)
 			iblInputs.sceneColorBuffer = sceneColorNode->flattenedSceneColorBuffer->buffer;
@@ -837,6 +861,9 @@ namespace bs { namespace ct
 		if(view.getRenderSettings().ambientOcclusion.enabled)
 			deps.push_back(RCNodeSSAO::getNodeId());
 
+		if(view.getProperties().numSamples > 1)
+			deps.push_back(RCNodeMSAACoverage::getNodeId());
+
 		return deps;
 	}