Forráskód Böngészése

More SSAO related fixes

BearishSun 8 éve
szülő
commit
966805cfcb

+ 35 - 5
Data/Raw/Engine/Shaders/PPSSAO.bsl

@@ -105,7 +105,7 @@ technique PPSSAO
 			return weightedSum / weightSum;
 			return weightedSum / weightSum;
 		}
 		}
 		
 		
-		float4 fsmain(VStoFS input) : SV_Target0
+		float4 fsmain(VStoFS input, float4 pixelPos : SV_Position) : SV_Target0
 		{
 		{
 			// TODO - Support MSAA (most likely don't require all samples)
 			// TODO - Support MSAA (most likely don't require all samples)
 		
 		
@@ -163,15 +163,20 @@ technique PPSSAO
 				{
 				{
 					float scale = j / (float)SAMPLE_STEPS;
 					float scale = j / (float)SAMPLE_STEPS;
 					
 					
-					float2 screenPosL = input.screenPos + sampleOffset;
-					float2 screenPosR = input.screenPos - sampleOffset;
+					float2 screenPosL = input.screenPos + sampleOffset * scale;
+					float2 screenPosR = input.screenPos - sampleOffset * scale;
 					
 					
 					// TODO - Sample HiZ here to minimize cache trashing (depending on quality)
 					// TODO - Sample HiZ here to minimize cache trashing (depending on quality)
+					#if FINAL_AO // Final uses gbuffer input
 					float depthL = gDepthTex.Sample(gInputSamp, ndcToDepthUV(screenPosL)).r;
 					float depthL = gDepthTex.Sample(gInputSamp, ndcToDepthUV(screenPosL)).r;
 					float depthR = gDepthTex.Sample(gInputSamp, ndcToDepthUV(screenPosR)).r;
 					float depthR = gDepthTex.Sample(gInputSamp, ndcToDepthUV(screenPosR)).r;
 					
 					
 					depthL = convertFromDeviceZ(depthL);
 					depthL = convertFromDeviceZ(depthL);
 					depthR = convertFromDeviceZ(depthR);
 					depthR = convertFromDeviceZ(depthR);
+					#else
+					float depthL = gSetupAO.Sample(gInputSamp, ndcToDepthUV(screenPosL)).w;
+					float depthR = gSetupAO.Sample(gInputSamp, ndcToDepthUV(screenPosR)).w;
+					#endif
 					
 					
 					float3 viewPosL = getViewSpacePos(screenPosL, depthL);
 					float3 viewPosL = getViewSpacePos(screenPosL, depthL);
 					float3 viewPosR = getViewSpacePos(screenPosR, depthR);
 					float3 viewPosR = getViewSpacePos(screenPosR, depthR);
@@ -182,6 +187,7 @@ technique PPSSAO
 					float angleL = saturate(dot(diffL, viewNormal) * rsqrt(dot(diffL, diffL)));
 					float angleL = saturate(dot(diffL, viewNormal) * rsqrt(dot(diffL, diffL)));
 					float angleR = saturate(dot(diffR, viewNormal) * rsqrt(dot(diffR, diffR)));
 					float angleR = saturate(dot(diffR, viewNormal) * rsqrt(dot(diffR, diffR)));
 					
 					
+					// Avoid blending if depths are too different to avoid leaking
 					float weight = saturate(1.0f - length(diffL) * invRange);
 					float weight = saturate(1.0f - length(diffL) * invRange);
 					weight *= saturate(1.0f - length(diffR) * invRange);
 					weight *= saturate(1.0f - length(diffR) * invRange);
 					
 					
@@ -219,8 +225,32 @@ technique PPSSAO
 			// TODO - Adjust power/intensity
 			// TODO - Adjust power/intensity
 			#endif
 			#endif
 			
 			
-			// TODO - Perform filtering over 2x2 pixels using derivatives (on quality levels with no upsampling)
-			return output;
+			// Perform a 2x2 ad-hoc blur to hide the dither pattern
+			// Note: Ideally the blur would be 4x4 since the pattern is 4x4
+			
+			// TODO - Don't blur on minimal quality level
+			float4 myVal = float4(output.r, viewNormal);
+			float4 dX = ddx_fine(myVal);
+			float4 dY = ddy_fine(myVal);
+			
+			int2 mod = (int2)(pixelPos.xy) % 2;
+			float4 horzVal = myVal - dX * (mod.x * 2 - 1);
+			float4 vertVal = myVal - dY * (mod.y * 2 - 1);
+			
+			// Do weighted average depending on how similar the normals are
+			float weightHorz = saturate(pow(saturate(dot(viewNormal, horzVal.yzw)), 4.0f));
+			float weightVert = saturate(pow(saturate(dot(viewNormal, vertVal.yzw)), 4.0f));
+			
+			float myWeight = 1.0f;
+			float invWeight = 1.0f / (myWeight + weightHorz + weightVert);
+			
+			myWeight *= invWeight;
+			weightHorz *= invWeight;
+			weightVert *= invWeight;
+			
+			output.r = output.r * myWeight + horzVal.r * weightHorz + vertVal.r * weightVert;
+			
+			return output; // TODO - No need to output 4 values
 		}	
 		}	
 	};
 	};
 };
 };

