Quellcode durchsuchen

Bulk of work implemented for Gaussian DOF

BearishSun vor 8 Jahren
Ursprung
Commit
0f42cf8dbc

+ 8 - 0
Data/Raw/Engine/DataList.json

@@ -139,6 +139,10 @@
         {
         {
             "Path": "ShadowProjectionCommon.bslinc",
             "Path": "ShadowProjectionCommon.bslinc",
             "UUID": "36da8807-b201-482b-b320-96f5300d1751"
             "UUID": "36da8807-b201-482b-b320-96f5300d1751"
+        },
+        {
+            "Path": "PPGaussianDOFCommon.bslinc",
+            "UUID": "78521453-a352-4fd8-b997-8e58942dee2d"
         }
         }
     ],
     ],
     "Shaders": [
     "Shaders": [
@@ -297,6 +301,10 @@
         {
         {
             "Path": "PPGaussianDOFSeparate.bsl",
             "Path": "PPGaussianDOFSeparate.bsl",
             "UUID": "78285aaa-a862-46f3-837c-d13abbe8b351"
             "UUID": "78285aaa-a862-46f3-837c-d13abbe8b351"
+        },
+        {
+            "Path": "PPGaussianDOFCombine.bsl",
+            "UUID": "2743e8f1-97cf-4441-b9e4-aad280343901"
         }
         }
     ],
     ],
     "Skin": [
     "Skin": [

+ 29 - 0
Data/Raw/Engine/Includes/PPGaussianDOFCommon.bslinc

@@ -0,0 +1,29 @@
+#include "$ENGINE$\PerCameraData.bslinc"
+
+mixin PPGaussianDOFCommon
+{
+	mixin PerCameraData;
+
+	code
+	{
+		[internal]
+		cbuffer Input
+		{
+			float gNearBlurPlane;
+			float gFarBlurPlane;
+			float gInvNearBlurRange;
+			float gInvFarBlurRange;
+			float2 gHalfPixelOffset;
+		}		
+		
+		float calcNearMask(float depth)
+		{
+			return saturate((gNearBlurPlane - depth) * gInvNearBlurRange);
+		}
+		
+		float calcFarMask(float depth)
+		{
+			return saturate((depth - gFarBlurPlane) * gInvFarBlurRange);
+		}
+	};
+};

+ 62 - 0
Data/Raw/Engine/Shaders/PPGaussianDOFCombine.bsl

@@ -0,0 +1,62 @@
+#include "$ENGINE$\PPBase.bslinc"
+#include "$ENGINE$\PPGaussianDOFCommon.bslinc"
+
+technique PPGaussianDOFCombine
+{
+	mixin PPBase;
+	mixin PPGaussianDOFCommon;
+	
+	code
+	{
+		SamplerState gColorSamp;
+		Texture2D gFocusedTex;
+		Texture2D gNearTex;
+		Texture2D gFarTex;
+		
+		SamplerState gDepthSamp;
+		Texture2D gDepthTex;
+
+		float3 fsmain(VStoFS input) : SV_Target0
+		{
+			float4 focusedColor = gFocusedTex.Sample(gColorSamp, input.uv0);
+			float depth = convertFromDeviceZ(gDepthTex.Sample(gDepthSamp, input.uv0));
+			
+			float4 nearColor = 0;
+			float4 farColor = 0;
+			
+			float bias = 0.00001f; // To avoid div by zero
+			#if NEAR
+				nearColor = gNearTex.Sample(gColorSamp, input.uv0);
+				nearColor.rgb /= (nearColor.a + bias);
+			#endif
+			#if FAR
+				farColor = gFarTex.Sample(gColorSamp, input.uv0);
+				farColor.rgb /= (farColor.a + bias);
+			#endif
+			
+			float3 combined;
+			
+			// Background layer
+			combined = farColor.rgb;
+			
+			// Focused layer
+			//// This uses value of background layer as long as the background mask strength is
+			//// higher than 0.2f. For strength lower than 0.2f it blends with the focused layer.
+			float focusedMask = calcFarMask(depth);
+			focusedMask = saturate(1.0f - focusedMask * 5.0f);
+			focusedMask *= focusedMask;
+			
+			combined = lerp(combined, focusedColor.rgb, focusedMask);
+			
+			// Foreground layer
+			//// Same type of blending as with the layer above
+			float foregroundMask = calcNearMask(depth);
+			foregroundMask = saturate(1.0f - foregroundMask * 5.0f);
+			foregroundMask *= foregroundMask;
+			
+			combined = lerp(combined, nearColor.rgb, foregroundMask);
+			
+			return combined;
+		}	
+	};
+};

+ 4 - 24
Data/Raw/Engine/Shaders/PPGaussianDOFSeparate.bsl

@@ -1,39 +1,19 @@
 #include "$ENGINE$\PPBase.bslinc"
 #include "$ENGINE$\PPBase.bslinc"
-#include "$ENGINE$\PerCameraData.bslinc"
+#include "$ENGINE$\PPGaussianDOFCommon.bslinc"
 
 
 technique PPGaussianDOFSeparate
 technique PPGaussianDOFSeparate
 {
 {
 	mixin PPBase;
 	mixin PPBase;
-	mixin PerCameraData;
+	mixin PPGaussianDOFCommon;
 
 
 	code
 	code
 	{
 	{
-		[internal]
-		cbuffer Input
-		{
-			float gNearBlurPlane;
-			float gFarBlurPlane;
-			float gInvNearBlurRange;
-			float gInvFarBlurRange;
-			float2 gHalfPixelOffset;
-		}		
-
 		SamplerState gColorSamp;
 		SamplerState gColorSamp;
 		Texture2D gColorTex;
 		Texture2D gColorTex;
 		
 		
 		SamplerState gDepthSamp;
 		SamplerState gDepthSamp;
 		Texture2D gDepthTex;
 		Texture2D gDepthTex;
-		
-		float calcNearMask(float depth)
-		{
-			return saturate((gNearBlurPlane - depth) * gInvNearBlurRange);
-		}
-		
-		float calcFarMask(float depth)
-		{
-			return saturate((gFarBlurPlane - depth) * gInvFarBlurRange);
-		}
-		
+
 		void addSample(float2 uv, float2 offset, float depth, inout float4 nearColor, inout float4 farColor)
 		void addSample(float2 uv, float2 offset, float depth, inout float4 nearColor, inout float4 farColor)
 		{
 		{
 			float4 smp;
 			float4 smp;
@@ -52,7 +32,7 @@ technique PPGaussianDOFSeparate
 			VStoFS input,
 			VStoFS input,
 			out float4 output0 : SV_Target0
 			out float4 output0 : SV_Target0
 			#if NEAR_AND_FAR
 			#if NEAR_AND_FAR
-			out float4 output1 : SV_Target1
+			, out float4 output1 : SV_Target1
 			#endif
 			#endif
 			)
 			)
 		{
 		{

+ 119 - 19
Source/RenderBeast/Include/BsPostProcessing.h

@@ -349,7 +349,7 @@ namespace bs { namespace ct
 		GpuParamTexture mInputTexture;
 		GpuParamTexture mInputTexture;
 	};
 	};
 
 
-	BS_PARAM_BLOCK_BEGIN(GaussianDOFSeparateParamDef)
+	BS_PARAM_BLOCK_BEGIN(GaussianDOFParamDef)
 		BS_PARAM_BLOCK_ENTRY(float, gNearBlurPlane)
 		BS_PARAM_BLOCK_ENTRY(float, gNearBlurPlane)
 		BS_PARAM_BLOCK_ENTRY(float, gFarBlurPlane)
 		BS_PARAM_BLOCK_ENTRY(float, gFarBlurPlane)
 		BS_PARAM_BLOCK_ENTRY(float, gInvNearBlurRange)
 		BS_PARAM_BLOCK_ENTRY(float, gInvNearBlurRange)
@@ -357,7 +357,37 @@ namespace bs { namespace ct
 		BS_PARAM_BLOCK_ENTRY(Vector2, gHalfPixelOffset)
 		BS_PARAM_BLOCK_ENTRY(Vector2, gHalfPixelOffset)
 	BS_PARAM_BLOCK_END
 	BS_PARAM_BLOCK_END
 
 
-	extern GaussianDOFSeparateParamDef sGaussianDOFSeparateParamDef;
+	extern GaussianDOFParamDef sGaussianDOFParamDef;
+
+	/** Common interface for all variations of GaussianDOFSeparateMat. */
+	class IGaussianDOFSeparateMat
+	{
+	public:
+		virtual ~IGaussianDOFSeparateMat() { }
+
+		/** 
+		 * Renders the post-process effect with the provided parameters. 
+		 * 
+		 * @param[in]	color		Input color texture to process.
+		 * @param[in]	depth		Input depth buffer texture that will be used for determining pixel depth.
+		 * @param[in]	view		View through which the depth of field effect is viewed.
+		 * @param[in]	settings	Settings used to control depth of field rendering. 
+		 */
+		virtual void execute(const SPtr<Texture>& color, const SPtr<Texture>& depth, const RendererView& view, 
+			const DepthOfFieldSettings& settings) = 0;
+
+		/**
+		 * Returns the texture generated after the shader was executed. Only valid to call this in-between calls to
+		 * execute() & release(), with @p idx value 0 or 1.
+		 */
+		virtual SPtr<PooledRenderTexture> getOutput(UINT32 idx) = 0;
+
+		/**
+		 * Releases the interally allocated output render textures. Must be called after each call to execute(), when the 
+		 * caller is done using the textures.
+		 */
+		virtual void release() = 0;
+	};
 
 
 	/** 
 	/** 
 	 * Shader that masks pixels from the input color texture into one or two output textures. The masking is done by
 	 * Shader that masks pixels from the input color texture into one or two output textures. The masking is done by
@@ -369,43 +399,112 @@ namespace bs { namespace ct
 	 *					pixels are output to the second render target instead.
 	 *					pixels are output to the second render target instead.
 	 */
 	 */
 	template<bool Near, bool Far>
 	template<bool Near, bool Far>
-	class GaussianDOFSeparateMat : public RendererMaterial<GaussianDOFSeparateMat<Near, Far>>
+	class GaussianDOFSeparateMat : public IGaussianDOFSeparateMat, public RendererMaterial<GaussianDOFSeparateMat<Near, Far>>
 	{
 	{
 		RMAT_DEF("PPGaussianDOFSeparate.bsl");
 		RMAT_DEF("PPGaussianDOFSeparate.bsl");
 
 
 	public:
 	public:
 		GaussianDOFSeparateMat();
 		GaussianDOFSeparateMat();
 
 
+		/** @copydoc IGaussianDOFSeparateMat::execute() */
+		void execute(const SPtr<Texture>& color, const SPtr<Texture>& depth, const RendererView& view, 
+			const DepthOfFieldSettings& settings) override;
+
+		/** @copydoc IGaussianDOFSeparateMat::getOutput() */
+		SPtr<PooledRenderTexture> getOutput(UINT32 idx) override;
+
+		/** @copydoc IGaussianDOFSeparateMat::release() */
+		void release() override;
+
+	private:
+		SPtr<GpuParamBlockBuffer> mParamBuffer;
+		GpuParamTexture mColorTexture;
+		GpuParamTexture mDepthTexture;
+
+		SPtr<PooledRenderTexture> mOutput0;
+		SPtr<PooledRenderTexture> mOutput1;
+	};
+
+	/** Common interface for all variations of GaussianDOFCombineMat. */
+	class IGaussianDOFCombineMat
+	{
+	public:
+		virtual ~IGaussianDOFCombineMat() { }
+
 		/** 
 		/** 
 		 * Renders the post-process effect with the provided parameters. 
 		 * Renders the post-process effect with the provided parameters. 
 		 * 
 		 * 
-		 * @param[in]	color		Input color texture to process.
+		 * @param[in]	focused		Input texture containing focused (default) scene color.
+		 * @param[in]	near		Input texture containing filtered (blurred) values for the unfocused foreground area.
+		 *							Can be null if no near plane needs to be blended.
+		 * @param[in]	far			Input texture containing filtered (blurred) values for the unfocused background area.
+		 *							Can be null if no far plane needs to be blended.
 		 * @param[in]	depth		Input depth buffer texture that will be used for determining pixel depth.
 		 * @param[in]	depth		Input depth buffer texture that will be used for determining pixel depth.
+		 * @param[in}	output		Texture to output the results to.
 		 * @param[in]	view		View through which the depth of field effect is viewed.
 		 * @param[in]	view		View through which the depth of field effect is viewed.
 		 * @param[in]	settings	Settings used to control depth of field rendering. 
 		 * @param[in]	settings	Settings used to control depth of field rendering. 
 		 */
 		 */
-		void execute(const SPtr<Texture>& color, const SPtr<Texture>& depth, const RendererView& view, 
-			const DepthOfFieldSettings& settings);
+		virtual void execute(const SPtr<Texture>& focused, const SPtr<Texture>& near, const SPtr<Texture>& far, 
+			const SPtr<Texture>& depth, const SPtr<RenderTarget>& output, const RendererView& view, 
+			const DepthOfFieldSettings& settings) = 0;
+	};
 
 
-		/**
-		 * Returns the texture generated after the shader was executed. Only valid to call this in-between calls to
-		 * execute() & release(), with @p idx value 0 or 1.
-		 */
-		SPtr<Texture> getOutput(UINT32 idx);
+	/** 
+	 * Shader that combines pixels for near unfocused, focused and far unfocused planes, as calculated by 
+	 * GaussianDOFSeparateMat. Outputs final depth-of-field filtered image.
+	 *
+	 * @tparam	Near	If true, near plane pixels are read from the near plane texture, otherwise near plane is assumed
+	 *					not to exist.
+	 * @tparam	Far		If true, far plane pixels are read from the far plane texture, otherwise far plane is assumed not
+	 *					to exist.
+	 */
+	template<bool Near, bool Far>
+	class GaussianDOFCombineMat : public IGaussianDOFCombineMat, public RendererMaterial<GaussianDOFCombineMat<Near, Far>>
+	{
+		RMAT_DEF("PPGaussianDOFCombine.bsl");
 
 
-		/**
-		 * Releases the interally allocated output render textures. Must be called after each call to execute(), when the 
-		 * caller is done using the textures.
-		 */
-		void release();
+	public:
+		GaussianDOFCombineMat();
 
 
+		void execute(const SPtr<Texture>& focused, const SPtr<Texture>& near, const SPtr<Texture>& far, 
+			const SPtr<Texture>& depth, const SPtr<RenderTarget>& output, const RendererView& view, 
+			const DepthOfFieldSettings& settings) override;
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
-		GpuParamTexture mColorTexture;
+		GpuParamTexture mFocusedTexture;
+		GpuParamTexture mNearTexture;
+		GpuParamTexture mFarTexture;
 		GpuParamTexture mDepthTexture;
 		GpuParamTexture mDepthTexture;
+	};
 
 
-		SPtr<PooledRenderTexture> mOutput0;
-		SPtr<PooledRenderTexture> mOutput1;
+	/** Performs Gaussian depth of field effect with the help of various related shaders. */
+	class GaussianDOF
+	{
+	public:
+		/** 
+		 * Executes the depth of field effect on the provided scene color texture.
+		 * 
+		 * @param[in]	sceneColor	Input texture containing scene color.
+		 * @param[in]	sceneDepth	Input depth buffer texture that will be used for determining pixel depth.
+		 * @param[in}	output		Texture to output the results to.
+		 * @param[in]	view		View through which the depth of field effect is viewed.
+		 * @param[in]	settings	Settings used to control depth of field rendering. 
+		 */
+		void execute(const SPtr<Texture>& sceneColor, const SPtr<Texture>& sceneDepth, const SPtr<RenderTarget>& output, 
+			const RendererView& view, const DepthOfFieldSettings& settings);
+
+		/** Checks does the depth of field effect need to execute. */
+		static bool requiresDOF(const DepthOfFieldSettings& settings);
+	private:
+		GaussianDOFSeparateMat<true, true> mSeparateNF;
+		GaussianDOFSeparateMat<false, true> mSeparateF;
+		GaussianDOFSeparateMat<true, false> mSeparateN;
+
+		GaussianDOFCombineMat<true, true> mCombineNF;
+		GaussianDOFCombineMat<false, true> mCombineF;
+		GaussianDOFCombineMat<true, false> mCombineN;
+
+		GaussianBlurMat mBlur;
 	};
 	};
 
 
 	/**
 	/**
@@ -431,6 +530,7 @@ namespace bs { namespace ct
 
 
 		CreateTonemapLUTMat mCreateLUT;
 		CreateTonemapLUTMat mCreateLUT;
 		TonemappingMaterials mTonemapping;
 		TonemappingMaterials mTonemapping;
+		GaussianDOF mGaussianDOF;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 49 - 8
Source/RenderBeast/Include/BsRenderTargets.h

@@ -24,8 +24,18 @@ namespace bs { namespace ct
 		RTT_LightAccumulation,
 		RTT_LightAccumulation,
 		/** Buffer containing temporary combined occlusion data for a specific light (from shadow maps or attenuation. */
 		/** Buffer containing temporary combined occlusion data for a specific light (from shadow maps or attenuation. */
 		RTT_LightOcclusion,
 		RTT_LightOcclusion,
-		/** Buffer containing final scene color information. */
-		RTT_SceneColor
+		/** Buffer containing (potentially multisampled) scene color information. */
+		RTT_SceneColor,
+		/** 
+		 * Buffer containing non-MSAA final scene color information. If MSAA is not used then this is equivalent to
+		 * RTT_SceneColor;
+		 */
+		RTT_ResolvedSceneColor,
+		/**
+		 * Secondary resolved scene color texture that can be used for ping-ponging between primary and secondary scene
+		 * color textures. Primarily useful for post-processing effects.
+		 */
+		RTT_ResolvedSceneColorSecondary
 	};
 	};
 
 
 	/**
 	/**
@@ -77,9 +87,21 @@ namespace bs { namespace ct
 		/**	Returns the third color texture of the gbuffer as a bindable texture. */
 		/**	Returns the third color texture of the gbuffer as a bindable texture. */
 		SPtr<Texture> getGBufferC() const;
 		SPtr<Texture> getGBufferC() const;
 
 
-		/**	Binds the scene color render target for rendering. */
+		/**	
+		 * Binds the scene color render target for rendering. If using MSAA this texture will be allocated as a texture 
+		 * with multiple samples.
+		 */
 		void bindSceneColor(bool readOnlyDepthStencil);
 		void bindSceneColor(bool readOnlyDepthStencil);
 
 
+		/**
+		 * Binds the non-MSAA version of the scene color texture for rendering. If not using MSAA this is equivalent to
+		 * calling bindSceneColor() (as long as @p secondary is false).
+		 * 
+		 * @param[in]	secondary	If true, a seconday scene color texture will be bound. This texture can be used
+		 *							for ping-pong operations between it and the primary scene color.
+		 */
+		void bindResolvedSceneColor(bool secondary = false);
+
 		/** Binds the light accumulation render target for rendering. */
 		/** Binds the light accumulation render target for rendering. */
 		void bindLightAccumulation();
 		void bindLightAccumulation();
 
 
@@ -89,18 +111,33 @@ namespace bs { namespace ct
 		 */
 		 */
 		void bindLightOcclusion();
 		void bindLightOcclusion();
 
 
-		/** 
-		 * Returns the texture for storing the final scene color. If using MSAA see getSceneColorBuffer() instead. Only 
-		 * available after bindSceneColor() has been called from this frame.
-		 **/
+		/** Returns the texture containing (potentially multisampled) scene color. */
 		SPtr<Texture> getSceneColor() const;
 		SPtr<Texture> getSceneColor() const;
 
 
 		/** 
 		/** 
-		 * Flattened, buffer version of the texture returned by getSceneColor(). Required when MSAA is used, since
+		 * Flattened, buffer version of the texture returned by getSceneColor(). Only available when MSAA is used, since
 		 * random writes to multisampled textures aren't supported on all render backends.
 		 * random writes to multisampled textures aren't supported on all render backends.
 		 */
 		 */
 		SPtr<GpuBuffer> getSceneColorBuffer() const;
 		SPtr<GpuBuffer> getSceneColorBuffer() const;
 
 
+		/**
+		 * Returns a non-MSAA version of the scene color texture. If MSAA is not used this is equivalent to calling
+		 * getSceneColor() (as long as @p secondary is set to false).
+		 * 
+		 * @param[in]	secondary	If true, a seconday scene color texture will be returned. This texture can be used
+		 *							for ping-pong operations between it and the primary scene color.
+		 */
+		SPtr<Texture> getResolvedSceneColor(bool secondary = false) const;
+
+		/**
+		 * Returns a non-MSAA version of the scene color render target. If MSAA is not used this will return the default
+		 * scene color render target (as long as @p secondary is set to false).
+		 * 
+		 * @param[in]	secondary	If true, a seconday scene color target will be returned. This target can be used
+		 *							for ping-pong operations between it and the primary scene color.
+		 */
+		SPtr<RenderTarget> getResolvedSceneColorRT(bool secondary = false) const;
+
 		/** Returns the texture for storing of the intermediate lighting information. */
 		/** Returns the texture for storing of the intermediate lighting information. */
 		SPtr<Texture> getLightAccumulation() const;
 		SPtr<Texture> getLightAccumulation() const;
 
 
@@ -151,9 +188,13 @@ namespace bs { namespace ct
 
 
 		SPtr<PooledRenderTexture> mSceneColorTex;
 		SPtr<PooledRenderTexture> mSceneColorTex;
 		SPtr<PooledStorageBuffer> mFlattenedSceneColorBuffer;
 		SPtr<PooledStorageBuffer> mFlattenedSceneColorBuffer;
+		SPtr<PooledRenderTexture> mResolvedSceneColorTex1;
+		SPtr<PooledRenderTexture> mResolvedSceneColorTex2;
 
 
 		SPtr<RenderTexture> mGBufferRT;
 		SPtr<RenderTexture> mGBufferRT;
 		SPtr<RenderTexture> mSceneColorRT;
 		SPtr<RenderTexture> mSceneColorRT;
+		SPtr<RenderTexture> mResolvedSceneColorRT1;
+		SPtr<RenderTexture> mResolvedSceneColorRT2;
 		SPtr<RenderTexture> mLightAccumulationRT;
 		SPtr<RenderTexture> mLightAccumulationRT;
 		SPtr<RenderTexture> mLightOcclusionRT;
 		SPtr<RenderTexture> mLightOcclusionRT;
 
 

+ 188 - 13
Source/RenderBeast/Source/BsPostProcessing.cpp

@@ -712,7 +712,7 @@ namespace bs { namespace ct
 		return std::min(length * scale / 2, (float)MAX_BLUR_SAMPLES - 1);
 		return std::min(length * scale / 2, (float)MAX_BLUR_SAMPLES - 1);
 	}
 	}
 
 
-	GaussianDOFSeparateParamDef gGaussianDOFSeparateParamDef;
+	GaussianDOFParamDef gGaussianDOFParamDef;
 
 
 	template<bool Near, bool Far>
 	template<bool Near, bool Far>
 	GaussianDOFSeparateMat<Near, Far>::GaussianDOFSeparateMat()
 	GaussianDOFSeparateMat<Near, Far>::GaussianDOFSeparateMat()
@@ -750,7 +750,6 @@ namespace bs { namespace ct
 	void GaussianDOFSeparateMat<Near, Far>::execute(const SPtr<Texture>& color, const SPtr<Texture>& depth, 
 	void GaussianDOFSeparateMat<Near, Far>::execute(const SPtr<Texture>& color, const SPtr<Texture>& depth, 
 		const RendererView& view, const DepthOfFieldSettings& settings)
 		const RendererView& view, const DepthOfFieldSettings& settings)
 	{
 	{
-		const RendererViewProperties& viewProps = view.getProperties();
 		const TextureProperties& srcProps = color->getProperties();
 		const TextureProperties& srcProps = color->getProperties();
 
 
 		POOLED_RENDER_TEXTURE_DESC outputTexDesc = POOLED_RENDER_TEXTURE_DESC::create2D(srcProps.getFormat(), 
 		POOLED_RENDER_TEXTURE_DESC outputTexDesc = POOLED_RENDER_TEXTURE_DESC::create2D(srcProps.getFormat(), 
@@ -773,11 +772,11 @@ namespace bs { namespace ct
 
 
 		Vector2 invTexSize(1.0f / srcProps.getWidth(), 1.0f / srcProps.getHeight());
 		Vector2 invTexSize(1.0f / srcProps.getWidth(), 1.0f / srcProps.getHeight());
 
 
-		gGaussianDOFSeparateParamDef.gHalfPixelOffset.set(mParamBuffer, invTexSize * 0.5f);
-		gGaussianDOFSeparateParamDef.gNearBlurPlane.set(mParamBuffer, settings.focalDistance - settings.focalRange * 0.5f);
-		gGaussianDOFSeparateParamDef.gFarBlurPlane.set(mParamBuffer, settings.focalDistance + settings.focalRange * 0.5f);
-		gGaussianDOFSeparateParamDef.gInvNearBlurRange.set(mParamBuffer, 1.0f / settings.nearTransitionRange);
-		gGaussianDOFSeparateParamDef.gInvFarBlurRange.set(mParamBuffer, 1.0f / settings.farTransitionRange);
+		gGaussianDOFParamDef.gHalfPixelOffset.set(mParamBuffer, invTexSize * 0.5f);
+		gGaussianDOFParamDef.gNearBlurPlane.set(mParamBuffer, settings.focalDistance - settings.focalRange * 0.5f);
+		gGaussianDOFParamDef.gFarBlurPlane.set(mParamBuffer, settings.focalDistance + settings.focalRange * 0.5f);
+		gGaussianDOFParamDef.gInvNearBlurRange.set(mParamBuffer, 1.0f / settings.nearTransitionRange);
+		gGaussianDOFParamDef.gInvFarBlurRange.set(mParamBuffer, 1.0f / settings.farTransitionRange);
 
 
 		mColorTexture.set(color);
 		mColorTexture.set(color);
 		mDepthTexture.set(depth);
 		mDepthTexture.set(depth);
@@ -794,12 +793,12 @@ namespace bs { namespace ct
 	}
 	}
 
 
 	template <bool Near, bool Far>
 	template <bool Near, bool Far>
-	SPtr<Texture> GaussianDOFSeparateMat<Near, Far>::getOutput(UINT32 idx)
+	SPtr<PooledRenderTexture> GaussianDOFSeparateMat<Near, Far>::getOutput(UINT32 idx)
 	{
 	{
 		if (idx == 0)
 		if (idx == 0)
-			return mOutput0->texture;
+			return mOutput0;
 		else if (idx == 1)
 		else if (idx == 1)
-			return mOutput1->texture;
+			return mOutput1;
 
 
 		return nullptr;
 		return nullptr;
 	}
 	}
@@ -814,6 +813,162 @@ namespace bs { namespace ct
 			GpuResourcePool::instance().release(mOutput1);
 			GpuResourcePool::instance().release(mOutput1);
 	}
 	}
 
 
+	template class GaussianDOFSeparateMat<true, true>;
+	template class GaussianDOFSeparateMat<true, false>;
+	template class GaussianDOFSeparateMat<false, true>;
+
+	template<bool Near, bool Far>
+	GaussianDOFCombineMat<Near, Far>::GaussianDOFCombineMat()
+	{
+		mParamBuffer = gDownsampleParamDef.createBuffer();
+
+		mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
+
+		SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
+		gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gFocusedTex", mFocusedTexture);
+		gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDepthTex", mDepthTexture);
+
+		if(gpuParams->hasTexture(GPT_FRAGMENT_PROGRAM, "gNearTex"))
+			gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gNearTex", mNearTexture);
+
+		if(gpuParams->hasTexture(GPT_FRAGMENT_PROGRAM, "gFarTex"))
+			gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gFarTex", mFarTexture);
+	}
+
+	template<bool Near, bool Far>
+	void GaussianDOFCombineMat<Near, Far>::_initDefines(ShaderDefines& defines)
+	{
+		defines.set("NEAR", Near ? 1 : 0);
+		defines.set("FAR", Far ? 1 : 0);
+		defines.set("NEAR_AND_FAR", (Near && Far) ? 1 : 0);
+	}
+
+	template<bool Near, bool Far>
+	void GaussianDOFCombineMat<Near, Far>::execute(const SPtr<Texture>& focused, const SPtr<Texture>& near, 
+		const SPtr<Texture>& far, const SPtr<Texture>& depth, const SPtr<RenderTarget>& output,
+		const RendererView& view, const DepthOfFieldSettings& settings)
+	{
+		const TextureProperties& srcProps = focused->getProperties();
+
+		Vector2 invTexSize(1.0f / srcProps.getWidth(), 1.0f / srcProps.getHeight());
+
+		gGaussianDOFParamDef.gHalfPixelOffset.set(mParamBuffer, invTexSize * 0.5f);
+		gGaussianDOFParamDef.gNearBlurPlane.set(mParamBuffer, settings.focalDistance - settings.focalRange * 0.5f);
+		gGaussianDOFParamDef.gFarBlurPlane.set(mParamBuffer, settings.focalDistance + settings.focalRange * 0.5f);
+		gGaussianDOFParamDef.gInvNearBlurRange.set(mParamBuffer, 1.0f / settings.nearTransitionRange);
+		gGaussianDOFParamDef.gInvFarBlurRange.set(mParamBuffer, 1.0f / settings.farTransitionRange);
+
+		mFocusedTexture.set(focused);
+		mNearTexture.set(near);
+		mFarTexture.set(far);
+		mDepthTexture.set(depth);
+
+		SPtr<GpuParamBlockBuffer> perView = view.getPerViewBuffer();
+		mParamsSet->setParamBlockBuffer("PerCamera", perView);
+
+		RenderAPI& rapi = RenderAPI::instance();
+		rapi.setRenderTarget(output);
+
+		gRendererUtility().setPass(mMaterial);
+		gRendererUtility().setPassParams(mParamsSet);
+		gRendererUtility().drawScreenQuad();
+	}
+
+	template class GaussianDOFCombineMat<true, true>;
+	template class GaussianDOFCombineMat<true, false>;
+	template class GaussianDOFCombineMat<false, true>;
+
+	void GaussianDOF::execute(const SPtr<Texture>& sceneColor, const SPtr<Texture>& sceneDepth, 
+		const SPtr<RenderTarget>& output, const RendererView& view, const DepthOfFieldSettings& settings)
+	{
+		bool near = settings.nearBlurAmount > 0.0f;
+		bool far = settings.farBlurAmount > 0.0f;
+
+		// This shouldn't have been called if both are false
+		assert(near || far);
+
+		IGaussianDOFSeparateMat* separateMat;
+		IGaussianDOFCombineMat* combineMat;
+
+		if (near && far)
+		{
+			separateMat = &mSeparateNF;
+			combineMat = &mCombineNF;
+		}
+		else
+		{
+			if(near)
+			{
+				separateMat = &mSeparateN;
+				combineMat = &mCombineN;
+			}
+			else
+			{
+				separateMat = &mSeparateF;
+				combineMat = &mCombineF;
+			}
+		}
+
+		separateMat->execute(sceneColor, sceneDepth, view, settings);
+
+		SPtr<PooledRenderTexture> nearTex, farTex;
+		if(near && far)
+		{
+			nearTex = separateMat->getOutput(0);
+			farTex = separateMat->getOutput(1);
+		}
+		else
+		{
+			if (near)
+				nearTex = separateMat->getOutput(0);
+			else
+				farTex = separateMat->getOutput(0);
+		}
+
+		// Blur the out of focus pixels
+		// Note: Perhaps set up stencil so I can avoid performing blur on unused parts of the textures?
+		const TextureProperties& texProps = sceneColor->getProperties();
+		POOLED_RENDER_TEXTURE_DESC tempTexDesc = POOLED_RENDER_TEXTURE_DESC::create2D(texProps.getFormat(), 
+			texProps.getWidth(), texProps.getHeight(), TU_RENDERTARGET);
+		SPtr<PooledRenderTexture> tempTexture = GpuResourcePool::instance().get(tempTexDesc);
+
+		SPtr<Texture> blurredNearTex;
+		if(nearTex)
+		{
+			mBlur.execute(nearTex->texture, settings.nearBlurAmount, tempTexture->renderTexture);
+			blurredNearTex = tempTexture->texture;
+		}
+
+		SPtr<Texture> blurredFarTex;
+		if(farTex)
+		{
+			// If temporary texture is used up, re-use the original near texture for the blurred result
+			if(blurredNearTex)
+			{
+				mBlur.execute(farTex->texture, settings.farBlurAmount, nearTex->renderTexture);
+				blurredFarTex = nearTex->texture;
+			}
+			else // Otherwise just use the temporary
+			{
+				mBlur.execute(farTex->texture, settings.farBlurAmount, tempTexture->renderTexture);
+				blurredFarTex = tempTexture->texture;
+			}
+		}
+		
+		combineMat->execute(sceneColor, blurredNearTex, blurredFarTex, sceneDepth, output, view, settings);
+
+		separateMat->release();
+		GpuResourcePool::instance().release(tempTexture);
+	}
+
+	bool GaussianDOF::requiresDOF(const DepthOfFieldSettings& settings)
+	{
+		bool near = settings.nearBlurAmount > 0.0f;
+		bool far = settings.farBlurAmount > 0.0f;
+
+		return settings.enabled && (near || far);
+	}
+	
 	void PostProcessing::postProcess(RendererView* viewInfo, const SPtr<RenderTargets>& renderTargets, float frameDelta)
 	void PostProcessing::postProcess(RendererView* viewInfo, const SPtr<RenderTargets>& renderTargets, float frameDelta)
 	{
 	{
 		auto& viewProps = viewInfo->getProperties();
 		auto& viewProps = viewInfo->getProperties();
@@ -840,8 +995,6 @@ namespace bs { namespace ct
 			mEyeAdaptHistogramReduce.release(ppInfo);
 			mEyeAdaptHistogramReduce.release(ppInfo);
 		}
 		}
 
 
-		SPtr<RenderTarget> resolveTarget = viewProps.target;
-
 		bool gammaOnly;
 		bool gammaOnly;
 		bool autoExposure;
 		bool autoExposure;
 		if (hdr)
 		if (hdr)
@@ -864,7 +1017,29 @@ namespace bs { namespace ct
 			autoExposure = false;
 			autoExposure = false;
 		}
 		}
 
 
-		mTonemapping.execute(gammaOnly, autoExposure, msaa, sceneColor, resolveTarget, viewportRect, ppInfo);
+		bool performDOF = GaussianDOF::requiresDOF(settings.depthOfField);
+
+		SPtr<RenderTarget> tonemapTarget;
+		if (!performDOF)
+			tonemapTarget = viewProps.target;
+		else
+		{
+			renderTargets->allocate(RTT_ResolvedSceneColorSecondary);
+			tonemapTarget = renderTargets->getResolvedSceneColorRT(true);
+		}
+
+		mTonemapping.execute(gammaOnly, autoExposure, msaa, sceneColor, tonemapTarget, viewportRect, ppInfo);
+
+		if(GaussianDOF::requiresDOF(settings.depthOfField))
+		{
+			SPtr<RenderTarget> dofTarget = viewProps.target;
+
+			mGaussianDOF.execute(renderTargets->getResolvedSceneColor(true), renderTargets->getSceneDepth(), dofTarget,
+				*viewInfo, settings.depthOfField);
+		}
+
+		if(performDOF)
+			renderTargets->release(RTT_ResolvedSceneColorSecondary);
 
 
 		if (ppInfo.settingDirty)
 		if (ppInfo.settingDirty)
 			ppInfo.settingDirty = false;
 			ppInfo.settingDirty = false;

+ 120 - 0
Source/RenderBeast/Source/BsRenderTargets.cpp

@@ -211,6 +211,74 @@ namespace bs { namespace ct
 				mLightOcclusionRT = TextureManager::instance().createRenderTexture(lightOcclusionRTDesc);
 				mLightOcclusionRT = TextureManager::instance().createRenderTexture(lightOcclusionRTDesc);
 			}
 			}
 		}
 		}
+		else if(type == RTT_ResolvedSceneColor)
+		{
+			// If not using MSAA, this is equivalent to default scene color texture
+			if(mViewTarget.numSamples > 1)
+			{
+				mResolvedSceneColorTex1 = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, width, height,
+					TU_RENDERTARGET, 1, false));
+
+				bool rebuildRT = false;
+				if (mResolvedSceneColorRT1 != nullptr)
+				{
+					rebuildRT |= mResolvedSceneColorRT1->getColorTexture(0) != mResolvedSceneColorTex1->texture;
+					rebuildRT |= mResolvedSceneColorRT1->getDepthStencilTexture() != mDepthTex->texture;
+				}
+				else
+					rebuildRT = true;
+
+				if (rebuildRT)
+				{
+					RENDER_TEXTURE_DESC sceneColorDesc;
+					sceneColorDesc.colorSurfaces[0].texture = mResolvedSceneColorTex1->texture;
+					sceneColorDesc.colorSurfaces[0].face = 0;
+					sceneColorDesc.colorSurfaces[0].numFaces = 1;
+					sceneColorDesc.colorSurfaces[0].mipLevel = 0;
+
+					sceneColorDesc.depthStencilSurface.texture = mDepthTex->texture;
+					sceneColorDesc.depthStencilSurface.face = 0;
+					sceneColorDesc.depthStencilSurface.numFaces = 1;
+					sceneColorDesc.depthStencilSurface.mipLevel = 0;
+
+					mResolvedSceneColorRT1 = TextureManager::instance().createRenderTexture(sceneColorDesc);
+				}
+			}
+		}
+		else if(type == RTT_ResolvedSceneColorSecondary)
+		{
+			// If not using MSAA, this is equivalent to default scene color texture
+			if(mViewTarget.numSamples > 1)
+			{
+				mResolvedSceneColorTex2 = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, 
+					width, height, TU_RENDERTARGET, 1, false));
+
+				bool rebuildRT = false;
+				if (mResolvedSceneColorRT2 != nullptr)
+				{
+					rebuildRT |= mResolvedSceneColorRT2->getColorTexture(0) != mResolvedSceneColorTex2->texture;
+					rebuildRT |= mResolvedSceneColorRT2->getDepthStencilTexture() != mDepthTex->texture;
+				}
+				else
+					rebuildRT = true;
+
+				if (rebuildRT)
+				{
+					RENDER_TEXTURE_DESC sceneColorDesc;
+					sceneColorDesc.colorSurfaces[0].texture = mResolvedSceneColorTex2->texture;
+					sceneColorDesc.colorSurfaces[0].face = 0;
+					sceneColorDesc.colorSurfaces[0].numFaces = 1;
+					sceneColorDesc.colorSurfaces[0].mipLevel = 0;
+
+					sceneColorDesc.depthStencilSurface.texture = mDepthTex->texture;
+					sceneColorDesc.depthStencilSurface.face = 0;
+					sceneColorDesc.depthStencilSurface.numFaces = 1;
+					sceneColorDesc.depthStencilSurface.mipLevel = 0;
+
+					mResolvedSceneColorRT2 = TextureManager::instance().createRenderTexture(sceneColorDesc);
+				}
+			}
+		}
 	}
 	}
 
 
 	void RenderTargets::release(RenderTargetType type)
 	void RenderTargets::release(RenderTargetType type)
@@ -244,6 +312,16 @@ namespace bs { namespace ct
 			if (mLightOcclusionTex != nullptr)
 			if (mLightOcclusionTex != nullptr)
 				texPool.release(mLightOcclusionTex);
 				texPool.release(mLightOcclusionTex);
 		}
 		}
+		else if(type == RTT_ResolvedSceneColor)
+		{
+			if (mResolvedSceneColorTex1 != nullptr)
+				texPool.release(mResolvedSceneColorTex1);
+		}
+		else if(type == RTT_ResolvedSceneColorSecondary)
+		{
+			if (mResolvedSceneColorTex2 != nullptr)
+				texPool.release(mResolvedSceneColorTex2);
+		}
 	}
 	}
 
 
 	void RenderTargets::bindGBuffer()
 	void RenderTargets::bindGBuffer()
