Browse Source

Feature: Depth range can now be encoded when rendering reflection probes

BearishSun 8 years ago
parent
commit
b149802ac8

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

@@ -365,6 +365,10 @@
         {
             "Path": "ClearStencilBits.bsl",
             "UUID": "e123138f-af24-422f-9301-f71113fcd282"
+        },
+        {
+            "Path": "PPEncodeDepth.bsl",
+            "UUID": "8bbf989a-9f8d-4864-8332-7f8c499685ba"
         }
     ],
     "Skin": [

+ 38 - 0
Data/Raw/Engine/Shaders/PPEncodeDepth.bsl

@@ -0,0 +1,38 @@
+#include "$ENGINE$\PPBase.bslinc"
+#include "$ENGINE$\PerCameraData.bslinc"
+
+technique PPEncodeDepth
+{
+	mixin PPBase;
+	mixin PerCameraData;
+
+	blend
+	{
+		target
+		{
+			writemask = A;
+		};
+	};
+
+	code
+	{
+		[internal]
+		cbuffer Params
+		{
+			float gNear;
+			float gFar;
+		}	
+	
+		SamplerState gInputSamp;
+		Texture2D gInputTex;
+		
+		float4 fsmain(VStoFS input) : SV_Target0
+		{
+			float deviceZ = gInputTex.Sample(gInputSamp, input.uv0);
+			float viewZ = convertFromDeviceZ(deviceZ);
+		
+			float alpha = 1.0f - saturate((viewZ - gNear) / (gFar - gNear));
+			return float4(0.0f, 0.0f, 0.0f, alpha);
+		}	
+	};
+};

+ 1 - 1
Source/BansheeCore/Renderer/BsLightProbeVolume.cpp

@@ -464,7 +464,7 @@ namespace bs
 				Vector3 localPos = mProbePositions[mFirstDirtyProbe];
 				Vector3 transformedPos = mRotation.rotate(localPos) + mPosition;
 
-				gRenderer()->captureSceneCubeMap(cubemap, transformedPos, true);
+				gRenderer()->captureSceneCubeMap(cubemap, transformedPos, CaptureSettings());
 				gIBLUtility().filterCubemapForIrradiance(cubemap, mCoefficients, probeInfo.bufferIdx);
 
 				probeInfo.flags = LightProbeFlags::Clean;

+ 9 - 2
Source/BansheeCore/Renderer/BsReflectionProbe.cpp

@@ -97,7 +97,15 @@ namespace bs
 		{
 			auto renderReflProbe = [coreTexture, coreProbe]()
 			{
-				ct::gRenderer()->captureSceneCubeMap(coreTexture, coreProbe->getPosition(), true);
+				float radius = coreProbe->mType == ReflectionProbeType::Sphere ? coreProbe->mRadius : 
+					coreProbe->mExtents.length();
+
+				ct::CaptureSettings settings;
+				settings.encodeDepth = true;
+				settings.depthEncodeNear = radius;
+				settings.depthEncodeFar = radius + 1; // + 1 arbitrary, make it a customizable value?
+
+				ct::gRenderer()->captureSceneCubeMap(coreTexture, coreProbe->getPosition(), settings);
 				ct::gIBLUtility().filterCubemapForSpecular(coreTexture, nullptr);
 
 				coreProbe->mFilteredTexture = coreTexture;
@@ -113,7 +121,6 @@ namespace bs
 			SPtr<ct::Texture> coreCustomTex = mCustomTexture->getCore();
 			auto filterReflProbe = [coreCustomTex, coreTexture, coreProbe]()
 			{
-				ct::gRenderer()->captureSceneCubeMap(coreTexture, coreProbe->getPosition(), true);
 				ct::gIBLUtility().scaleCubemap(coreCustomTex, 0, coreTexture, 0);
 				ct::gIBLUtility().filterCubemapForSpecular(coreTexture, nullptr);
 

+ 29 - 2
Source/BansheeCore/Renderer/BsRenderer.h

@@ -32,6 +32,32 @@ namespace bs
 		virtual ~RendererOptions() { }
 	};
 
+	/** Settings that control renderer scene capture. */
+	struct CaptureSettings
+	{	
+		/** If true scene will be captured in a format that supports high dynamic range. */
+		bool hdr = true;
+
+		/** 
+		 * When enabled the alpha channel of the final render target will be populated with an encoded depth value. 
+		 * Parameters @p depthEncodeNear and @p depthEncodeFar control which range of the depth buffer to encode.
+		 */
+		bool encodeDepth = false;
+
+		/**
+		 * Controls at which position to start encoding depth, in view space. Only relevant with @p encodeDepth is enabled.
+		 * Depth will be linearly interpolated between this value and @p depthEncodeFar.
+		 */
+		float depthEncodeNear = 0.0f;
+
+		/**
+		 * Controls at which position to stop encoding depth, in view space. Only relevant with @p encodeDepth is enabled.
+		 * Depth will be linearly interpolated between @p depthEncodeNear and this value.
+		 */
+		float depthEncodeFar = 0.0f;
+	};
+
+
 	/**
 	 * Primarily rendering class that allows you to specify how to render objects that exist in the scene graph. You need
 	 * to provide your own implementation of your class.
@@ -188,11 +214,12 @@ namespace bs
 		 * 
 		 * @param[in]	cubemap		Cubemap to store the results in.
 		 * @param[in]	position	Position to capture the scene at.
-		 * @param[in]	hdr			If true scene will be captured in a format that supports high dynamic range.
+		 * @param[in]	settings	Settings that allow you to customize the capture.
 		 *
 		 * @note	Core thread.
 		 */
-		virtual void captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, bool hdr) = 0;
+		virtual void captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, 
+			const CaptureSettings& settings) = 0;
 
 		/**
 		 * Creates a new empty renderer mesh data.

+ 44 - 0
Source/RenderBeast/BsPostProcessing.cpp

@@ -1745,4 +1745,48 @@ namespace bs { namespace ct
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().drawScreenQuad();
 	}
+
+	EncodeDepthParamDef gEncodeDepthParamDef;
+
+	EncodeDepthMat::EncodeDepthMat()
+	{
+		mParamBuffer = gEncodeDepthParamDef.createBuffer();
+		mParamsSet->setParamBlockBuffer("Params", mParamBuffer);
+
+		mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
+
+		GpuParamSampState inputSampState;
+		mParamsSet->getGpuParams()->getSamplerStateParam(GPT_FRAGMENT_PROGRAM, "gInputSamp", inputSampState);
+
+		SAMPLER_STATE_DESC sampDesc;
+		sampDesc.minFilter = FO_POINT;
+		sampDesc.magFilter = FO_POINT;
+		sampDesc.mipFilter = FO_POINT;
+		sampDesc.addressMode.u = TAM_CLAMP;
+		sampDesc.addressMode.v = TAM_CLAMP;
+		sampDesc.addressMode.w = TAM_CLAMP;
+
+		SPtr<SamplerState> samplerState = SamplerState::create(sampDesc);
+		inputSampState.set(samplerState);
+	}
+
+	void EncodeDepthMat::_initVariations(ShaderVariations& variations)
+	{
+		// Do nothing
+	}
+
+	void EncodeDepthMat::execute(const SPtr<Texture>& depth, float near, float far, const SPtr<RenderTarget>& output)
+	{
+		mInputTexture.set(depth);
+
+		gEncodeDepthParamDef.gNear.set(mParamBuffer, near);
+		gEncodeDepthParamDef.gFar.set(mParamBuffer, far);
+
+		RenderAPI& rapi = RenderAPI::instance();
+		rapi.setRenderTarget(output, 0, RT_COLOR0);
+
+		gRendererUtility().setPass(mMaterial);
+		gRendererUtility().setPassParams(mParamsSet);
+		gRendererUtility().drawScreenQuad();
+	}
 }}

+ 35 - 0
Source/RenderBeast/BsPostProcessing.h

@@ -786,5 +786,40 @@ namespace bs { namespace ct
 		void execute();
 	};
 
+	BS_PARAM_BLOCK_BEGIN(EncodeDepthParamDef)
+		BS_PARAM_BLOCK_ENTRY(float, gNear)
+		BS_PARAM_BLOCK_ENTRY(float, gFar)
+	BS_PARAM_BLOCK_END
+
+	extern EncodeDepthParamDef gEncodeDepthParamDef;
+
+	/** 
+	 * Shader that encodes depth from a specified range into [0, 1] range, and writes the result in the alpha channel
+	 * of the output texture. 
+	 */
+	class EncodeDepthMat : public RendererMaterial<EncodeDepthMat>
+	{
+		RMAT_DEF("PPEncodeDepth.bsl");
+
+	public:
+		EncodeDepthMat();
+
+		/** 
+		 * Renders the post-process effect with the provided parameters. 
+		 * 
+		 * @param[in]	depth		Resolved (non-MSAA) depth texture to encode.
+		 * @param[in]	near		Near range (in view space) to start encoding the depth. Any depth lower than this will
+		 *							be encoded to 1.
+		 * @param[in]	far			Far range (in view space) to end encoding the depth. Any depth higher than this will
+		 *							be encoded to 0.
+		 * @param[in]	output		Output texture to write the results in. Results will be written in the alpha channel.
+		 */
+		void execute(const SPtr<Texture>& depth, float near, float far, const SPtr<RenderTarget>& output);
+
+	private:
+		SPtr<GpuParamBlockBuffer> mParamBuffer;
+		GpuParamTexture mInputTexture;
+	};
+
 	/** @} */
 }}