+ 2 - 2
Source/BansheeEngine/Include/BsStandardPostProcessSettings.h

@@ -210,8 +210,8 @@ namespace bs
 		/** 
 		/** 
 		 * Radius (in world space, in meters) over which occluders are searched for. Smaller radius ensures better sampling
 		 * Radius (in world space, in meters) over which occluders are searched for. Smaller radius ensures better sampling
 		 * precision but can miss occluders. Larger radius ensures far away occluders are considered but can yield lower
 		 * precision but can miss occluders. Larger radius ensures far away occluders are considered but can yield lower
-		 * quality or noise because of low sampling precision. Usually best to keep at around a few centimeters, valid range
-		 * is roughly [0.005, 0.5].
+		 * quality or noise because of low sampling precision. Usually best to keep at around a meter, valid range
+		 * is roughly [0.05, 5.0].
 		 */
 		 */
 		float radius;
 		float radius;
 
 

+ 1 - 1
Source/BansheeEngine/Source/BsStandardPostProcessSettings.cpp

@@ -66,7 +66,7 @@ namespace bs
 	}
 	}
 
 
 	AmbientOcclusionSettings::AmbientOcclusionSettings()
 	AmbientOcclusionSettings::AmbientOcclusionSettings()
-		: enabled(false), radius(0.03f), bias(1.0f)
+		: enabled(true), radius(1.5f), bias(1.0f)
 	{ }
 	{ }
 
 
 	RTTITypeBase* AmbientOcclusionSettings::getRTTIStatic()
 	RTTITypeBase* AmbientOcclusionSettings::getRTTIStatic()

+ 33 - 7
Source/RenderBeast/Source/BsPostProcessing.cpp

