Просмотр исходного кода

Added rotation randomization in SSAO shader, in order to reduce banding

BearishSun 8 лет назад
Родитель
Сommit
047238cb55

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

@@ -11,11 +11,10 @@ technique PPSSAO
 		[internal]
 		cbuffer Input
 		{
-			float4x4 gMixedToView;
-		
 			float gSampleRadius;
 			float gWorldSpaceRadiusMask;
 			float2 gTanHalfFOV; // x - horz FOV, y - vert FOV
+			float2 gRandomTileScale;
 			float gCotHalfFOV;
 		}		
 
@@ -23,9 +22,12 @@ technique PPSSAO
 		Texture2D gDepthTex;
 		Texture2D gNormalsTex;
 		
+		SamplerState gRandomSamp;
+		Texture2D gRandomTex;
+		
 		// TODO - Allow these to be controlled by a quality level
 		#define SAMPLE_COUNT 6
-		#define SAMPLE_STEPS 20
+		#define SAMPLE_STEPS 3
 		
 		static const float2 SAMPLES[6] =
 		{
@@ -77,8 +79,9 @@ technique PPSSAO
 			float sampleRadius = gSampleRadius * lerp(-sceneDepth, 1, gWorldSpaceRadiusMask) * gCotHalfFOV / -sceneDepth;
 			
 			// TODO - Apply bias to viewposition (and reconstruct screen pos from it)
-			// TODO - Get random rotation (depending on active quality)
-			float2 rotateDir = float2(0, 1);
+
+			// Get random rotation
+			float2 rotateDir = gRandomTex.Sample(gRandomSamp, input.uv0 * gRandomTileScale) * 2 - 1;
 			
 			// Scale by screen space sample radius
 			rotateDir *= sampleRadius;

+ 13 - 1
Source/BansheeUtility/Include/BsBitwise.h

@@ -144,7 +144,7 @@ namespace bs
 		}
 
 		/** 
-		 * Convert N bit colour channel value to P bits. It fills P bits with the bit pattern repeated. 
+		 * Convert N bit color channel value to P bits. It fills P bits with the bit pattern repeated. 
 		 * (this is /((1<<n)-1) in fixed point).
 		 */
 		static unsigned int fixedToFixed(UINT32 value, unsigned int n, unsigned int p)
@@ -492,6 +492,18 @@ namespace bs
 
 			return *(float*)&output;
 		}
+
+		/** Converts a float in range [-1,1] into an unsigned 8-bit integer. */
+		static UINT8 quantize8BitSigned(float v)
+		{
+			return quantize8BitUnsigned(v * 0.5f + 0.5f);
+		}
+
+		/** Converts a float in range [0,1] into an unsigned 8-bit integer. */
+		static UINT8 quantize8BitUnsigned(float v)
+		{
+			return (UINT8)(v * 255.999f);
+		}
 	};
 
 	/** @} */

+ 14 - 3
Source/RenderBeast/Include/BsPostProcessing.h

@@ -584,10 +584,10 @@ namespace bs { namespace ct
 	};
 
 	BS_PARAM_BLOCK_BEGIN(SSAOParamDef)
-		BS_PARAM_BLOCK_ENTRY(Matrix4, gMixedToView)
 		BS_PARAM_BLOCK_ENTRY(float, gSampleRadius)
 		BS_PARAM_BLOCK_ENTRY(float, gWorldSpaceRadiusMask)
 		BS_PARAM_BLOCK_ENTRY(Vector2, gTanHalfFOV)
+		BS_PARAM_BLOCK_ENTRY(Vector2, gRandomTileScale)
 		BS_PARAM_BLOCK_ENTRY(float, gCotHalfFOV)
 	BS_PARAM_BLOCK_END
 
