Răsfoiți Sursa

Added gaussian DOF setup shader & related code

BearishSun 8 ani în urmă
părinte
comite
35c18ec554

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

@@ -293,6 +293,10 @@
         {
         {
             "Path": "PPGaussianBlur.bsl",
             "Path": "PPGaussianBlur.bsl",
             "UUID": "14b16378-6282-4d2d-bc4c-2d662cc98066"
             "UUID": "14b16378-6282-4d2d-bc4c-2d662cc98066"
+        },
+        {
+            "Path": "PPGaussianDOFSeparate.bsl",
+            "UUID": "78285aaa-a862-46f3-837c-d13abbe8b351"
         }
         }
     ],
     ],
     "Skin": [
     "Skin": [

+ 6 - 0
Data/Raw/Engine/Includes/PerCameraData.bslinc

@@ -41,6 +41,12 @@ mixin PerCameraData
 			return (1.0f / (deviceZ + gDeviceZToWorldZ.y)) * gDeviceZToWorldZ.x;
 			return (1.0f / (deviceZ + gDeviceZToWorldZ.y)) * gDeviceZToWorldZ.x;
 		}
 		}
 		
 		
+		/** Converts Z value in range [0,1] into Z value in view space. */
+		float4 convertFromDeviceZ(float4 deviceZ)
+		{
+			return gDeviceZToWorldZ.x / (deviceZ + gDeviceZToWorldZ.y);
+		}		
+		
 		/** Converts Z value from view space to NDC space. */
 		/** Converts Z value from view space to NDC space. */
 		float convertToNDCZ(float viewZ)
 		float convertToNDCZ(float viewZ)
 		{
 		{

+ 86 - 0
Data/Raw/Engine/Shaders/PPGaussianDOFSeparate.bsl

@@ -0,0 +1,86 @@
+#include "$ENGINE$\PPBase.bslinc"
+#include "$ENGINE$\PerCameraData.bslinc"
+
+technique PPGaussianDOFSeparate
+{
+	mixin PPBase;
+	mixin PerCameraData;
+
+	code
+	{
+		[internal]
+		cbuffer Input
+		{
+			float gNearBlurPlane;
+			float gFarBlurPlane;
+			float gInvNearBlurRange;
+			float gInvFarBlurRange;
+			float2 gHalfPixelOffset;
+		}		
+
+		SamplerState gColorSamp;
+		Texture2D gColorTex;
+		
+		SamplerState gDepthSamp;
+		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)
+		{
+			float4 smp;
+			smp.rgb = gColorTex.SampleLevel(gColorSamp, uv + gHalfPixelOffset * offset, 0.0f).rgb;
+			smp.a = 1.0f;
+			
+			#if NEAR
+			nearColor += smp * calcNearMask(depth);
+			#endif
+			#if FAR
+			farColor += smp * calcFarMask(depth);
+			#endif		
+		}
+		
+		void fsmain(
+			VStoFS input,
+			out float4 output0 : SV_Target0
+			#if NEAR_AND_FAR
+			out float4 output1 : SV_Target1
+			#endif
+			)
+		{
+			float4 depth = convertFromDeviceZ(gDepthTex.Gather(gDepthSamp, input.uv0));
+			
+			float4 nearColor = 0;
+			float4 farColor = 0;
+			
+			// Samples start in bottom left and go in counter-clockwise order, in order to match
+			// depth Gather
+			addSample(input.uv0, float2(-1, 1), depth.x, nearColor, farColor);
+			addSample(input.uv0, float2(1, 1), depth.y, nearColor, farColor);
+			addSample(input.uv0, float2(1, -1), depth.x, nearColor, farColor);
+			addSample(input.uv0, float2(-1, -1), depth.x, nearColor, farColor);
+			
+			nearColor *= 0.25f;
+			farColor *= 0.25f;
+			
+			#if NEAR_AND_FAR
+				output0 = nearColor;
+				output1 = farColor;
+			#else
+			#if NEAR
+				output0 = nearColor;
+			#else
+				output0 = farColor;
+			#endif
+			#endif
+		}	
+	};
+};

+ 2 - 1
Source/BansheeEngine/Include/BsPrerequisites.h

@@ -231,6 +231,7 @@ namespace bs
 		TID_AutoExposureSettings = 30016,
 		TID_AutoExposureSettings = 30016,
 		TID_TonemappingSettings = 30017,
 		TID_TonemappingSettings = 30017,
 		TID_WhiteBalanceSettings = 30018,
 		TID_WhiteBalanceSettings = 30018,
-		TID_ColorGradingSettings = 30019
+		TID_ColorGradingSettings = 30019,
+		TID_DepthOfFieldSettings = 30020
 	};
 	};
 }
 }