@@ -1150,7 +1150,12 @@ namespace bs { namespace ct
 	void SSAOMat<UPSAMPLE, FINAL_PASS, QUALITY>::execute(const RendererView& view, const SSAOTextureInputs& textures, 
 	void SSAOMat<UPSAMPLE, FINAL_PASS, QUALITY>::execute(const RendererView& view, const SSAOTextureInputs& textures, 
 		const SPtr<RenderTexture>& destination, const AmbientOcclusionSettings& settings)
 		const SPtr<RenderTexture>& destination, const AmbientOcclusionSettings& settings)
 	{
 	{
+		// Scale that can be used to adjust how quickly does AO radius increase with downsampled AO. This yields a very
+		// small AO radius at highest level, and very large radius at lowest level
+		static const float DOWNSAMPLE_SCALE = 4.0f;
+
 		const RendererViewProperties& viewProps = view.getProperties();
 		const RendererViewProperties& viewProps = view.getProperties();
+		const RenderTargetProperties& rtProps = destination->getProperties();
 
 
 		Vector2 tanHalfFOV;
 		Vector2 tanHalfFOV;
 		tanHalfFOV.x = 1.0f / viewProps.projTransform[0][0];
 		tanHalfFOV.x = 1.0f / viewProps.projTransform[0][0];
@@ -1158,11 +1163,26 @@ namespace bs { namespace ct
 
 
 		float cotHalfFOV = viewProps.projTransform[0][0];
 		float cotHalfFOV = viewProps.projTransform[0][0];
 
 
-		gSSAOParamDef.gSampleRadius.set(mParamBuffer, settings.radius);
+		// Downsampled AO uses a larger AO radius (in higher resolutions this would cause too much cache trashing). This
+		// means if only full res AO is used, then only AO from nearby geometry will be calculated.
+		float viewScale = viewProps.viewRect.width / (float)rtProps.getWidth();
+
+		// Ramp up the radius exponentially. c^log2(x) function chosen arbitrarily, as it ramps up the radius in a nice way
+		float scale = pow(DOWNSAMPLE_SCALE, Math::log2(viewScale)); 
+
+		// Determine maximum radius scale (division by 4 because we don't downsample more than quarter-size)
+		float maxScale = pow(DOWNSAMPLE_SCALE, Math::log2(4.0f));
+
+		// Normalize the scale in [0, 1] range
+		scale /= maxScale;
+
+		float radius = settings.radius * scale;
+
+		gSSAOParamDef.gSampleRadius.set(mParamBuffer, radius);
 		gSSAOParamDef.gCotHalfFOV.set(mParamBuffer, cotHalfFOV);
 		gSSAOParamDef.gCotHalfFOV.set(mParamBuffer, cotHalfFOV);
 		gSSAOParamDef.gTanHalfFOV.set(mParamBuffer, tanHalfFOV);
 		gSSAOParamDef.gTanHalfFOV.set(mParamBuffer, tanHalfFOV);
 		gSSAOParamDef.gWorldSpaceRadiusMask.set(mParamBuffer, 1.0f);
 		gSSAOParamDef.gWorldSpaceRadiusMask.set(mParamBuffer, 1.0f);
-		gSSAOParamDef.gBias.set(mParamBuffer, settings.bias / 1000.0f);
+		gSSAOParamDef.gBias.set(mParamBuffer, (settings.bias * viewScale) / 1000.0f);
 		
 		
 		if(UPSAMPLE)
 		if(UPSAMPLE)
 		{
 		{
@@ -1181,8 +1201,8 @@ namespace bs { namespace ct
 		UINT32 rndHeight = rndProps.getHeight();
 		UINT32 rndHeight = rndProps.getHeight();
 
 
 		//// Multiple of random texture size, rounded up
 		//// Multiple of random texture size, rounded up
-		UINT32 scaleWidth = (viewProps.viewRect.width + rndWidth - 1) / rndWidth;
-		UINT32 scaleHeight = (viewProps.viewRect.height + rndHeight - 1) / rndHeight;
+		UINT32 scaleWidth = (rtProps.getWidth() + rndWidth - 1) / rndWidth;
+		UINT32 scaleHeight = (rtProps.getHeight() + rndHeight - 1) / rndHeight;
 
 
 		Vector2 randomTileScale((float)scaleWidth, (float)scaleHeight);
 		Vector2 randomTileScale((float)scaleWidth, (float)scaleHeight);
 		gSSAOParamDef.gRandomTileScale.set(mParamBuffer, randomTileScale);
 		gSSAOParamDef.gRandomTileScale.set(mParamBuffer, randomTileScale);
@@ -1286,6 +1306,7 @@ namespace bs { namespace ct
 		SPtr<Texture> sceneNormals = renderTargets->get(RTT_GBuffer, RT_COLOR1);
 		SPtr<Texture> sceneNormals = renderTargets->get(RTT_GBuffer, RT_COLOR1);
 
 
 		// TODO - Resolve normals if MSAA
 		// TODO - Resolve normals if MSAA
+		// TODO - When downsampling, consider using previous pass as input instead of always sampling gbuffer data
 
 
 		UINT32 numDownsampleLevels = 1; // TODO - Make it a property, ranging [0, 2]
 		UINT32 numDownsampleLevels = 1; // TODO - Make it a property, ranging [0, 2]
 		UINT32 quality = 1; // TODO - Make it a property
 		UINT32 quality = 1; // TODO - Make it a property
@@ -1349,7 +1370,9 @@ namespace bs { namespace ct
 		if(numDownsampleLevels > 0)
 		if(numDownsampleLevels > 0)
 		{
 		{
 			textures.aoSetup = setupTex0->texture;
 			textures.aoSetup = setupTex0->texture;
-			textures.aoDownsampled = downAOTex1->texture;
+
+			if(downAOTex1)
+				textures.aoDownsampled = downAOTex1->texture;
 
 
 			Vector2I downsampledSize(
 			Vector2I downsampledSize(
 				std::max(1, Math::divideAndRoundUp(viewProps.viewRect.width, 2)),
 				std::max(1, Math::divideAndRoundUp(viewProps.viewRect.width, 2)),
@@ -1371,8 +1394,11 @@ namespace bs { namespace ct
 		}
 		}
 
 
 		{
 		{
-			textures.aoSetup = setupTex0->texture;
-			textures.aoDownsampled = downAOTex0->texture;
+			if(setupTex0)
+				textures.aoSetup = setupTex0->texture;
+
+			if(downAOTex0)
+				textures.aoDownsampled = downAOTex0->texture;
 
 
 			bool upsample = numDownsampleLevels > 0;
 			bool upsample = numDownsampleLevels > 0;
 			executeSSAOMat(upsample, true, quality, view, textures, destination, settings);
 			executeSSAOMat(upsample, true, quality, view, textures, destination, settings);

+ 27 - 2
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -633,8 +633,16 @@ namespace bs { namespace ct
 		renderTargets->allocate(RTT_SceneColor);
 		renderTargets->allocate(RTT_SceneColor);
 		imageBasedLightingMat->execute(renderTargets, perCameraBuffer, mPreintegratedEnvBRDF);
 		imageBasedLightingMat->execute(renderTargets, perCameraBuffer, mPreintegratedEnvBRDF);
 
 
-		if (useSSAO)
-			renderTargets->release(RTT_AmbientOcclusion);
+
+
+
+		// DEBUG ONLY
+		//if (useSSAO)
+		//	renderTargets->release(RTT_AmbientOcclusion);
+
+
+
+
 
 
 		renderTargets->release(RTT_LightAccumulation);
 		renderTargets->release(RTT_LightAccumulation);
 		renderTargets->release(RTT_GBuffer);
 		renderTargets->release(RTT_GBuffer);
@@ -718,6 +726,23 @@ namespace bs { namespace ct
 		if (isMSAA)
 		if (isMSAA)
 			renderTargets->release(RTT_ResolvedDepth);
 			renderTargets->release(RTT_ResolvedDepth);
 
 
+
+
+
+
+		// DEBUG ONLY
+		if(useSSAO)
+		{
+			rapi.setRenderTarget(viewInfo->getProperties().target);
+			gRendererUtility().blit(renderTargets->get(RTT_AmbientOcclusion));
+
+			renderTargets->release(RTT_AmbientOcclusion);
+		}
+
+
+
+
+
 		// Trigger overlay callbacks
 		// Trigger overlay callbacks
 		if (viewProps.triggerCallbacks)
 		if (viewProps.triggerCallbacks)
 		{
 		{