@@ -296,6 +374,22 @@ namespace bs { namespace ct
 		RenderAPI::instance().clearViewport(FBT_COLOR, Color::ZERO);
 		RenderAPI::instance().clearViewport(FBT_COLOR, Color::ZERO);
 	}
 	}
 
 
+	void RenderTargets::bindResolvedSceneColor(bool secondary)
+	{
+		RenderAPI& rapi = RenderAPI::instance();
+
+		if(secondary)
+			rapi.setRenderTarget(mResolvedSceneColorRT2, FBT_DEPTH | FBT_STENCIL, RT_DEPTH_STENCIL);
+		else
+		{
+			if(mViewTarget.numSamples > 1)
+				rapi.setRenderTarget(mResolvedSceneColorRT1, FBT_DEPTH | FBT_STENCIL, RT_DEPTH_STENCIL);
+			else
+				rapi.setRenderTarget(mSceneColorRT, FBT_DEPTH | FBT_STENCIL, RT_DEPTH_STENCIL);
+		}
+	}
+
+
 	SPtr<Texture> RenderTargets::getSceneColor() const
 	SPtr<Texture> RenderTargets::getSceneColor() const
 	{
 	{
 		return mSceneColorTex->texture;
 		return mSceneColorTex->texture;
@@ -340,4 +434,30 @@ namespace bs { namespace ct
 	{
 	{
 		return mFlattenedLightAccumulationBuffer->buffer;
 		return mFlattenedLightAccumulationBuffer->buffer;
 	}
 	}
+
+	SPtr<Texture> RenderTargets::getResolvedSceneColor(bool secondary) const
+	{
+		if (secondary)
+			return mResolvedSceneColorTex2->texture;
+		else
+		{
+			if (mViewTarget.numSamples > 1)
+				return mResolvedSceneColorTex1->texture;
+			else
+				return mSceneColorTex->texture;
+		}
+	}
+
+	SPtr<RenderTarget> RenderTargets::getResolvedSceneColorRT(bool secondary) const
+	{
+		if (secondary)
+			return mResolvedSceneColorRT2;
+		else
+		{
+			if (mViewTarget.numSamples > 1)
+				return mResolvedSceneColorRT1;
+			else
+				return mSceneColorRT;
+		}
+	}
 }}
 }}