+ 12 - 8
Source/RenderBeast/BsRenderBeast.cpp

@@ -540,7 +540,8 @@ namespace bs { namespace ct
 		bs_frame_clear();
 	}
 
-	void RenderBeast::captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, bool hdr)
+	void RenderBeast::captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, 
+		const CaptureSettings& settings)
 	{
 		const SceneInfo& sceneInfo = mScene->getSceneInfo();
 		auto& texProps = cubemap->getProperties();
@@ -564,6 +565,9 @@ namespace bs { namespace ct
 		viewDesc.triggerCallbacks = false;
 		viewDesc.runPostProcessing = false;
 		viewDesc.renderingReflections = true;
+		viewDesc.encodeDepth = settings.encodeDepth;
+		viewDesc.depthEncodeNear = settings.depthEncodeNear;
+		viewDesc.depthEncodeFar = settings.depthEncodeFar;
 
 		viewDesc.visibleLayers = 0xFFFFFFFFFFFFFFFF;
 		viewDesc.nearPlane = 0.5f;
@@ -577,12 +581,12 @@ namespace bs { namespace ct
 		viewDesc.stateReduction = mCoreOptions->stateReductionMode;
 		viewDesc.sceneCamera = nullptr;
 
-		SPtr<RenderSettings> settings = bs_shared_ptr_new<RenderSettings>();
-		settings->enableHDR = hdr;
-		settings->enableShadows = true;
-		settings->enableIndirectLighting = false;
-		settings->screenSpaceReflections.enabled = false;
-		settings->ambientOcclusion.enabled = false;
+		SPtr<RenderSettings> renderSettings = bs_shared_ptr_new<RenderSettings>();
+		renderSettings->enableHDR = settings.hdr;
+		renderSettings->enableShadows = true;
+		renderSettings->enableIndirectLighting = false;
+		renderSettings->screenSpaceReflections.enabled = false;
+		renderSettings->ambientOcclusion.enabled = false;
 
 		Matrix4 viewOffsetMat = Matrix4::translation(-position);
 
@@ -648,7 +652,7 @@ namespace bs { namespace ct
 			viewDesc.target.target = RenderTexture::create(cubeFaceRTDesc);
 
 			views[i].setView(viewDesc);
-			views[i].setRenderSettings(settings);
+			views[i].setRenderSettings(renderSettings);
 			views[i].updatePerViewBuffer();
 		}
 

+ 2 - 1
Source/RenderBeast/BsRenderBeast.h

@@ -79,7 +79,8 @@ namespace bs
 		void destroy() override;
 
 		/** @copydoc Renderer::captureSceneCubeMap */
-		void captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, bool hdr) override;
+		void captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, 
+			const CaptureSettings& settings) override;
 
 	private:
 		/** @copydoc Renderer::notifyCameraAdded */

+ 12 - 1
Source/RenderBeast/BsRenderCompositor.cpp

@@ -1016,6 +1016,15 @@ namespace bs { namespace ct
 
 		gRendererUtility().blit(input, Rect2I::EMPTY, viewProps.flipView);
 
+		if(viewProps.encodeDepth)
+		{
+			RCNodeResolvedSceneDepth* resolvedSceneDepthNode = static_cast<RCNodeResolvedSceneDepth*>(inputs.inputNodes[0]);
+
+			EncodeDepthMat* encodeDepthMat = EncodeDepthMat::get();
+			encodeDepthMat->execute(resolvedSceneDepthNode->output->texture, viewProps.depthEncodeNear, 
+				viewProps.depthEncodeFar, target);
+		}
+
 		// Trigger overlay callbacks
 		Camera* sceneCamera = inputs.view.getSceneCamera();
 		if (sceneCamera != nullptr)
@@ -1045,9 +1054,11 @@ namespace bs { namespace ct
 		{
 			deps.push_back(RCNodeSceneColor::getNodeId());
 			deps.push_back(RCNodeClusteredForward::getNodeId());
-			
 		}
 
+		if(viewProps.encodeDepth)
+			deps.push_back(RCNodeResolvedSceneDepth::getNodeId());
+
 		return deps;
 	}
 

+ 6 - 0
Source/RenderBeast/BsRendererView.cpp

@@ -67,6 +67,12 @@ namespace bs { namespace ct
 		return get(VAR_Texture);
 	}
 
+	RendererViewData::RendererViewData()
+		:encodeDepth(false), depthEncodeNear(0.0f), depthEncodeFar(0.0f)
+	{
+		
+	}
+
 	RendererViewProperties::RendererViewProperties(const RENDERER_VIEW_DESC& src)
 		:RendererViewData(src), frameIdx(0)
 	{

+ 31 - 0
Source/RenderBeast/BsRendererView.h

@@ -82,6 +82,8 @@ namespace bs { namespace ct
 	/** Data shared between RENDERER_VIEW_DESC and RendererViewProperties */
 	struct RendererViewData
 	{
+		RendererViewData();
+
 		Matrix4 viewTransform;
 		Matrix4 projTransform;
 		Vector3 viewDirection;
@@ -91,10 +93,39 @@ namespace bs { namespace ct
 		float farPlane;
 		ProjectionType projType;
 
+		/** 
+		 * When enabled, renderer extension callbacks will be triggered, allowing other systems to inject their own 
+		 * render operations into the view.
+		 */
 		bool triggerCallbacks : 1;
+
+		/** When enabled, post-processing effects (like tonemapping) will be executed. */
 		bool runPostProcessing : 1;
+
+		/** 
+		 * Determines if the view is currently rendering reflection probes. This ensures the systems can disable refl.
+		 * probe reads in order to prevent incorrect rendering (since probes won't yet have any data).
+		 */
 		bool renderingReflections : 1;
 
+		/** 
+		 * When enabled the alpha channel of the final render target will be populated with an encoded depth value. 
+		 * Parameters @p depthEncodeNear and @p depthEncodeFar control which range of the depth buffer to encode.
+		 */
+		bool encodeDepth : 1;
+
+		/**
+		 * Controls at which position to start encoding depth, in view space. Only relevant with @p encodeDepth is enabled.
+		 * Depth will be linearly interpolated between this value and @p depthEncodeFar.
+		 */
+		float depthEncodeNear;
+
+		/**
+		 * Controls at which position to stop encoding depth, in view space. Only relevant with @p encodeDepth is enabled.
+		 * Depth will be linearly interpolated between @p depthEncodeNear and this value.
+		 */
+		float depthEncodeFar;
+
 		UINT64 visibleLayers;
 		ConvexVolume cullFrustum;
 	};