@@ -607,16 +607,23 @@ namespace bs { namespace ct
 		 * @param[in]	view			Information about the view we're rendering from.
 		 * @param[in]	sceneDepth		Input texture containing scene depth.
 		 * @param[in]	sceneNormals	Input texture containing scene world space normals.
+		 * @param[in]	randomRotations	Tileable texture containing random rotations that will be applied to AO samples.
 		 * @param[in]	destination		Output texture to which to write the ambient occlusion data to.
 		 */
 		void execute(const RendererView& view, const SPtr<Texture>& sceneDepth, const SPtr<Texture>& sceneNormals, 
-			const SPtr<RenderTexture>& destination);
+			const SPtr<Texture>& randomRotations, const SPtr<RenderTexture>& destination);
+
+		/**
+		 * Generates a texture that is used for randomizing sample locations during SSAO calculation. The texture contains
+		 * 16 different rotations in a 4x4 tile.
+		 */
+		SPtr<Texture> generate4x4RandomizationTexture() const;
 
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		GpuParamTexture mDepthTexture;
 		GpuParamTexture mNormalsTexture;
-		GpuParamSampState mInputSampState;
+		GpuParamTexture mRandomTexture;
 	};
 
 	/**
@@ -627,6 +634,8 @@ namespace bs { namespace ct
 	class PostProcessing : public Module<PostProcessing>
 	{
 	public:
+		PostProcessing();
+
 		/** 
 		 * Renders post-processing effects for the provided render target. Resolves provided scene color texture into the
 		 * view's final output render target. Once the method exits, final render target is guaranteed to be currently
@@ -645,6 +654,8 @@ namespace bs { namespace ct
 		GaussianDOF mGaussianDOF;
 		FXAAMat mFXAA;
 		SSAOMat mSSAO;
+
+		SPtr<Texture> mSSAORandomizationTex;
 	};
 
 	/** @} */

+ 69 - 26
Source/RenderBeast/Source/BsPostProcessing.cpp

@@ -1142,17 +1142,29 @@ namespace bs { namespace ct
 		SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
 		gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDepthTex", mDepthTexture);
 		gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gNormalsTex", mNormalsTexture);
-
-		SAMPLER_STATE_DESC desc;
-		desc.minFilter = FO_POINT;
-		desc.magFilter = FO_POINT;
-		desc.mipFilter = FO_POINT;
-		desc.addressMode.u = TAM_CLAMP;
-		desc.addressMode.v = TAM_CLAMP;
-		desc.addressMode.w = TAM_CLAMP;
-
-		SPtr<SamplerState> sampState = SamplerState::create(desc);
-		gpuParams->setSamplerState(GPT_FRAGMENT_PROGRAM, "gInputSamp", sampState);
+		gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gRandomTex", mRandomTexture);
+
+		SAMPLER_STATE_DESC inputSampDesc;
+		inputSampDesc.minFilter = FO_POINT;
+		inputSampDesc.magFilter = FO_POINT;
+		inputSampDesc.mipFilter = FO_POINT;
+		inputSampDesc.addressMode.u = TAM_CLAMP;
+		inputSampDesc.addressMode.v = TAM_CLAMP;
+		inputSampDesc.addressMode.w = TAM_CLAMP;
+
+		SPtr<SamplerState> inputSampState = SamplerState::create(inputSampDesc);
+		gpuParams->setSamplerState(GPT_FRAGMENT_PROGRAM, "gInputSamp", inputSampState);
+
+		SAMPLER_STATE_DESC randomSampDesc;
+		randomSampDesc.minFilter = FO_POINT;
+		randomSampDesc.magFilter = FO_POINT;
+		randomSampDesc.mipFilter = FO_POINT;
+		randomSampDesc.addressMode.u = TAM_WRAP;
+		randomSampDesc.addressMode.v = TAM_WRAP;
+		randomSampDesc.addressMode.w = TAM_WRAP;
+
+		SPtr<SamplerState> randomSampState = SamplerState::create(inputSampDesc);
+		gpuParams->setSamplerState(GPT_FRAGMENT_PROGRAM, "gRandomSamp", randomSampState);
 	}
 
 	void SSAOMat::_initDefines(ShaderDefines& defines)