+ 55 - 0
Source/BansheeEngine/Include/BsStandardPostProcessSettings.h

@@ -199,6 +199,58 @@ namespace bs
 		RTTITypeBase* getRTTI() const override;
 		RTTITypeBase* getRTTI() const override;
 	};
 	};
 
 
+	/** Settings that control the depth-of-field effect. */
+	struct BS_EXPORT DepthOfFieldSettings : public IReflectable
+	{
+		DepthOfFieldSettings();
+
+		/** Enables or disables the depth of field effect. */
+		bool enabled;
+
+		/** 
+		 * Distance from the camera at which the focal plane is located in. Objects at this distance will be fully in focus.
+		 */
+		float focalDistance;
+		
+		/** 
+		 * Range within which the objects remain fully in focus. This range is applied relative to the focal distance. 
+		 * Only relevant if Gaussian depth of field is used as other methods don't use a constant in-focus range.
+		 */
+		float focalRange;
+
+		/**
+		 * Determines the size of the range within which objects transition from focused to fully unfocused, at the near 
+		 * plane. Only relevant for Gaussian depth of field.
+		 */
+		float nearTransitionRange;
+
+		/**
+		 * Determines the size of the range within which objects transition from focused to fully unfocused, at the far 
+		 * plane. Only relevant for Gaussian depth of field.
+		 */
+		float farTransitionRange;
+
+		/** 
+		 * Determines the amount of blur to apply to fully unfocused objects that are closer to camera than the in-focus
+		 * zone. Set to zero to disable near-field blur. Only relevant for Gaussian depth of field.
+		 */
+		float nearBlurAmount;
+
+		/** 
+		 * Determines the amount of blur to apply to fully unfocused objects that are farther away from camera than the
+		 * in-focus zone. Set to zero to disable far-field blur. Only relevant for Gaussian depth of field.
+		 */
+		float farBlurAmount;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class DepthOfFieldSettingsRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		RTTITypeBase* getRTTI() const override;
+	};
+
 	/** Settings that control the post-process operations. */
 	/** Settings that control the post-process operations. */
 	struct BS_EXPORT StandardPostProcessSettings : public PostProcessSettings
 	struct BS_EXPORT StandardPostProcessSettings : public PostProcessSettings
 	{
 	{
@@ -249,6 +301,9 @@ namespace bs
 		/** Parameters used for customizing color grading. */
 		/** Parameters used for customizing color grading. */
 		ColorGradingSettings colorGrading;
 		ColorGradingSettings colorGrading;
 
 
+		/** Parameters used for customizing the depth of field effect. */
+		DepthOfFieldSettings depthOfField;
+
 		/**
 		/**
 		 * Log2 value to scale the eye adaptation by (for example 2^0 = 1). Smaller values yield darker image, while larger
 		 * Log2 value to scale the eye adaptation by (for example 2^0 = 1). Smaller values yield darker image, while larger
 		 * yield brighter image. Allows you to customize exposure manually, applied on top of eye adaptation exposure (if
 		 * yield brighter image. Allows you to customize exposure manually, applied on top of eye adaptation exposure (if

+ 36 - 0
Source/BansheeEngine/Include/BsStandardPostProcessSettingsRTTI.h

@@ -146,6 +146,41 @@ namespace bs
 		}
 		}
 	};
 	};
 
 
+	class BS_EXPORT DepthOfFieldSettingsRTTI : public RTTIType <DepthOfFieldSettings, IReflectable, DepthOfFieldSettingsRTTI>
+	{
+	private:
+		BS_BEGIN_RTTI_MEMBERS
+			BS_RTTI_MEMBER_PLAIN(enabled, 0)
+			BS_RTTI_MEMBER_PLAIN(focalDistance, 1)
+			BS_RTTI_MEMBER_PLAIN(focalRange, 2)
+			BS_RTTI_MEMBER_PLAIN(nearTransitionRange, 3)
+			BS_RTTI_MEMBER_PLAIN(farTransitionRange, 4)
+			BS_RTTI_MEMBER_PLAIN(nearBlurAmount, 5)
+			BS_RTTI_MEMBER_PLAIN(farBlurAmount, 6)
+		BS_END_RTTI_MEMBERS
+
+	public:
+		DepthOfFieldSettingsRTTI()
+			:mInitMembers(this)
+		{ }
+
+		const String& getRTTIName() override
+		{
+			static String name = "DepthOfFieldSettings";
+			return name;
+		}
+
+		UINT32 getRTTIId() override
+		{
+			return TID_DepthOfFieldSettings;
+		}
+
+		SPtr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<DepthOfFieldSettings>();
+		}
+	};
+
 	class BS_EXPORT StandardPostProcessSettingsRTTI : public RTTIType <StandardPostProcessSettings, PostProcessSettings, StandardPostProcessSettingsRTTI>
 	class BS_EXPORT StandardPostProcessSettingsRTTI : public RTTIType <StandardPostProcessSettings, PostProcessSettings, StandardPostProcessSettingsRTTI>
 	{
 	{
 	private:
 	private:
@@ -158,6 +193,7 @@ namespace bs
 			BS_RTTI_MEMBER_REFL(colorGrading, 5)
 			BS_RTTI_MEMBER_REFL(colorGrading, 5)
 			BS_RTTI_MEMBER_PLAIN(exposureScale, 6)
 			BS_RTTI_MEMBER_PLAIN(exposureScale, 6)
 			BS_RTTI_MEMBER_PLAIN(gamma, 7)
 			BS_RTTI_MEMBER_PLAIN(gamma, 7)
+			BS_RTTI_MEMBER_REFL(depthOfField, 8)
 		BS_END_RTTI_MEMBERS
 		BS_END_RTTI_MEMBERS
 			
 			
 	public:
 	public:

+ 15 - 0
Source/BansheeEngine/Source/BsStandardPostProcessSettings.cpp

@@ -65,6 +65,21 @@ namespace bs
 		return ColorGradingSettings::getRTTIStatic();
 		return ColorGradingSettings::getRTTIStatic();
 	}
 	}
 
 
+	DepthOfFieldSettings::DepthOfFieldSettings()
+		: enabled(false), focalDistance(2.0f), focalRange(1.0f), nearTransitionRange(0.25f), farTransitionRange(0.25f)
+		, nearBlurAmount(16.0f), farBlurAmount(16.0f)
+	{ }
+
+	RTTITypeBase* DepthOfFieldSettings::getRTTIStatic()
+	{
+		return DepthOfFieldSettingsRTTI::instance();
+	}
+
+	RTTITypeBase* DepthOfFieldSettings::getRTTI() const
+	{
+		return DepthOfFieldSettings::getRTTIStatic();
+	}
+
 	StandardPostProcessSettings::StandardPostProcessSettings()
 	StandardPostProcessSettings::StandardPostProcessSettings()
 		: enableAutoExposure(true), enableTonemapping(true), exposureScale(0.0f), gamma(2.2f)
 		: enableAutoExposure(true), enableTonemapping(true), exposureScale(0.0f), gamma(2.2f)
 	{ }
 	{ }

+ 60 - 1
Source/RenderBeast/Include/BsPostProcessing.h

@@ -313,7 +313,7 @@ namespace bs { namespace ct
 
 
 	extern GaussianBlurParamDef gGaussianBlurParamDef;
 	extern GaussianBlurParamDef gGaussianBlurParamDef;
 
 
-	/** Shader that perform Gaussian blur filtering on the provided texture. */
+	/** Shader that performs Gaussian blur filtering on the provided texture. */
 	class GaussianBlurMat : public RendererMaterial<GaussianBlurMat>
 	class GaussianBlurMat : public RendererMaterial<GaussianBlurMat>
 	{
 	{
 		// Direction of the Gaussian filter pass
 		// Direction of the Gaussian filter pass
@@ -349,6 +349,65 @@ namespace bs { namespace ct
 		GpuParamTexture mInputTexture;
 		GpuParamTexture mInputTexture;
 	};
 	};
 
 
+	BS_PARAM_BLOCK_BEGIN(GaussianDOFSeparateParamDef)
+		BS_PARAM_BLOCK_ENTRY(float, gNearBlurPlane)
+		BS_PARAM_BLOCK_ENTRY(float, gFarBlurPlane)
+		BS_PARAM_BLOCK_ENTRY(float, gInvNearBlurRange)
+		BS_PARAM_BLOCK_ENTRY(float, gInvFarBlurRange)
+		BS_PARAM_BLOCK_ENTRY(Vector2, gHalfPixelOffset)
+	BS_PARAM_BLOCK_END
+
+	extern GaussianDOFSeparateParamDef sGaussianDOFSeparateParamDef;
+
+	/** 
+	 * Shader that masks pixels from the input color texture into one or two output textures. The masking is done by
+	 * determining if the pixel falls into near or far unfocused plane, as determined by depth-of-field parameters. User
+	 * can pick whether to output pixels just on the near plane, just on the far plane, or both.
+	 *
+	 * @tparam	Near	If true, near plane pixels are output to the first render target.
+	 * @tparam	Far		If true, far plane pixels are output to the first render target. If @p Near is also enabled, the
+	 *					pixels are output to the second render target instead.
+	 */
+	template<bool Near, bool Far>
+	class GaussianDOFSeparateMat : public RendererMaterial<GaussianDOFSeparateMat<Near, Far>>
+	{
+		RMAT_DEF("PPGaussianDOFSeparate.bsl");
+
+	public:
+		GaussianDOFSeparateMat();
+
+		/** 
+		 * 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. 
+		 */
+		void execute(const SPtr<Texture>& color, const SPtr<Texture>& depth, const RendererView& view, 
+			const DepthOfFieldSettings& settings);
+
+		/**
+		 * 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);
+
+		/**
+		 * 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();
+
+	private:
+		SPtr<GpuParamBlockBuffer> mParamBuffer;
+		GpuParamTexture mColorTexture;
+		GpuParamTexture mDepthTexture;
+
+		SPtr<PooledRenderTexture> mOutput0;
+		SPtr<PooledRenderTexture> mOutput1;
+	};
+
 	/**
 	/**
 	 * Renders post-processing effects for the provided render target.
 	 * Renders post-processing effects for the provided render target.
 	 *
 	 *

+ 102 - 0
Source/RenderBeast/Source/BsPostProcessing.cpp

@@ -712,6 +712,108 @@ 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;
+
+	template<bool Near, bool Far>
+	GaussianDOFSeparateMat<Near, Far>::GaussianDOFSeparateMat()
+	{
+		mParamBuffer = gDownsampleParamDef.createBuffer();
+
+		mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
+		mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gColorTex", mColorTexture);
+		mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDepthTex", mDepthTexture);
+
+		GpuParamSampState colorSampState;
+		mParamsSet->getGpuParams()->getSamplerStateParam(GPT_FRAGMENT_PROGRAM, "gColorSamp", colorSampState);
+
+		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> samplerState = SamplerState::create(desc);
+		colorSampState.set(samplerState);
+	}
+
+	template<bool Near, bool Far>
+	void GaussianDOFSeparateMat<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 GaussianDOFSeparateMat<Near, Far>::execute(const SPtr<Texture>& color, const SPtr<Texture>& depth, 
+		const RendererView& view, const DepthOfFieldSettings& settings)
+	{
+		const RendererViewProperties& viewProps = view.getProperties();
+		const TextureProperties& srcProps = color->getProperties();
+
+		POOLED_RENDER_TEXTURE_DESC outputTexDesc = POOLED_RENDER_TEXTURE_DESC::create2D(srcProps.getFormat(), 
+			srcProps.getWidth(), srcProps.getHeight(), TU_RENDERTARGET);
+		mOutput0 = GpuResourcePool::instance().get(outputTexDesc);
+
+		SPtr<RenderTexture> rt;
+		if (Near && Far)
+		{
+			mOutput1 = GpuResourcePool::instance().get(outputTexDesc);
+
+			RENDER_TEXTURE_DESC rtDesc;
+			rtDesc.colorSurfaces[0].texture = mOutput0->texture;
+			rtDesc.colorSurfaces[1].texture = mOutput1->texture;
+
+			rt = RenderTexture::create(rtDesc);
+		}
+		else
+			rt = mOutput0->renderTexture;
+
+		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);
+
+		mColorTexture.set(color);
+		mDepthTexture.set(depth);
+
+		SPtr<GpuParamBlockBuffer> perView = view.getPerViewBuffer();
+		mParamsSet->setParamBlockBuffer("PerCamera", perView);
+
+		RenderAPI& rapi = RenderAPI::instance();
+		rapi.setRenderTarget(rt);
+
+		gRendererUtility().setPass(mMaterial);
+		gRendererUtility().setPassParams(mParamsSet);
+		gRendererUtility().drawScreenQuad();
+	}
+
+	template <bool Near, bool Far>
+	SPtr<Texture> GaussianDOFSeparateMat<Near, Far>::getOutput(UINT32 idx)
+	{
+		if (idx == 0)
+			return mOutput0->texture;
+		else if (idx == 1)
+			return mOutput1->texture;
+
+		return nullptr;
+	}
+
+	template<bool Near, bool Far>
+	void GaussianDOFSeparateMat<Near, Far>::release()
+	{
+		if (mOutput0 != nullptr)
+			GpuResourcePool::instance().release(mOutput0);
+
+		if (mOutput1 != nullptr)
+			GpuResourcePool::instance().release(mOutput1);
+	}
+
 	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();