@@ -1161,7 +1173,7 @@ namespace bs { namespace ct
 	}
 
 	void SSAOMat::execute(const RendererView& view, const SPtr<Texture>& depth, const SPtr<Texture>& normals, 
-		const SPtr<RenderTexture>& destination)
+		const SPtr<Texture>& random, const SPtr<RenderTexture>& destination)
 	{
 		const RendererViewProperties& viewProps = view.getProperties();
 
@@ -1177,23 +1189,21 @@ namespace bs { namespace ct
 		gSSAOParamDef.gTanHalfFOV.set(mParamBuffer, tanHalfFOV);
 		gSSAOParamDef.gWorldSpaceRadiusMask.set(mParamBuffer, 1.0f);
 
-		// Construct a special inverse view-projection matrix that had projection entries that effect z and w eliminated.
-		// Used to transform a vector(clip_x, clip_y, view_z, view_w), where clip_x/clip_y are in clip space, and 
-		// view_z/view_w in view space, into world space.
+		// Generate a scale which we need to use in order to achieve tiling
+		const TextureProperties& rndProps = random->getProperties();
+		UINT32 rndWidth = rndProps.getWidth();
+		UINT32 rndHeight = rndProps.getHeight();
 
-		// Only projects z/w coordinates (cancels out with the inverse matrix below)
-		Matrix4 projZ = Matrix4::IDENTITY;
-		projZ[2][2] = viewProps.projTransform[2][2];
-		projZ[2][3] = viewProps.projTransform[2][3];
-		projZ[3][2] = viewProps.projTransform[3][2];
-		projZ[3][3] = 0.0f;
+		//// Multiple of random texture size, rounded up
+		UINT32 scaleWidth = (viewProps.viewRect.width + rndWidth - 1) / rndWidth;
+		UINT32 scaleHeight = (viewProps.viewRect.height + rndHeight - 1) / rndHeight;
 
-		Matrix4 xyProj = viewProps.projTransform.inverse() * projZ;
-		
-		gSSAOParamDef.gMixedToView.set(mParamBuffer, xyProj);
+		Vector2 randomTileScale((float)scaleWidth, (float)scaleHeight);
+		gSSAOParamDef.gRandomTileScale.set(mParamBuffer, randomTileScale);
 
 		mDepthTexture.set(depth);
 		mNormalsTexture.set(normals);
+		mRandomTexture.set(random);
 
 		SPtr<GpuParamBlockBuffer> perView = view.getPerViewBuffer();
 		mParamsSet->setParamBlockBuffer("PerCamera", perView);
@@ -1204,7 +1214,39 @@ namespace bs { namespace ct
 		gRendererUtility().setPass(mMaterial);
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().drawScreenQuad();
-}
+	}
+
+	SPtr<Texture> SSAOMat::generate4x4RandomizationTexture() const
+	{
+		UINT32 mapping[16] = { 13, 5, 1, 9, 14, 3, 7, 11, 15, 2, 6, 12, 4, 8, 0, 10 };
+		Vector2 bases[16];
+		for (UINT32 i = 0; i < 16; ++i)
+		{
+			float angle = (mapping[i] / 16.0f) * Math::PI;
+			bases[i].x = cos(angle);
+			bases[i].y = sin(angle);
+		}
+
+		SPtr<PixelData> pixelData = PixelData::create(4, 4, 1, PF_R8G8);
+		for(UINT32 y = 0; y < 4; ++y)
+			for(UINT32 x = 0; x < 4; ++x)
+			{
+				UINT32 base = (y * 4) + x;
+
+				Color color;
+				color.r = bases[base].x * 0.5f + 0.5f;
+				color.g = bases[base].y * 0.5f + 0.5f;
+
+				pixelData->setColorAt(color, x, y);
+			}
+
+		return Texture::create(pixelData);
+	}
+
+	PostProcessing::PostProcessing()
+	{
+		mSSAORandomizationTex = mSSAO.generate4x4RandomizationTexture();
+	}
 
 	void PostProcessing::postProcess(RendererView* viewInfo, const SPtr<RenderTargets>& renderTargets, float frameDelta)
 	{
@@ -1224,7 +1266,8 @@ namespace bs { namespace ct
 		//	POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, viewProps.viewRect.width, viewProps.viewRect.height, 
 		//	TU_RENDERTARGET));
 
-		//mSSAO.execute(*viewInfo, renderTargets->getSceneDepth(), renderTargets->getGBufferB(), temp->renderTexture);
+		//mSSAO.execute(*viewInfo, renderTargets->getSceneDepth(), renderTargets->getGBufferB(), mSSAORandomizationTex, 
+		//	temp->renderTexture);
 		// END DEBUG ONLY
 
 		if(hdr && settings.enableAutoExposure)