Jelajahi Sumber

Moved remaining renderer techniques to the node based system, cleaned up obsolete code

BearishSun 8 tahun lalu
induk
melakukan
f278716c61

+ 0 - 22
Source/BansheeEngine/Include/BsIBLUtility.h

@@ -224,12 +224,6 @@ namespace bs { namespace ct
 	class BS_EXPORT IBLUtility
 	{
 	public:
-		/** Sets up any resources requires for operation. Must be called before any other methods in this class. */
-		static void startUp();
-
-		/** Cleans up any resources allocated during startUp(). */
-		static void shutDown();
-
 		/**
 		 * Performs filtering on the cubemap, populating its mip-maps with filtered values that can be used for
 		 * evaluating specular reflections.
@@ -275,16 +269,6 @@ namespace bs { namespace ct
 		 */
 		static void scaleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, UINT32 dstMip);
 
-		/**
-		 * Retrieves a 2D 2-channel texture containing a pre-integrated G and F factors of the microfactet BRDF. This is an
-		 * approximation used for image based lighting, so we can avoid sampling environment maps for each light. Works in
-		 * tandem with the importance sampled reflection cubemaps.
-		 * 
-		 * (u, v) = (NoV, roughness)
-		 * (r, g) = (scale, bias)
-		 */
-		static SPtr<Texture> getPreintegratedEnvBRDF();
-
 		static const UINT32 REFLECTION_CUBEMAP_SIZE;
 		static const UINT32 IRRADIANCE_CUBEMAP_SIZE;
 	private:
@@ -297,12 +281,6 @@ namespace bs { namespace ct
 		 * @param[in]   dstMip			Determines which mip level of the destination texture to scale.
 		 */
 		static void downsampleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, UINT32 dstMip);
-
-		/** Generates the texture returned by getPreIntegratedEnvBRDF(). */
-		static SPtr<Texture> generatePreintegratedEnvBRDF();
-
-		struct Members;
-		static Members* m;
 	};
 
 	/** @} */

+ 4 - 166
Source/BansheeEngine/Source/BsIBLUtility.cpp

@@ -8,28 +8,6 @@
 
 namespace bs { namespace ct
 {
-	struct IBLUtility::Members
-	{
-		ReflectionCubeDownsampleMat downsampleMat;
-		ReflectionCubeImportanceSampleMat importanceSampleMat;
-
-		SPtr<Texture> preIntegratedGF;
-	};
-
-	IBLUtility::Members* IBLUtility::m = nullptr;
-
-	void IBLUtility::startUp()
-	{
-		m = bs_new<Members>();
-
-		m->preIntegratedGF = generatePreintegratedEnvBRDF();
-	}
-
-	void IBLUtility::shutDown()
-	{
-		bs_delete(m);
-	}
-
 	ReflectionCubeDownsampleParamDef gReflectionCubeDownsampleParamDef;
 
 	ReflectionCubeDownsampleMat::ReflectionCubeDownsampleMat()
@@ -355,7 +333,8 @@ namespace bs { namespace ct
 
 				SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
 
-				m->importanceSampleMat.execute(scratchCubemap, face, mip, target);
+				ReflectionCubeImportanceSampleMat* material = ReflectionCubeImportanceSampleMat::get();
+				material->execute(scratchCubemap, face, mip, target);
 			}
 		}
 
@@ -449,11 +428,6 @@ namespace bs { namespace ct
 			downsampleCubemap(scratchTex, srcMip, dst, dstMip);
 	}
 
-	SPtr<Texture> IBLUtility::getPreintegratedEnvBRDF()
-	{
-		return m->preIntegratedGF;
-	}
-
 	void IBLUtility::downsampleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, UINT32 dstMip)
 	{
 		for (UINT32 face = 0; face < 6; face++)
@@ -467,144 +441,8 @@ namespace bs { namespace ct
 			SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
 
 			TextureSurface sourceSurface(srcMip, 1, 0, 6);
-			m->downsampleMat.execute(src, face, sourceSurface, target);
-		}
-	}
-
-	// Reverse bits functions used for Hammersley sequence
-	float reverseBits(UINT32 bits)
-	{
-		bits = (bits << 16u) | (bits >> 16u);
-		bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
-		bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
-		bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
-		bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
-
-		return (float)(double(bits) / (double)0x100000000LL);
-	}
-
-	void hammersleySequence(UINT32 i, UINT32 count, float& e0, float& e1)
-	{
-		e0 = i / (float)count;
-		e1 = reverseBits(i);
-	}
-
-	Vector3 sphericalToCartesian(float cosTheta, float sinTheta, float phi)
-	{
-		Vector3 output;
-		output.x = sinTheta * cos(phi);
-		output.y = sinTheta * sin(phi);
-		output.z = cosTheta;
-
-		return output;
-	}
-
-	// Generates an angle in spherical coordinates, importance sampled for the specified roughness based on some uniformly
-	// distributed random variables in range [0, 1].
-	void importanceSampleGGX(float e0, float e1, float roughness4, float& cosTheta, float& phi)
-	{
-		// See GGXImportanceSample.nb for derivation (essentially, take base GGX, normalize it, generate PDF, split PDF into
-		// marginal probability for theta and conditional probability for phi. Plug those into the CDF, invert it.)				
-		cosTheta = sqrt((1.0f - e0) / (1.0f + (roughness4 - 1.0f) * e0));
-		phi = 2.0f * Math::PI * e1;
-	}
-
-	float calcMicrofacetShadowingSmithGGX(float roughness4, float NoV, float NoL)
-	{
-		// Note: See lighting shader for derivation. Includes microfacet BRDF divisor.
-		float g1V = NoV + sqrt(NoV * (NoV - NoV * roughness4) + roughness4);
-		float g1L = NoL + sqrt(NoL * (NoL - NoL * roughness4) + roughness4);
-		return 1.0f / (g1V * g1L);
-	}
-
-	SPtr<Texture> IBLUtility::generatePreintegratedEnvBRDF()
-	{
-		TEXTURE_DESC desc;
-		desc.type = TEX_TYPE_2D;
-		desc.format = PF_FLOAT16_RG;
-		desc.width = 128;
-		desc.height = 32;
-
-		SPtr<Texture> texture = Texture::create(desc);
-		PixelData pixelData = texture->lock(GBL_WRITE_ONLY_DISCARD);
-
-		for (UINT32 y = 0; y < desc.height; y++)
-		{
-			float roughness = (float)(y + 0.5f) / desc.height;
-			float m = roughness * roughness;
-			float m2 = m*m;
-
-			for (UINT32 x = 0; x < desc.width; x++)
-			{
-				float NoV = (float)(x + 0.5f) / desc.width;
-
-				Vector3 V;
-				V.x = sqrt(1.0f - NoV * NoV); // sine
-				V.y = 0.0f;
-				V.z = NoV;
-
-				// These are the two integrals resulting from the second part of the split-sum approximation. Described in
-				// Epic's 2013 paper:
-				//    http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
-				float scale = 0.0f;
-				float offset = 0.0f;
-
-				// We use the same importance sampling function we use for reflection cube importance sampling, only we
-				// sample G and F, instead of D factors of the microfactet BRDF. See GGXImportanceSample.nb for derivation.
-				constexpr UINT32 NumSamples = 128;
-				for (UINT32 i = 0; i < NumSamples; i++)
-				{
-					float e0, e1;
-					hammersleySequence(i, NumSamples, e0, e1);
-
-					float cosTheta, phi;
-					importanceSampleGGX(e0, e1, m2, cosTheta, phi);
-
-					float sinTheta = sqrt(1.0f - cosTheta * cosTheta);
-					Vector3 H = sphericalToCartesian(cosTheta, sinTheta, phi);
-					Vector3 L = 2.0f * Vector3::dot(V, H) * H - V;
-
-					float VoH = std::max(Vector3::dot(V, H), 0.0f);
-					float NoL = std::max(L.z, 0.0f); // N assumed (0, 0, 1)
-					float NoH = std::max(H.z, 0.0f); // N assumed (0, 0, 1)
-
-					// Set second part of the split sum integral is split into two parts:
-					//   F0*I[G * (1 - (1 - v.h)^5) * cos(theta)] + I[G * (1 - v.h)^5 * cos(theta)] (F0 * scale + bias)
-
-					// We calculate the fresnel scale (1 - (1 - v.h)^5) and bias ((1 - v.h)^5) parts
-					float fc = pow(1.0f - VoH, 5.0f);
-					float fresnelScale = 1.0f - fc;
-					float fresnelOffset = fc;
-
-					// We calculate the G part
-					float G = calcMicrofacetShadowingSmithGGX(m2, NoV, NoL);
-
-					// When we factor out G and F, then divide D by PDF, this is what's left
-					// Note: This is based on PDF: D * NoH / (4 * VoH). (4 * VoH) factor comes from the Jacobian of the
-					// transformation from half vector to light vector
-					float pdfFactor = 4.0f * VoH / NoH;
-
-					if (NoL > 0.0f)
-					{
-						scale += NoL * pdfFactor * G * fresnelScale;
-						offset += NoL * pdfFactor * G * fresnelOffset;
-					}
-				}
-
-				scale /= NumSamples;
-				offset /= NumSamples;
-
-				Color color;
-				color.r = Math::clamp01(scale);
-				color.g = Math::clamp01(offset);
-
-				pixelData.setColorAt(color, x, y);
-			}
+			ReflectionCubeDownsampleMat* material = ReflectionCubeDownsampleMat::get();
+			material->execute(src, face, sourceSurface, target);
 		}
-
-		texture->unlock();
-
-		return texture;
 	}
-
 }}

+ 1 - 5
Source/BansheeEngine/Source/BsRendererUtility.cpp

@@ -122,14 +122,10 @@ namespace bs { namespace ct
 
 			mSkyBoxMesh = Mesh::create(meshData);
 		}
-
-		IBLUtility::startUp();
 	}
 
 	RendererUtility::~RendererUtility()
-	{
-		IBLUtility::shutDown();
-	}
+	{ }
 
 	void RendererUtility::setPass(const SPtr<Material>& material, UINT32 passIdx, UINT32 techniqueIdx)
 	{

+ 2 - 2
Source/RenderBeast/CMakeSources.cmake

@@ -5,7 +5,6 @@ set(BS_RENDERBEAST_INC_NOFILTER
 	"Include/BsRenderBeast.h"
 	"Include/BsRenderBeastFactory.h"
 	"Include/BsRenderBeastPrerequisites.h"
-	"Include/BsRenderTargets.h"
 	"Include/BsObjectRendering.h"
 	"Include/BsLightRendering.h"
 	"Include/BsPostProcessing.h"
@@ -18,6 +17,7 @@ set(BS_RENDERBEAST_INC_NOFILTER
 	"Include/BsStandardDeferredLighting.h"
 	"Include/BsLightProbes.h"
 	"Include/BsRenderCompositor.h"
+	"Include/BsRendererTextures.h"
 )
 
 set(BS_RENDERBEAST_SRC_NOFILTER
@@ -26,7 +26,6 @@ set(BS_RENDERBEAST_SRC_NOFILTER
 	"Source/BsRenderBeast.cpp"
 	"Source/BsRenderBeastFactory.cpp"
 	"Source/BsRenderBeastPlugin.cpp"
-	"Source/BsRenderTargets.cpp"
 	"Source/BsObjectRendering.cpp"
 	"Source/BsLightRendering.cpp"
 	"Source/BsPostProcessing.cpp"
@@ -39,6 +38,7 @@ set(BS_RENDERBEAST_SRC_NOFILTER
 	"Source/BsStandardDeferredLighting.cpp"
 	"Source/BsLightProbes.cpp"
 	"Source/BsRenderCompositor.cpp"
+	"Source/BsRendererTextures.cpp"
 )
 
 source_group("Header Files" FILES ${BS_RENDERBEAST_INC_NOFILTER})

+ 0 - 3
Source/RenderBeast/Include/BsLightRendering.h

@@ -71,9 +71,6 @@ namespace bs { namespace ct
 	public:
 		GBufferParams(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet);
 
-		/** Binds the GBuffer textures to the pipeline. */
-		void bind(const RenderTargets& renderTargets);
-
 		/** Binds the GBuffer textures to the pipeline. */
 		void bind(const GBufferInput& gbuffer);
 	private:

+ 7 - 77
Source/RenderBeast/Include/BsPostProcessing.h

@@ -22,13 +22,6 @@ namespace bs { namespace ct
 	{
 		SPtr<StandardPostProcessSettings> settings;
 		bool settingDirty = true;
-
-		SPtr<PooledRenderTexture> downsampledSceneTex;
-		SPtr<PooledRenderTexture> histogramTex;
-		SPtr<PooledRenderTexture> histogramReduceTex;
-		SPtr<PooledRenderTexture> eyeAdaptationTex[2];
-		SPtr<PooledRenderTexture> colorLUT;
-		INT32 lastEyeAdaptationTex = 0;
 	};
 
 	BS_PARAM_BLOCK_BEGIN(DownsampleParamDef)
@@ -433,24 +426,6 @@ namespace bs { namespace ct
 		GpuParamTexture mInputTexture;
 	};
 
-	/** Builds a hierarchical Z mipmap chain from the source depth texture. */
-	class BuildHiZ
-	{
-	public:
-		/** 
-		 * Renders the post-process effect with the provided parameters. 
-		 * 
-		 * @param[in]	viewInfo	Information about the view we're rendering from.
-		 * @param[in]	source		Input depth texture to use as the source.
-		 * @param[in]	output		Output target to which to write to results. This texture should be created using the
-		 *							descriptor returned by getHiZTextureDesc().
-		 */
-		void execute(const RendererViewTargetData& viewInfo, const SPtr<Texture>& source, const SPtr<Texture>& output);
-
-		/** Generates a descriptor that can be used for creating a texture to contain the HiZ mipmap chain. */
-		static POOLED_RENDER_TEXTURE_DESC getHiZTextureDesc(UINT32 viewWidth, UINT32 viewHeight);
-	};
-
 	BS_PARAM_BLOCK_BEGIN(FXAAParamDef)
 		BS_PARAM_BLOCK_ENTRY(Vector2, gInvTexSize)
 	BS_PARAM_BLOCK_END
@@ -645,32 +620,6 @@ namespace bs { namespace ct
 		static ShaderVariation VAR_Horizontal;
 	};
 
-	/** Helper class that is used for calculating the SSAO information. */
-	class SSAO
-	{
-	public:
-		SSAO();
-
-		/** 
-		 * Calculates SSAO for the specified view. 
-		 * 
-		 * @param[in]	view			Information about the view we're rendering from.
-		 * @param[in]	destination		Output texture to which to write the SSAO data to.
-		 * @param[in]	settings		Settings that control how is SSAO calculated.
-		 */
-		void execute(const RendererView& view, const SPtr<RenderTexture>& destination, 
-			const AmbientOcclusionSettings& settings);
-
-		/**
-		 * 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<Texture> mSSAORandomizationTex;
-	};
-
 	BS_PARAM_BLOCK_BEGIN(SSRStencilParamDef)
 		BS_PARAM_BLOCK_ENTRY(Vector2, gRoughnessScaleBias)
 	BS_PARAM_BLOCK_END
@@ -689,9 +638,10 @@ namespace bs { namespace ct
 		 * Renders the effect with the provided parameters, using the currently bound render target. 
 		 * 
 		 * @param[in]	view			Information about the view we're rendering from.
+		 * @param[in]	gbuffer			GBuffer textures.
 		 * @param[in]	settings		Parameters used for controling the SSR effect.
 		 */
-		void execute(const RendererView& view, const ScreenSpaceReflectionsSettings& settings);
+		void execute(const RendererView& view, GBufferInput gbuffer, const ScreenSpaceReflectionsSettings& settings);
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		GBufferParams mGBufferParams;
@@ -720,10 +670,14 @@ namespace bs { namespace ct
 		 * Renders the effect with the provided parameters. 
 		 * 
 		 * @param[in]	view			Information about the view we're rendering from.
+		 * @param[in]	gbuffer			GBuffer textures.
+		 * @param[in]	sceneColor		Scene color texture.
+		 * @param[in]	hiZ				Hierarchical Z buffer.
 		 * @param[in]	settings		Parameters used for controling the SSR effect.
 		 * @param[in]	destination		Render target to which to write the results to.
 		 */
-		void execute(const RendererView& view, const ScreenSpaceReflectionsSettings& settings, 
+		void execute(const RendererView& view, GBufferInput gbuffer, const SPtr<Texture>& sceneColor, 
+			const SPtr<Texture>& hiZ, const ScreenSpaceReflectionsSettings& settings, 
 			const SPtr<RenderTarget>& destination);
 
 		/**
@@ -796,29 +750,5 @@ namespace bs { namespace ct
 		static ShaderVariation VAR_NoEyeAdaptation;
 	};
 
-	/**
-	 * Renders post-processing effects for the provided render target.
-	 *
-	 * @note	Core thread only.
-	 */
-	class PostProcessing : public Module<PostProcessing>
-	{
-	public:
-		/** 
-		 * 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
-		 * bound for rendering. 
-		 */
-		void postProcess(RendererView* viewInfo, const SPtr<RenderTargets>& renderTargets, float frameDelta);
-		
-		/**
-		 * Populates the ambient occlusion texture of the specified view with screen-space ambient occlusion information.
-		 * Ambient occlusion texture must be allocated on the view's render targets before calling this method.
-		 */
-		void buildSSAO(const RendererView& view);
-	private:
-		SSAO mSSAO;
-	};
-
 	/** @} */
 }}

+ 68 - 0
Source/RenderBeast/Include/BsRenderCompositor.h

@@ -356,6 +356,20 @@ namespace bs { namespace ct
 		void clear() override;
 	};
 
+	/** Renders transparent objects using clustered forward rendering. */
+	class RCNodeClusteredForward : public RenderCompositorNode
+	{
+	public:
+		static StringID getNodeId() { return "ClusteredForward"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+	};
+
 	/**
 	 * In case scene color was rendered into a buffer instead of a texture (if MSAA is used), this node will
 	 * unflatten the buffer and write its contents into the scene color texture.
@@ -495,5 +509,59 @@ namespace bs { namespace ct
 		void clear() override;
 	};
 
+	/************************************************************************/
+	/* 							SCREEN SPACE								*/
+	/************************************************************************/
+
+	/** Resolves the depth buffer (if multi-sampled). Otherwise just references the original depth buffer. */
+	class RCNodeResolvedSceneDepth : public RenderCompositorNode
+	{
+	public:
+		SPtr<PooledRenderTexture> output;
+
+		static StringID getNodeId() { return "ResolvedSceneDepth"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+
+		bool mPassThrough = false;
+	};
+
+	/** Builds the hierarchical Z buffer. */
+	class RCNodeHiZ : public RenderCompositorNode
+	{
+	public:
+		SPtr<PooledRenderTexture> output;
+
+		static StringID getNodeId() { return "HiZ"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+	};
+
+	/** Renders screen space ambient occlusion. */
+	class RCNodeSSAO : public RenderCompositorNode
+	{
+	public:
+		SPtr<PooledRenderTexture> output;
+
+		static StringID getNodeId() { return "SSAO"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+	};
+
 	/** @} */
 }}

+ 0 - 189
Source/RenderBeast/Include/BsRenderTargets.h

@@ -1,189 +0,0 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsRenderBeastPrerequisites.h"
-#include "BsPixelUtil.h"
-#include "BsRendererView.h"
-
-namespace bs { namespace ct
-{
-	/** @addtogroup RenderBeast
-	 *  @{
-	 */
-
-	/** Types of render target textures that can be allocated by RenderTargets manager. */
-	enum RenderTargetType
-	{
-		/** 
-		 * Buffer containing albedo, normals, metalness/roughness and other material data, populated during base pass and
-		 * used during lighting and other operations.
-		 */
-		RTT_GBuffer,
-		/** Buffer containing intermediate lighting information used during deferred lighting pass. */
-		RTT_LightAccumulation,
-		/** Buffer containing temporary combined occlusion data for a specific light (from shadow maps or attenuation. */
-		RTT_LightOcclusion,
-		/** 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,
-		/**
-		 * Buffer containing a hierarchical Z buffer. If passed to RenderTargets::generate() it will build
-		 * the hierarchical Z buffer from the current contents of the scene depth buffer. Generated buffer can be
-		 * accessed from getHiZ(). If using MSAA render targets, make sure to first generate the RTT_ResolvedDepth
-		 * target as HiZ can't be built from multisampled depth buffer.
-		 */
-		RTT_HiZ,
-		/**
-		 * Buffer containing the resolved (non-multisampled) depth buffer. If multisampling isn't used then this will be
-		 * the same buffer as the scene depth buffer. If passed to RenderTargets::generate() it will resolve
-		 * the scene depth buffer into the newly allocated buffer. Scene depth must be previously allocated and populated
-		 * with scene data.
-		 */
-		RTT_ResolvedDepth,
-		/** Buffer containing ambient occlusion. */
-		RTT_AmbientOcclusion
-	};
-
-	/**
-	 * Allocates and handles all the required render targets for rendering a scene from a specific view.
-	 *
-	 * @note	Core thread only.
-	 */
-	class RenderTargets
-	{
-	public:
-		/** 
-		 * Prepares any internal data for rendering. Should be called at the beginning of each frame, before allocating,
-		 * retrieving or binding any textures. Must eventually be followed by cleanup().
-		 */
-		void prepare();
-
-		/**
-		 * Cleans up any internal data after rendering. Should be called after done rendering for a frame. All allocations
-		 * must be released at this point and no further allocations or texture binds should be done until the next call
-		 * to prepare().
-		 */
-		void cleanup();
-
-		/**
-		 * Allocates the textures required for rendering. Allocations are pooled so this is generally a fast operation
-		 * unless the size or other render target options changed. This must be called before binding render targets.
-		 * Some render target types are also automatically populated with data, in which case calling generate() instead
-		 * of allocate is a better option - see individual target descriptions for more details.
-		 */
-		void allocate(RenderTargetType type);
-
-		/**
-		 * Deallocates textures by returning them to the pool. This should be done when the caller is done using the render
-		 * targets, so that other systems might re-use them. This will not release any memory unless all render targets
-		 * pointing to those textures go out of scope.
-		 */
-		void release(RenderTargetType type);
-
-		/**
-		 * Binds the specified render target for rendering, and performs any clear operations as necessary.
-		 */
-		void bind(RenderTargetType type, bool readOnlyDepthStencil = false);
-
-		/**
-		 * Generates contents for the specified render target type. Target must first be allocated by calling allocate().
-		 * Note that not all target types can have their contents automatically generated, most are meant to be populated
-		 * by external code. And those that can usually have prerequisites. See individual target descriptions for more
-		 * details.
-		 */
-		void generate(RenderTargetType type);
-
-		/** Returns a bindable texture for a render target previously allocated using allocate().*/
-		SPtr<Texture> get(RenderTargetType type, RenderSurfaceMaskBits surface = RT_COLOR0) const;
-
-		/** Returns a render target previously allocated using allocate(). */
-		SPtr<RenderTexture> getRT(RenderTargetType type) const;
-
-		/** 
-		 * Flattened, buffer version of the texture returned by get(RTT_SceneColor). Only available when MSAA is used, since
-		 * random writes to multisampled textures aren't supported on all render backends.
-		 */
-		SPtr<GpuBuffer> getSceneColorBuffer() const;
-
-		/**
-		 * Flattened, buffer version of the texture returned by get(RTT_LightAccumulation). Required when MSAA is used, 
-		 * since random writes to multisampled textures aren't supported on all render backends.
-		 */
-		SPtr<GpuBuffer> getLightAccumulationBuffer() const;
-
-		/**	Checks if the targets support HDR rendering. */
-		bool getHDR() const { return mHDR; }
-
-		/**	Returns the number of samples per pixel supported by the targets. */
-		UINT32 getNumSamples() const { return mViewTarget.numSamples; }
-
-		/** Gets the width of the targets, in pixels. */
-		UINT32 getWidth() const { return mWidth; }
-
-		/** Gets the height of the targets, in pixels. */
-		UINT32 getHeight() const { return mHeight; }
-
-		/**
-		 * Creates a new set of render targets. Note in order to actually use the render targets you need to call the
-		 * relevant allocate* method before use.
-		 *
-		 * @param[in]	view			Information about the view that the render targets will be used for. Determines size
-		 *								of the render targets, and the output color render target.
-		 * @param[in]	hdr				Should the render targets support high dynamic range rendering.
-		 */
-		static SPtr<RenderTargets> create(const RENDERER_VIEW_TARGET_DESC& view, bool hdr);
-
-	private:
-		RenderTargets(const RENDERER_VIEW_TARGET_DESC& view, bool hdr);
-
-		/** Returns a pooled texture previously allocated with a call to allocate(). */
-		SPtr<PooledRenderTexture> getPooledTexture(RenderTargetType type, RenderSurfaceMaskBits surface = RT_COLOR0) const;
-
-		RENDERER_VIEW_TARGET_DESC mViewTarget;
-
-		SPtr<PooledRenderTexture> mAlbedoTex;
-		SPtr<PooledRenderTexture> mNormalTex;
-		SPtr<PooledRenderTexture> mRoughMetalTex;
-		SPtr<PooledRenderTexture> mDepthTex;
-
-		SPtr<PooledRenderTexture> mLightAccumulationTex;
-		SPtr<PooledRenderTexture> mLightOcclusionTex;
-		SPtr<PooledStorageBuffer> mFlattenedLightAccumulationBuffer;
-
-		SPtr<PooledRenderTexture> mSceneColorTex;
-		SPtr<PooledStorageBuffer> mFlattenedSceneColorBuffer;
-		SPtr<PooledRenderTexture> mResolvedSceneColorTex1;
-		SPtr<PooledRenderTexture> mResolvedSceneColorTex2;
-
-		SPtr<PooledRenderTexture> mHiZ;
-		SPtr<PooledRenderTexture> mResolvedDepthTex;
-		SPtr<PooledRenderTexture> mAmbientOcclusionTex;
-
-		SPtr<RenderTexture> mGBufferRT;
-		SPtr<RenderTexture> mSceneColorRT;
-		SPtr<RenderTexture> mLightAccumulationRT;
-		SPtr<RenderTexture> mLightOcclusionRT;
-
-		PixelFormat mSceneColorFormat;
-		PixelFormat mAlbedoFormat;
-		PixelFormat mNormalFormat;
-		bool mHDR;
-
-		UINT32 mWidth;
-		UINT32 mHeight;
-
-		BuildHiZ mBuildHiZ;
-	};
-
-	/** @} */
-}}

+ 38 - 0
Source/RenderBeast/Include/BsRendererTextures.h

@@ -0,0 +1,38 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsRenderBeastPrerequisites.h"
+
+namespace bs { namespace ct
+{
+	/** @addtogroup RenderBeast
+	 *  @{
+	 */
+
+	/** Contains static textures required for various render techniques. */
+	class RendererTextures
+	{
+	public:
+		/** Initializes the renderer textures. Must be called before using the textures. */
+		static void startUp();
+
+		/** Cleans up renderer textures. */
+		static void shutDown();
+
+		/**
+		 * 2D 2-channel texture containing a pre-integrated G and F factors of the microfactet BRDF. This is an
+		 * approximation used for image based lighting, so we can avoid sampling environment maps for each light. Works in
+		 * tandem with the importance sampled reflection cubemaps.
+		 * 
+		 * (u, v) = (NoV, roughness)
+		 * (r, g) = (scale, bias)
+		 */
+		static SPtr<Texture> preintegratedEnvGF;
+
+		/** Tileable 4x4 texture to be used for randomization in SSAO rendering. */
+		static SPtr<Texture> ssaoRandomization4x4;
+	};
+
+	/** @} */
+}}

+ 0 - 5
Source/RenderBeast/Include/BsRendererView.h

@@ -212,9 +212,6 @@ namespace bs { namespace ct
 		/** Ends rendering and frees any acquired resources. */
 		void endFrame();
 
-		/** Returns the view's renderTargets. Only valid if called in-between beginRendering() and endRendering() calls. */
-		SPtr<RenderTargets> getRenderTargets() const { return mRenderTargets; }
-
 		/** 
 		 * Returns a render queue containing all opaque objects. Make sure to call determineVisible() beforehand if view 
 		 * or object transforms changed since the last time it was called.
@@ -344,8 +341,6 @@ namespace bs { namespace ct
 		SPtr<RenderQueue> mTransparentQueue;
 
 		RenderCompositor mCompositor;
-
-		SPtr<RenderTargets> mRenderTargets; // TODO - Remove
 		PostProcessInfo mPostProcessInfo;
 
 		SPtr<GpuParamBlockBuffer> mParamBuffer;

+ 0 - 1
Source/RenderBeast/Source/BsImageBasedLighting.cpp

@@ -8,7 +8,6 @@
 #include "BsReflectionProbe.h"
 #include "BsLightProbeCache.h"
 #include "BsGpuParamsSet.h"
-#include "BsRenderTargets.h"
 #include "BsRenderBeast.h"
 #include "BsRendererUtility.h"
 #include "BsSkybox.h"

+ 0 - 1
Source/RenderBeast/Source/BsLightGrid.cpp

@@ -5,7 +5,6 @@
 #include "BsGpuParamsSet.h"
 #include "BsRendererUtility.h"
 #include "BsRendererView.h"
-#include "BsRenderTargets.h"
 #include "BsLightRendering.h"
 #include "BsImageBasedLighting.h"
 

+ 0 - 11
Source/RenderBeast/Source/BsLightRendering.cpp

@@ -4,7 +4,6 @@
 #include "BsMaterial.h"
 #include "BsShader.h"
 #include "BsRenderBeast.h"
-#include "BsRenderTargets.h"
 #include "BsGpuParams.h"
 #include "BsGpuParamsSet.h"
 #include "BsGpuBuffer.h"
@@ -117,16 +116,6 @@ namespace bs { namespace ct
 		material->setSamplerState("gDepthBufferSamp", ss);
 	}
 
-	void GBufferParams::bind(const RenderTargets& renderTargets)
-	{
-		mGBufferA.set(renderTargets.get(RTT_GBuffer, RT_COLOR0));
-		mGBufferB.set(renderTargets.get(RTT_GBuffer, RT_COLOR1));
-		mGBufferC.set(renderTargets.get(RTT_GBuffer, RT_COLOR2));
-		mGBufferDepth.set(renderTargets.get(RTT_GBuffer, RT_DEPTH));
-
-		mMaterial->updateParamsSet(mParamsSet);
-	}
-
 	void GBufferParams::bind(const GBufferInput& gbuffer)
 	{
 		mGBufferA.set(gbuffer.albedo);

+ 8 - 312
Source/RenderBeast/Source/BsPostProcessing.cpp

@@ -8,7 +8,6 @@
 #include "BsCamera.h"
 #include "BsGpuParamsSet.h"
 #include "BsRendererView.h"
-#include "BsRenderTargets.h"
 #include "BsPixelUtil.h"
 #include "BsBitwise.h"
 #include "BsBuiltinResourcesHelper.h"
@@ -977,78 +976,6 @@ namespace bs { namespace ct
 		rapi.setViewport(Rect2(0, 0, 1, 1));
 	}
 
-	void BuildHiZ::execute(const RendererViewTargetData& viewInfo, const SPtr<Texture>& source, const SPtr<Texture>& output)
-	{
-		Rect2 srcRect = viewInfo.nrmViewRect;
-
-		// If viewport size is odd, adjust UV
-		srcRect.width += (viewInfo.viewRect.width % 2) * (1.0f / viewInfo.viewRect.width);
-		srcRect.height += (viewInfo.viewRect.height % 2) * (1.0f / viewInfo.viewRect.height);
-
-		// Generate first mip
-		RENDER_TEXTURE_DESC rtDesc;
-		rtDesc.colorSurfaces[0].texture = output;
-		rtDesc.colorSurfaces[0].mipLevel = 0;
-
-		SPtr<RenderTexture> rt = RenderTexture::create(rtDesc);
-		const TextureProperties& outProps = output->getProperties();
-
-		Rect2 destRect;
-		bool downsampledFirstMip = false; // Not used currently
-		if (downsampledFirstMip)
-		{
-			// Make sure that 1 pixel in HiZ maps to a 2x2 block in source
-			destRect = Rect2(0, 0,
-				Math::ceilToInt(viewInfo.viewRect.width / 2.0f) / (float)outProps.getWidth(),
-				Math::ceilToInt(viewInfo.viewRect.height / 2.0f) / (float)outProps.getHeight());
-
-			BuildHiZMat* material = BuildHiZMat::get();
-			material->execute(source, 0, srcRect, destRect, rt);
-		}
-		else // First level is just a copy of the depth buffer
-		{
-			destRect = Rect2(0, 0,
-				viewInfo.viewRect.width / (float)outProps.getWidth(),
-				viewInfo.viewRect.height / (float)outProps.getHeight());
-
-			RenderAPI& rapi = RenderAPI::instance();
-			rapi.setRenderTarget(rt);
-			rapi.setViewport(destRect);
-
-			Rect2I srcAreaInt;
-			srcAreaInt.x = (INT32)(srcRect.x * viewInfo.viewRect.width);
-			srcAreaInt.y = (INT32)(srcRect.y * viewInfo.viewRect.height);
-			srcAreaInt.width = (UINT32)(srcRect.width * viewInfo.viewRect.width);
-			srcAreaInt.height = (UINT32)(srcRect.height * viewInfo.viewRect.height);
-
-			gRendererUtility().blit(source, srcAreaInt);			
-			rapi.setViewport(Rect2(0, 0, 1, 1));
-		}
-
-		// Generate remaining mip levels
-		for(UINT32 i = 1; i <= outProps.getNumMipmaps(); i++)
-		{
-			rtDesc.colorSurfaces[0].mipLevel = i;
-
-			rt = RenderTexture::create(rtDesc);
-
-			BuildHiZMat* material = BuildHiZMat::get();
-			material->execute(output, i - 1, destRect, destRect, rt);
-		}
-	}
-
-	POOLED_RENDER_TEXTURE_DESC BuildHiZ::getHiZTextureDesc(UINT32 viewWidth, UINT32 viewHeight)
-	{
-		UINT32 size = Bitwise::nextPow2(std::max(viewWidth, viewHeight));
-		UINT32 numMips = PixelUtil::getMaxMipmaps(size, size, 1, PF_FLOAT32_R);
-		size = 1 << numMips;
-
-		// Note: Use the 32-bit buffer here as 16-bit causes too much banding (most of the scene gets assigned 4-5 different
-		// depth values). 
-		//  - When I add UNORM 16-bit format I should be able to switch to that
-		return POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT32_R, size, size, TU_RENDERTARGET, 1, false, 1, numMips);
-	}
-
 	FXAAParamDef gFXAAParamDef;
 
 	FXAAMat::FXAAMat()
@@ -1431,207 +1358,6 @@ namespace bs { namespace ct
 		return get(VAR_Vertical);
 	}
 
-	SSAO::SSAO()
-	{
-		mSSAORandomizationTex = generate4x4RandomizationTexture();
-	}
-
-	void SSAO::execute(const RendererView& view, const SPtr<RenderTexture>& destination, 
-		const AmbientOcclusionSettings& settings)
-	{
-		/** Maximum valid depth range within samples in a sample set. In meters. */
-		static const float DEPTH_RANGE = 1.0f;
-
-		const RendererViewProperties& viewProps = view.getProperties();
-		SPtr<RenderTargets> renderTargets = view.getRenderTargets();
-
-		SPtr<Texture> sceneDepth = renderTargets->get(RTT_ResolvedDepth);
-		SPtr<Texture> sceneNormals = renderTargets->get(RTT_GBuffer, RT_COLOR1);
-
-		const TextureProperties& normalsProps = sceneNormals->getProperties();
-		SPtr<PooledRenderTexture> resolvedNormals;
-		if(sceneNormals->getProperties().getNumSamples() > 1)
-		{
-			POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(normalsProps.getFormat(), 
-				normalsProps.getWidth(), normalsProps.getHeight(), TU_RENDERTARGET);
-			resolvedNormals = GpuResourcePool::instance().get(desc);
-
-			RenderAPI::instance().setRenderTarget(resolvedNormals->renderTexture);
-			gRendererUtility().blit(sceneNormals);
-
-			sceneNormals = resolvedNormals->texture;
-		}
-
-		// Multiple downsampled AO levels are used to minimize cache trashing. Downsampled AO targets use larger radius,
-		// whose contents are then blended with the higher level.
-
-		UINT32 quality = settings.quality;
-		UINT32 numDownsampleLevels = 0;
-		if (quality > 1)
-			numDownsampleLevels = 1;
-		else if (quality > 2)
-			numDownsampleLevels = 2;
-
-
-		SSAODownsampleMat* downsample = SSAODownsampleMat::get();
-
-		SPtr<PooledRenderTexture> setupTex0;
-		if(numDownsampleLevels > 0)
-		{
-			Vector2I downsampledSize(
-				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 2)),
-				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 2))
-			);
-
-			POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RGBA, downsampledSize.x, 
-				downsampledSize.y, TU_RENDERTARGET);
-			setupTex0 = GpuResourcePool::instance().get(desc);
-
-			downsample->execute(view, sceneDepth, sceneNormals, setupTex0->renderTexture, DEPTH_RANGE);
-		}
-
-		SPtr<PooledRenderTexture> setupTex1;
-		if(numDownsampleLevels > 1)
-		{
-			Vector2I downsampledSize(
-				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 4)),
-				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 4))
-			);
-
-			POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RGBA, downsampledSize.x, 
-				downsampledSize.y, TU_RENDERTARGET);
-			setupTex1 = GpuResourcePool::instance().get(desc);
-
-			downsample->execute(view, sceneDepth, sceneNormals, setupTex1->renderTexture, DEPTH_RANGE);
-		}
-
-		SSAOTextureInputs textures;
-		textures.sceneDepth = sceneDepth;
-		textures.sceneNormals = sceneNormals;
-		textures.randomRotations = mSSAORandomizationTex;
-
-		SPtr<PooledRenderTexture> downAOTex1;
-		if(numDownsampleLevels > 1)
-		{
-			textures.aoSetup = setupTex1->texture;
-
-			Vector2I downsampledSize(
-				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 4)),
-				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 4))
-			);
-
-			POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, downsampledSize.x, 
-				downsampledSize.y, TU_RENDERTARGET);
-			downAOTex1 = GpuResourcePool::instance().get(desc);
-
-			SSAOMat* ssaoMat = SSAOMat::getVariation(false, false, quality);
-			ssaoMat->execute(view, textures, downAOTex1->renderTexture, settings);
-
-			GpuResourcePool::instance().release(setupTex1);
-			setupTex1 = nullptr;
-		}
-
-		SPtr<PooledRenderTexture> downAOTex0;
-		if(numDownsampleLevels > 0)
-		{
-			textures.aoSetup = setupTex0->texture;
-
-			if(downAOTex1)
-				textures.aoDownsampled = downAOTex1->texture;
-
-			Vector2I downsampledSize(
-				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 2)),
-				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 2))
-			);
-
-			POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, downsampledSize.x, 
-				downsampledSize.y, TU_RENDERTARGET);
-			downAOTex0 = GpuResourcePool::instance().get(desc);
-
-			bool upsample = numDownsampleLevels > 1;
-			SSAOMat* ssaoMat = SSAOMat::getVariation(upsample, false, quality);
-			ssaoMat->execute(view, textures, downAOTex0->renderTexture, settings);
-
-			if(upsample)
-			{
-				GpuResourcePool::instance().release(downAOTex1);
-				downAOTex1 = nullptr;
-			}
-		}
-
-		{
-			if(setupTex0)
-				textures.aoSetup = setupTex0->texture;
-
-			if(downAOTex0)
-				textures.aoDownsampled = downAOTex0->texture;
-
-			bool upsample = numDownsampleLevels > 0;
-			SSAOMat* ssaoMat = SSAOMat::getVariation(upsample, true, quality);
-			ssaoMat->execute(view, textures, destination, settings);
-		}
-
-		if(resolvedNormals)
-		{
-			GpuResourcePool::instance().release(resolvedNormals);
-			resolvedNormals = nullptr;
-		}
-
-		if(numDownsampleLevels > 0)
-		{
-			GpuResourcePool::instance().release(setupTex0);
-			GpuResourcePool::instance().release(downAOTex0);
-		}
-
-		// Blur the output
-		// Note: If I implement temporal AA then this can probably be avoided. I can instead jitter the sample offsets
-		// each frame, and averaging them out should yield blurred AO.
-		if(quality > 1) // On level 0 we don't blur at all, on level 1 we use the ad-hoc blur in shader
-		{
-			const RenderTargetProperties& rtProps = destination->getProperties();
-
-			POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, rtProps.getWidth(), 
-				rtProps.getHeight(), TU_RENDERTARGET);
-			SPtr<PooledRenderTexture> blurIntermediateTex = GpuResourcePool::instance().get(desc);
-
-			SSAOBlurMat* blurHorz = SSAOBlurMat::getVariation(true);
-			SSAOBlurMat* blurVert = SSAOBlurMat::getVariation(false);
-
-			blurHorz->execute(view, destination->getColorTexture(0), sceneDepth, blurIntermediateTex->renderTexture, 
-				DEPTH_RANGE);
-			blurVert->execute(view, blurIntermediateTex->texture, sceneDepth, destination, DEPTH_RANGE);
-
-			GpuResourcePool::instance().release(blurIntermediateTex);
-		}
-	}
-
-	SPtr<Texture> SSAO::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);
-	}
-
 	SSRStencilParamDef gSSRStencilParamDef;
 
 	SSRStencilMat::SSRStencilMat()
@@ -1646,12 +1372,10 @@ namespace bs { namespace ct
 		// Do nothing
 	}
 
-	void SSRStencilMat::execute(const RendererView& view, const ScreenSpaceReflectionsSettings& settings)
+	void SSRStencilMat::execute(const RendererView& view, GBufferInput gbuffer, 
+		const ScreenSpaceReflectionsSettings& settings)
 	{
-		const RendererViewProperties& viewProps = view.getProperties();
-		RenderTargets& renderTargets = *view.getRenderTargets();
-
-		mGBufferParams.bind(renderTargets);
+		mGBufferParams.bind(gbuffer);
 
 		Vector2 roughnessScaleBias = SSRTraceMat::calcRoughnessFadeScaleBias(settings.maxRoughness);
 		gSSRStencilParamDef.gRoughnessScaleBias.set(mParamBuffer, roughnessScaleBias);
@@ -1684,17 +1408,16 @@ namespace bs { namespace ct
 		// Do nothing
 	}
 
-	void SSRTraceMat::execute(const RendererView& view, const ScreenSpaceReflectionsSettings& settings, 
-		const SPtr<RenderTarget>& destination)
+	void SSRTraceMat::execute(const RendererView& view, GBufferInput gbuffer, const SPtr<Texture>& sceneColor, 
+			const SPtr<Texture>& hiZ, const ScreenSpaceReflectionsSettings& settings, 
+			const SPtr<RenderTarget>& destination)
 	{
 		const RendererViewProperties& viewProps = view.getProperties();
-		RenderTargets& renderTargets = *view.getRenderTargets();
 
-		SPtr<Texture> hiZ = renderTargets.get(RTT_HiZ);
 		const TextureProperties& hiZProps = hiZ->getProperties();
 
-		mGBufferParams.bind(renderTargets);
-		mSceneColorTexture.set(renderTargets.get(RTT_ResolvedSceneColor));
+		mGBufferParams.bind(gbuffer);
+		mSceneColorTexture.set(sceneColor);
 		mHiZTexture.set(hiZ);
 		
 		Rect2I viewRect = viewProps.viewRect;
@@ -1927,31 +1650,4 @@ namespace bs { namespace ct
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().drawScreenQuad();
 	}
-
-	void PostProcessing::postProcess(RendererView* viewInfo, const SPtr<RenderTargets>& renderTargets, float frameDelta)
-	{
-		auto& viewProps = viewInfo->getProperties();
-
-		PostProcessInfo& ppInfo = viewInfo->getPPInfo();
-		const StandardPostProcessSettings& settings = *ppInfo.settings;
-
-		// DEBUG ONLY
-		//SSRTraceMat ssrTrace;
-
-		//renderTargets->allocate(RTT_ResolvedSceneColorSecondary);
-		//SPtr<RenderTarget> target = renderTargets->getRT(RTT_ResolvedSceneColorSecondary);
-
-		//ssrTrace.execute(*viewInfo, ppInfo.settings->screenSpaceReflections, target);
-
-		//RenderAPI::instance().setRenderTarget(renderTargets->getRT(RTT_ResolvedSceneColor));
-		//gRendererUtility().blit(renderTargets->get(RTT_ResolvedSceneColorSecondary));
-	}
-
-	void PostProcessing::buildSSAO(const RendererView& view)
-	{
-		const SPtr<RenderTargets> renderTargets = view.getRenderTargets();
-		const PostProcessInfo& ppInfo = view.getPPInfo();
-
-		mSSAO.execute(view, renderTargets->getRT(RTT_AmbientOcclusion), ppInfo.settings->ambientOcclusion);
-	}
 }}

+ 8 - 42
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -19,7 +19,6 @@
 #include "BsRenderBeastOptions.h"
 #include "BsLight.h"
 #include "BsGpuResourcePool.h"
-#include "BsRenderTargets.h"
 #include "BsRendererUtility.h"
 #include "BsAnimationManager.h"
 #include "BsSkeleton.h"
@@ -35,6 +34,7 @@
 #include "BsStandardDeferredLighting.h"
 #include "BsRenderCompositor.h"
 #include "BsMesh.h"
+#include "BsRendererTextures.h"
 
 using namespace std::placeholders;
 
@@ -70,6 +70,7 @@ namespace bs { namespace ct
 	{
 		RendererUtility::startUp();
 		GpuResourcePool::startUp();
+		RendererTextures::startUp();
 
 		mCoreOptions = bs_shared_ptr_new<RenderBeastOptions>(); 
 		mScene = bs_shared_ptr_new<RendererScene>(mCoreOptions);
@@ -77,7 +78,6 @@ namespace bs { namespace ct
 
 		mMainViewGroup = bs_new<RendererViewGroup>();
 
-		PostProcessing::startUp();
 		StandardDeferred::startUp();
 
 		RenderCompositor::registerNodeType<RCNodeSceneDepth>();
@@ -95,6 +95,10 @@ namespace bs { namespace ct
 		RenderCompositor::registerNodeType<RCNodeTonemapping>();
 		RenderCompositor::registerNodeType<RCNodeGaussianDOF>();
 		RenderCompositor::registerNodeType<RCNodeFXAA>();
+		RenderCompositor::registerNodeType<RCNodeResolvedSceneDepth>();
+		RenderCompositor::registerNodeType<RCNodeHiZ>();
+		RenderCompositor::registerNodeType<RCNodeSSAO>();
+		RenderCompositor::registerNodeType<RCNodeClusteredForward>();
 	}
 
 	void RenderBeast::destroyCore()
@@ -107,10 +111,10 @@ namespace bs { namespace ct
 		RenderCompositor::cleanUp();
 
 		StandardDeferred::shutDown();
-		PostProcessing::shutDown();
 
 		bs_delete(mMainViewGroup);
 
+		RendererTextures::shutDown();
 		GpuResourcePool::shutDown();
 		RendererUtility::shutDown();
 	}
@@ -438,7 +442,7 @@ namespace bs { namespace ct
 				iblParams.skyIrradianceTexParam.set(sceneInfo.sky.irradiance);
 
 				iblParams.reflectionProbeCubemapsTexParam.set(sceneInfo.reflProbeCubemapsTex);
-				iblParams.preintegratedEnvBRDFParam.set(IBLUtility::getPreintegratedEnvBRDF());
+				iblParams.preintegratedEnvBRDFParam.set(RendererTextures::preintegratedEnvGF);
 			}
 		}
 
@@ -460,15 +464,6 @@ namespace bs { namespace ct
 			}
 		}
 
-		// Build HiZ buffer
-		bool isMSAA = numSamples > 1;
-		//// TODO - Avoid generating it unless it actually gets used in some system
-		//if (isMSAA)
-		//{
-		//	renderTargets->allocate(RTT_ResolvedDepth);
-		//	renderTargets->generate(RTT_ResolvedDepth);
-		//}
-
 		// Trigger post-base-pass callbacks
 		if (viewProps.triggerCallbacks)
 		{
@@ -489,35 +484,6 @@ namespace bs { namespace ct
 		compositor.execute(viewGroup, *viewInfo, sceneInfo, frameInfo, *mCoreOptions);
 		viewInfo->getPPInfo().settingDirty = false;
 
-		//renderTargets->allocate(RTT_HiZ);
-		//renderTargets->generate(RTT_HiZ);
-
-		//// Build AO if required
-		//bool useSSAO = viewInfo->getPPInfo().settings->ambientOcclusion.enabled;
-		//if(useSSAO)
-		//{
-		//	renderTargets->allocate(RTT_AmbientOcclusion);
-
-		//	// Note: This could be done as async compute (and started earlier, right after base pass)
-		//	PostProcessing::instance().buildSSAO(*viewInfo);
-		//}
-
-		//if (useSSAO)
-		//	renderTargets->release(RTT_AmbientOcclusion);
-
-		//renderTargets->bind(RTT_SceneColor, false);
-
-		// Render transparent objects
-		// TODO: Transparent objects cannot receive shadows. In order to support this I'd have to render the light occlusion
-		// for all lights affecting this object into a single (or a few) textures. I can likely use texture arrays for this,
-		// or to avoid sampling many textures, perhaps just jam it all in one or few texture channels. 
-		//const Vector<RenderQueueElement>& transparentElements = viewInfo->getTransparentQueue()->getSortedElements();
-		//for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
-		//{
-		//	BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
-		//	renderElement(*renderElem, iter->passIdx, iter->applyPass, viewProj);
-		//}
-
 		// Trigger post-light-pass callbacks
 		if (viewProps.triggerCallbacks)
 		{

+ 360 - 3
Source/RenderBeast/Source/BsRenderCompositor.cpp

@@ -12,6 +12,8 @@
 #include "BsRendererScene.h"
 #include "BsIBLUtility.h"
 #include "BsRenderBeast.h"
+#include "BsBitwise.h"
+#include "BsRendererTextures.h"
 
 namespace bs { namespace ct
 {
@@ -620,7 +622,7 @@ namespace bs { namespace ct
 		iblInputs.gbuffer.depth = sceneDepthNode->depthTex->texture;
 		iblInputs.sceneColorTex = sceneColorNode->sceneColorTex->texture;
 		iblInputs.lightAccumulation = lightAccumNode->lightAccumulationTex->texture;
-		iblInputs.preIntegratedGF = IBLUtility::getPreintegratedEnvBRDF();
+		iblInputs.preIntegratedGF = RendererTextures::preintegratedEnvGF;
 
 		if(sceneColorNode->flattenedSceneColorBuffer)
 			iblInputs.sceneColorBuffer = sceneColorNode->flattenedSceneColorBuffer->buffer;
@@ -667,6 +669,40 @@ namespace bs { namespace ct
 		output = nullptr;
 	}
 
+	void RCNodeClusteredForward::render(const RenderCompositorNodeInputs& inputs)
+	{
+		// TODO: Transparent objects cannot receive shadows. In order to support this I'd have to render the light occlusion
+		// for all lights affecting this object into a single (or a few) textures. I can likely use texture arrays for this,
+		// or to avoid sampling many textures, perhaps just jam it all in one or few texture channels. 
+		const Vector<RenderQueueElement>& transparentElements = inputs.view.getTransparentQueue()->getSortedElements();
+		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
+		{
+			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
+			SPtr<Material> material = renderElem->material;
+
+			if (iter->applyPass)
+				gRendererUtility().setPass(material, iter->passIdx, renderElem->techniqueIdx);
+
+			gRendererUtility().setPassParams(renderElem->params, iter->passIdx);
+
+			if(renderElem->morphVertexDeclaration == nullptr)
+				gRendererUtility().draw(renderElem->mesh, renderElem->subMesh);
+			else
+				gRendererUtility().drawMorph(renderElem->mesh, renderElem->subMesh, renderElem->morphShapeBuffer, 
+					renderElem->morphVertexDeclaration);
+		}
+	}
+
+	void RCNodeClusteredForward::clear()
+	{
+		// Do nothing
+	}
+
+	SmallVector<StringID, 4> RCNodeClusteredForward::getDependencies(const RendererView& view)
+	{
+		return { RCNodeSceneColor::getNodeId(), RCNodeSkybox::getNodeId() };
+	}
+
 	SmallVector<StringID, 4> RCNodeUnflattenSceneColor::getDependencies(const RendererView& view)
 	{
 		return { RCNodeSceneColor::getNodeId() };
@@ -763,7 +799,7 @@ namespace bs { namespace ct
 		else
 		{
 			deps.push_back(RCNodeSceneColor::getNodeId());
-			deps.push_back(RCNodeSkybox::getNodeId());
+			deps.push_back(RCNodeClusteredForward::getNodeId());
 			
 		}
 
@@ -975,7 +1011,7 @@ namespace bs { namespace ct
 
 	SmallVector<StringID, 4> RCNodeTonemapping::getDependencies(const RendererView& view)
 	{
-		return{ RCNodeSceneColor::getNodeId(), RCNodeSkybox::getNodeId(), RCNodePostProcess::getNodeId() };
+		return{ RCNodeSceneColor::getNodeId(), RCNodeClusteredForward::getNodeId(), RCNodePostProcess::getNodeId() };
 	}
 
 	void RCNodeGaussianDOF::render(const RenderCompositorNodeInputs& inputs)
@@ -1088,4 +1124,325 @@ namespace bs { namespace ct
 	{
 		return { RCNodeGaussianDOF::getNodeId(), RCNodePostProcess::getNodeId() };
 	}
+
+	void RCNodeResolvedSceneDepth::render(const RenderCompositorNodeInputs& inputs)
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+		RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[0]);
+
+		if (viewProps.numSamples > 1)
+		{
+			UINT32 width = viewProps.viewRect.width;
+			UINT32 height = viewProps.viewRect.height;
+
+			output = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_D32, width, height, TU_RENDERTARGET, 1, false)); 
+
+			RenderAPI& rapi = RenderAPI::instance();
+			rapi.setRenderTarget(output->renderTexture);
+			gRendererUtility().blit(sceneDepthNode->depthTex->texture, Rect2I::EMPTY, false, true);
+
+			mPassThrough = false;
+		}
+		else
+		{
+			output = sceneDepthNode->depthTex;
+			mPassThrough = true;
+		}
+	}
+
+	void RCNodeResolvedSceneDepth::clear()
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+
+		if (!mPassThrough)
+			resPool.release(output);
+		else
+			output = nullptr;
+
+		mPassThrough = false;
+	}
+
+	SmallVector<StringID, 4> RCNodeResolvedSceneDepth::getDependencies(const RendererView& view)
+	{
+		// GBuffer require because it renders the base pass (populates the depth buffer)
+		return { RCNodeSceneDepth::getNodeId(), RCNodeGBuffer::getNodeId() };
+	}
+
+	void RCNodeHiZ::render(const RenderCompositorNodeInputs& inputs)
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+
+		RCNodeResolvedSceneDepth* resolvedSceneDepth = static_cast<RCNodeResolvedSceneDepth*>(inputs.inputNodes[0]);
+
+		UINT32 width = viewProps.viewRect.width;
+		UINT32 height = viewProps.viewRect.height;
+
+		UINT32 size = Bitwise::nextPow2(std::max(width, height));
+		UINT32 numMips = PixelUtil::getMaxMipmaps(size, size, 1, PF_FLOAT32_R);
+		size = 1 << numMips;
+
+		// Note: Use the 32-bit buffer here as 16-bit causes too much banding (most of the scene gets assigned 4-5 different
+		// depth values). 
+		//  - When I add UNORM 16-bit format I should be able to switch to that
+		output = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT32_R, size, size, TU_RENDERTARGET, 1, false, 1, 
+			numMips));
+
+		Rect2 srcRect = viewProps.nrmViewRect;
+
+		// If viewport size is odd, adjust UV
+		srcRect.width += (viewProps.viewRect.width % 2) * (1.0f / viewProps.viewRect.width);
+		srcRect.height += (viewProps.viewRect.height % 2) * (1.0f / viewProps.viewRect.height);
+
+		// Generate first mip
+		RENDER_TEXTURE_DESC rtDesc;
+		rtDesc.colorSurfaces[0].texture = output->texture;
+		rtDesc.colorSurfaces[0].mipLevel = 0;
+
+		SPtr<RenderTexture> rt = RenderTexture::create(rtDesc);
+
+		Rect2 destRect;
+		bool downsampledFirstMip = false; // Not used currently
+		if (downsampledFirstMip)
+		{
+			// Make sure that 1 pixel in HiZ maps to a 2x2 block in source
+			destRect = Rect2(0, 0,
+				Math::ceilToInt(viewProps.viewRect.width / 2.0f) / (float)size,
+				Math::ceilToInt(viewProps.viewRect.height / 2.0f) / (float)size);
+
+			BuildHiZMat* material = BuildHiZMat::get();
+			material->execute(resolvedSceneDepth->output->texture, 0, srcRect, destRect, rt);
+		}
+		else // First level is just a copy of the depth buffer
+		{
+			destRect = Rect2(0, 0,
+				viewProps.viewRect.width / (float)size,
+				viewProps.viewRect.height / (float)size);
+
+			RenderAPI& rapi = RenderAPI::instance();
+			rapi.setRenderTarget(rt);
+			rapi.setViewport(destRect);
+
+			Rect2I srcAreaInt;
+			srcAreaInt.x = (INT32)(srcRect.x * viewProps.viewRect.width);
+			srcAreaInt.y = (INT32)(srcRect.y * viewProps.viewRect.height);
+			srcAreaInt.width = (UINT32)(srcRect.width * viewProps.viewRect.width);
+			srcAreaInt.height = (UINT32)(srcRect.height * viewProps.viewRect.height);
+
+			gRendererUtility().blit(resolvedSceneDepth->output->texture, srcAreaInt);
+			rapi.setViewport(Rect2(0, 0, 1, 1));
+		}
+
+		// Generate remaining mip levels
+		for(UINT32 i = 1; i <= numMips; i++)
+		{
+			rtDesc.colorSurfaces[0].mipLevel = i;
+
+			rt = RenderTexture::create(rtDesc);
+
+			BuildHiZMat* material = BuildHiZMat::get();
+			material->execute(output->texture, i - 1, destRect, destRect, rt);
+		}
+	}
+
+	void RCNodeHiZ::clear()
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		resPool.release(output);
+	}
+
+	SmallVector<StringID, 4> RCNodeHiZ::getDependencies(const RendererView& view)
+	{
+		// Note: This doesn't actually use any gbuffer textures, but node is a dependency because it renders to the depth
+		// buffer. In order to avoid keeping gbuffer textures alive I could separate out the base pass into its own node
+		// perhaps. But at the moment it doesn't matter, as anything using HiZ also needs gbuffer.
+		return { RCNodeResolvedSceneDepth::getNodeId(), RCNodeGBuffer::getNodeId() };
+	}
+
+	void RCNodeSSAO::render(const RenderCompositorNodeInputs& inputs)
+	{
+		/** Maximum valid depth range within samples in a sample set. In meters. */
+		static const float DEPTH_RANGE = 1.0f;
+
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+		const AmbientOcclusionSettings& settings = inputs.view.getPPInfo().settings->ambientOcclusion;
+
+		RCNodeResolvedSceneDepth* resolvedDepthNode = static_cast<RCNodeResolvedSceneDepth*>(inputs.inputNodes[0]);
+		RCNodeGBuffer* gbufferNode = static_cast<RCNodeGBuffer*>(inputs.inputNodes[1]);
+
+		SPtr<Texture> sceneDepth = resolvedDepthNode->output->texture;
+		SPtr<Texture> sceneNormals = gbufferNode->normalTex->texture;
+
+		const TextureProperties& normalsProps = sceneNormals->getProperties();
+		SPtr<PooledRenderTexture> resolvedNormals;
+
+		RenderAPI& rapi = RenderAPI::instance();
+		if(sceneNormals->getProperties().getNumSamples() > 1)
+		{
+			POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(normalsProps.getFormat(), 
+				normalsProps.getWidth(), normalsProps.getHeight(), TU_RENDERTARGET);
+			resolvedNormals = resPool.get(desc);
+
+			rapi.setRenderTarget(resolvedNormals->renderTexture);
+			gRendererUtility().blit(sceneNormals);
+
+			sceneNormals = resolvedNormals->texture;
+		}
+
+		// Multiple downsampled AO levels are used to minimize cache trashing. Downsampled AO targets use larger radius,
+		// whose contents are then blended with the higher level.
+		UINT32 quality = settings.quality;
+		UINT32 numDownsampleLevels = 0;
+		if (quality > 1)
+			numDownsampleLevels = 1;
+		else if (quality > 2)
+			numDownsampleLevels = 2;
+
+		SSAODownsampleMat* downsample = SSAODownsampleMat::get();
+
+		SPtr<PooledRenderTexture> setupTex0;
+		if(numDownsampleLevels > 0)
+		{
+			Vector2I downsampledSize(
+				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 2)),
+				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 2))
+			);
+
+			POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RGBA, downsampledSize.x, 
+				downsampledSize.y, TU_RENDERTARGET);
+			setupTex0 = GpuResourcePool::instance().get(desc);
+
+			downsample->execute(inputs.view, sceneDepth, sceneNormals, setupTex0->renderTexture, DEPTH_RANGE);
+		}
+
+		SPtr<PooledRenderTexture> setupTex1;
+		if(numDownsampleLevels > 1)
+		{
+			Vector2I downsampledSize(
+				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 4)),
+				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 4))
+			);
+
+			POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RGBA, downsampledSize.x, 
+				downsampledSize.y, TU_RENDERTARGET);
+			setupTex1 = GpuResourcePool::instance().get(desc);
+
+			downsample->execute(inputs.view, sceneDepth, sceneNormals, setupTex1->renderTexture, DEPTH_RANGE);
+		}
+
+		SSAOTextureInputs textures;
+		textures.sceneDepth = sceneDepth;
+		textures.sceneNormals = sceneNormals;
+		textures.randomRotations = RendererTextures::ssaoRandomization4x4;
+
+		SPtr<PooledRenderTexture> downAOTex1;
+		if(numDownsampleLevels > 1)
+		{
+			textures.aoSetup = setupTex1->texture;
+
+			Vector2I downsampledSize(
+				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 4)),
+				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 4))
+			);
+
+			POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, downsampledSize.x, 
+				downsampledSize.y, TU_RENDERTARGET);
+			downAOTex1 = GpuResourcePool::instance().get(desc);
+
+			SSAOMat* ssaoMat = SSAOMat::getVariation(false, false, quality);
+			ssaoMat->execute(inputs.view, textures, downAOTex1->renderTexture, settings);
+
+			GpuResourcePool::instance().release(setupTex1);
+			setupTex1 = nullptr;
+		}
+
+		SPtr<PooledRenderTexture> downAOTex0;
+		if(numDownsampleLevels > 0)
+		{
+			textures.aoSetup = setupTex0->texture;
+
+			if(downAOTex1)
+				textures.aoDownsampled = downAOTex1->texture;
+
+			Vector2I downsampledSize(
+				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.width, 2)),
+				std::max(1, Math::divideAndRoundUp((INT32)viewProps.viewRect.height, 2))
+			);
+
+			POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, downsampledSize.x, 
+				downsampledSize.y, TU_RENDERTARGET);
+			downAOTex0 = GpuResourcePool::instance().get(desc);
+
+			bool upsample = numDownsampleLevels > 1;
+			SSAOMat* ssaoMat = SSAOMat::getVariation(upsample, false, quality);
+			ssaoMat->execute(inputs.view, textures, downAOTex0->renderTexture, settings);
+
+			if(upsample)
+			{
+				GpuResourcePool::instance().release(downAOTex1);
+				downAOTex1 = nullptr;
+			}
+		}
+
+		UINT32 width = viewProps.viewRect.width;
+		UINT32 height = viewProps.viewRect.height;
+		output = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, width, height, TU_RENDERTARGET));
+
+		{
+			if(setupTex0)
+				textures.aoSetup = setupTex0->texture;
+
+			if(downAOTex0)
+				textures.aoDownsampled = downAOTex0->texture;
+
+			bool upsample = numDownsampleLevels > 0;
+			SSAOMat* ssaoMat = SSAOMat::getVariation(upsample, true, quality);
+			ssaoMat->execute(inputs.view, textures, output->renderTexture, settings);
+		}
+
+		if(resolvedNormals)
+		{
+			GpuResourcePool::instance().release(resolvedNormals);
+			resolvedNormals = nullptr;
+		}
+
+		if(numDownsampleLevels > 0)
+		{
+			GpuResourcePool::instance().release(setupTex0);
+			GpuResourcePool::instance().release(downAOTex0);
+		}
+
+		// Blur the output
+		// Note: If I implement temporal AA then this can probably be avoided. I can instead jitter the sample offsets
+		// each frame, and averaging them out should yield blurred AO.
+		if(quality > 1) // On level 0 we don't blur at all, on level 1 we use the ad-hoc blur in shader
+		{
+			const RenderTargetProperties& rtProps = output->renderTexture->getProperties();
+
+			POOLED_RENDER_TEXTURE_DESC desc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, rtProps.getWidth(), 
+				rtProps.getHeight(), TU_RENDERTARGET);
+			SPtr<PooledRenderTexture> blurIntermediateTex = GpuResourcePool::instance().get(desc);
+
+			SSAOBlurMat* blurHorz = SSAOBlurMat::getVariation(true);
+			SSAOBlurMat* blurVert = SSAOBlurMat::getVariation(false);
+
+			blurHorz->execute(inputs.view, output->texture, sceneDepth, blurIntermediateTex->renderTexture, DEPTH_RANGE);
+			blurVert->execute(inputs.view, blurIntermediateTex->texture, sceneDepth, output->renderTexture, DEPTH_RANGE);
+
+			GpuResourcePool::instance().release(blurIntermediateTex);
+		}
+	}
+
+	void RCNodeSSAO::clear()
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		resPool.release(output);
+	}
+
+	SmallVector<StringID, 4> RCNodeSSAO::getDependencies(const RendererView& view)
+	{
+		return { RCNodeResolvedSceneDepth::getNodeId(), RCNodeGBuffer::getNodeId() };
+	}
 }}

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

@@ -1,496 +0,0 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsRenderTargets.h"
-#include "BsGpuResourcePool.h"
-#include "BsViewport.h"
-#include "BsRenderAPI.h"
-#include "BsTextureManager.h"
-#include "BsRendererUtility.h"
-#include "BsGpuBuffer.h"
-
-namespace bs { namespace ct
-{
-	RenderTargets::RenderTargets(const RENDERER_VIEW_TARGET_DESC& view, bool hdr)
-		:mViewTarget(view), mHDR(hdr), mWidth(view.targetWidth), mHeight(view.targetHeight)
-	{
-		// Note: Consider customizable HDR format via options? e.g. smaller PF_FLOAT_R11G11B10 or larger 32-bit format
-		mSceneColorFormat = PF_FLOAT16_RGBA;
-		mAlbedoFormat = PF_R8G8B8A8; // Note: Also consider customizable format (e.g. 16-bit float?)
-		mNormalFormat = PF_UNORM_R10G10B10A2; // Note: Also consider customizable format (e.g. 16-bit float?)
-	}
-
-	SPtr<RenderTargets> RenderTargets::create(const RENDERER_VIEW_TARGET_DESC& view, bool hdr)
-	{
-		return bs_shared_ptr<RenderTargets>(new (bs_alloc<RenderTargets>()) RenderTargets(view, hdr));
-	}
-
-	void RenderTargets::prepare()
-	{
-		GpuResourcePool& texPool = GpuResourcePool::instance();
-
-		UINT32 width = mViewTarget.viewRect.width;
-		UINT32 height = mViewTarget.viewRect.height;
-
-		mDepthTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_D32_S8X24, width, height, TU_DEPTHSTENCIL, 
-			mViewTarget.numSamples, false));
-	}
-
-	void RenderTargets::cleanup()
-	{
-		RenderAPI& rapi = RenderAPI::instance();
-		rapi.setRenderTarget(nullptr);
-
-		GpuResourcePool& texPool = GpuResourcePool::instance();
-		texPool.release(mDepthTex);
-	}
-
-	void RenderTargets::allocate(RenderTargetType type)
-	{
-		GpuResourcePool& texPool = GpuResourcePool::instance();
-
-		UINT32 width = mViewTarget.viewRect.width;
-		UINT32 height = mViewTarget.viewRect.height;
-
-		// Note: This class is keeping all these textures alive for too long (even after they are done for a frame). We
-		// could save on memory by deallocating and reallocating them every frame, but it remains to be seen how much of
-		// a performance impact would that have.
-
-		if (type == RTT_GBuffer)
-		{
-			// Note: Albedo is allocated as SRGB, meaning when reading from textures during depth pass we decode from sRGB
-			// into linear, then back into sRGB when writing to albedo, and back to linear when reading from albedo during
-			// light pass. This /might/ have a performance impact. In which case we could just use a higher precision albedo
-			// buffer, which can then store linear color directly (storing linear in 8bit buffer causes too much detail to
-			// be lost in the blacks).
-			mAlbedoTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mAlbedoFormat, width, height, TU_RENDERTARGET,
-				mViewTarget.numSamples, true));
-			mNormalTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mNormalFormat, width, height, TU_RENDERTARGET,
-				mViewTarget.numSamples, false));
-			mRoughMetalTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RG, width, height, TU_RENDERTARGET,
-				mViewTarget.numSamples, false)); // Note: Metal doesn't need 16-bit float
-
-			bool rebuildRT = false;
-			if (mGBufferRT != nullptr)
-			{
-				rebuildRT |= mGBufferRT->getColorTexture(0) != mAlbedoTex->texture;
-				rebuildRT |= mGBufferRT->getColorTexture(1) != mNormalTex->texture;
-				rebuildRT |= mGBufferRT->getColorTexture(2) != mRoughMetalTex->texture;
-				rebuildRT |= mGBufferRT->getDepthStencilTexture() != mDepthTex->texture;
-			}
-			else
-				rebuildRT = true;
-
-			if (mGBufferRT == nullptr || rebuildRT)
-			{
-				RENDER_TEXTURE_DESC gbufferDesc;
-				gbufferDesc.colorSurfaces[0].texture = mAlbedoTex->texture;
-				gbufferDesc.colorSurfaces[0].face = 0;
-				gbufferDesc.colorSurfaces[0].numFaces = 1;
-				gbufferDesc.colorSurfaces[0].mipLevel = 0;
-
-				gbufferDesc.colorSurfaces[1].texture = mNormalTex->texture;
-				gbufferDesc.colorSurfaces[1].face = 0;
-				gbufferDesc.colorSurfaces[1].numFaces = 1;
-				gbufferDesc.colorSurfaces[1].mipLevel = 0;
-
-				gbufferDesc.colorSurfaces[2].texture = mRoughMetalTex->texture;
-				gbufferDesc.colorSurfaces[2].face = 0;
-				gbufferDesc.colorSurfaces[2].numFaces = 1;
-				gbufferDesc.colorSurfaces[2].mipLevel = 0;
-
-				gbufferDesc.depthStencilSurface.texture = mDepthTex->texture;
-				gbufferDesc.depthStencilSurface.face = 0;
-				gbufferDesc.depthStencilSurface.mipLevel = 0;
-
-				mGBufferRT = RenderTexture::create(gbufferDesc);
-			}
-		}
-		else if(type == RTT_SceneColor)
-		{
-			mSceneColorTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, width,
-				height, TU_RENDERTARGET | TU_LOADSTORE, mViewTarget.numSamples, false));
-
-			if (mViewTarget.numSamples > 1)
-			{
-				UINT32 bufferNumElements = width * height * mViewTarget.numSamples;
-				mFlattenedSceneColorBuffer = texPool.get(POOLED_STORAGE_BUFFER_DESC::createStandard(BF_16X4F, bufferNumElements));
-			}
-
-			bool rebuildRT = false;
-			if (mSceneColorRT != nullptr)
-			{
-				rebuildRT |= mSceneColorRT->getColorTexture(0) != mSceneColorTex->texture;
-				rebuildRT |= mSceneColorRT->getDepthStencilTexture() != mDepthTex->texture;
-			}
-			else
-				rebuildRT = true;
-
-			if (rebuildRT)
-			{
-				RENDER_TEXTURE_DESC sceneColorDesc;
-				sceneColorDesc.colorSurfaces[0].texture = mSceneColorTex->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;
-
-				mSceneColorRT = TextureManager::instance().createRenderTexture(sceneColorDesc);
-			}
-		}
-		else if(type == RTT_LightAccumulation)
-		{
-			if (mViewTarget.numSamples > 1)
-			{
-				UINT32 bufferNumElements = width * height * mViewTarget.numSamples;
-				mFlattenedLightAccumulationBuffer =
-					texPool.get(POOLED_STORAGE_BUFFER_DESC::createStandard(BF_16X4F, bufferNumElements));
-
-				SPtr<GpuBuffer> buffer = mFlattenedLightAccumulationBuffer->buffer;
-
-				auto& bufferProps = buffer->getProperties();
-
-				UINT32 bufferSize = bufferProps.getElementSize() * bufferProps.getElementCount();
-				UINT16* data = (UINT16*)buffer->lock(0, bufferSize, GBL_WRITE_ONLY_DISCARD);
-				{
-					memset(data, 0, bufferSize);
-				}
-				buffer->unlock();
-			}
-
-			mLightAccumulationTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, width,
-				height, TU_LOADSTORE | TU_RENDERTARGET, mViewTarget.numSamples, false));
-
-			bool rebuildRT;
-			if (mLightAccumulationRT != nullptr)
-				rebuildRT = mLightAccumulationRT->getColorTexture(0) != mLightAccumulationTex->texture;
-			else
-				rebuildRT = true;
-
-			if (rebuildRT)
-			{
-				RENDER_TEXTURE_DESC lightAccumulationRTDesc;
-				lightAccumulationRTDesc.colorSurfaces[0].texture = mLightAccumulationTex->texture;
-				lightAccumulationRTDesc.colorSurfaces[0].face = 0;
-				lightAccumulationRTDesc.colorSurfaces[0].numFaces = 1;
-				lightAccumulationRTDesc.colorSurfaces[0].mipLevel = 0;
-
-				mLightAccumulationRT = TextureManager::instance().createRenderTexture(lightAccumulationRTDesc);
-			}
-		}
-		else if(type == RTT_LightOcclusion)
-		{
-			mLightOcclusionTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, width,
-				height, TU_RENDERTARGET, mViewTarget.numSamples, false));
-
-			bool rebuildRT = false;
-			if (mLightOcclusionRT != nullptr)
-			{
-				rebuildRT |= mLightOcclusionRT->getColorTexture(0) != mLightOcclusionTex->texture;
-				rebuildRT |= mLightOcclusionRT->getDepthStencilTexture() != mDepthTex->texture;
-			}
-			else
-				rebuildRT = true;
-
-			if (rebuildRT)
-			{
-				RENDER_TEXTURE_DESC lightOcclusionRTDesc;
-				lightOcclusionRTDesc.colorSurfaces[0].texture = mLightOcclusionTex->texture;
-				lightOcclusionRTDesc.colorSurfaces[0].face = 0;
-				lightOcclusionRTDesc.colorSurfaces[0].numFaces = 1;
-				lightOcclusionRTDesc.colorSurfaces[0].mipLevel = 0;
-
-				lightOcclusionRTDesc.depthStencilSurface.texture = mDepthTex->texture;
-				lightOcclusionRTDesc.depthStencilSurface.face = 0;
-				lightOcclusionRTDesc.depthStencilSurface.numFaces = 1;
-				lightOcclusionRTDesc.depthStencilSurface.mipLevel = 0;
-
-				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));
-			}
-		}
-		else if(type == RTT_ResolvedSceneColorSecondary)
-		{
-			mResolvedSceneColorTex2 = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, 
-				width, height, TU_RENDERTARGET, 1, false));
-		}
-		else if(type == RTT_HiZ)
-		{
-			mHiZ = GpuResourcePool::instance().get(
-				BuildHiZ::getHiZTextureDesc(
-					mViewTarget.viewRect.width, 
-					mViewTarget.viewRect.height)
-			);
-		}
-		else if(type == RTT_ResolvedDepth)
-		{
-			// If not using MSAA, this is equivalent to default depth texture
-			if(mViewTarget.numSamples > 1)
-			{
-				mResolvedDepthTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_D32, width, height, TU_RENDERTARGET,
-					1, false));
-			}
-		}
-		else if(type == RTT_AmbientOcclusion)
-		{
-			mAmbientOcclusionTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, width, height, TU_RENDERTARGET));
-		}
-	}
-
-	void RenderTargets::release(RenderTargetType type)
-	{
-		GpuResourcePool& texPool = GpuResourcePool::instance();
-
-		if (type == RTT_GBuffer)
-		{
-			texPool.release(mSceneColorTex);
-			texPool.release(mAlbedoTex);
-			texPool.release(mNormalTex);
-			texPool.release(mRoughMetalTex);
-		}
-		else if(type == RTT_SceneColor)
-		{
-			texPool.release(mSceneColorTex);
-
-			if (mFlattenedSceneColorBuffer != nullptr)
-				texPool.release(mFlattenedSceneColorBuffer);
-		}
-		else if(type == RTT_LightAccumulation)
-		{
-			if (mLightAccumulationTex != nullptr)
-				texPool.release(mLightAccumulationTex);
-
-			if (mFlattenedLightAccumulationBuffer != nullptr)
-				texPool.release(mFlattenedLightAccumulationBuffer);
-		}
-		else if(type == RTT_LightOcclusion)
-		{
-			if (mLightOcclusionTex != nullptr)
-				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);
-		}
-		else if(type == RTT_HiZ)
-		{
-			if (mHiZ != nullptr)
-				texPool.release(mHiZ);
-		}
-		else if(type == RTT_ResolvedDepth)
-		{
-			if (mResolvedDepthTex != nullptr)
-				texPool.release(mResolvedDepthTex);
-		}
-		else if(type == RTT_AmbientOcclusion)
-		{
-			if (mAmbientOcclusionTex != nullptr)
-				texPool.release(mAmbientOcclusionTex);
-		}
-	}
-
-	void RenderTargets::bind(RenderTargetType type, bool readOnlyDepthStencil)
-	{
-		RenderAPI& rapi = RenderAPI::instance();
-		switch(type)
-		{
-		case RTT_GBuffer:
-		{
-			rapi.setRenderTarget(mGBufferRT);
-
-			Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
-			rapi.setViewport(area);
-
-			// Clear depth & stencil according to user defined values, don't clear color as all values will get written to
-			UINT32 clearFlags = mViewTarget.clearFlags & ~FBT_COLOR;
-			if (clearFlags != 0)
-			{
-				RenderAPI::instance().clearViewport(clearFlags, mViewTarget.clearColor,
-					mViewTarget.clearDepthValue, mViewTarget.clearStencilValue, 0x01);
-			}
-
-			// Clear all non primary targets (Note: I could perhaps clear all but albedo, since it stores a per-pixel write mask)
-			RenderAPI::instance().clearViewport(FBT_COLOR, Color::ZERO, 1.0f, 0, 0xFF & ~0x01);
-		}
-		break;
-		case RTT_SceneColor:
-		{
-			int readOnlyFlags = 0;
-			if (readOnlyDepthStencil)
-				readOnlyFlags = FBT_DEPTH | FBT_STENCIL;
-
-			rapi.setRenderTarget(mSceneColorRT, readOnlyFlags, RT_COLOR0 | RT_DEPTH_STENCIL);
-
-			Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
-			rapi.setViewport(area);
-			
-		}
-		break;
-		case RTT_LightAccumulation:
-			rapi.setRenderTarget(mLightAccumulationRT, FBT_DEPTH | FBT_STENCIL, RT_COLOR0 | RT_DEPTH_STENCIL);
-		break;
-		case RTT_LightOcclusion:
-		{
-			rapi.setRenderTarget(mLightOcclusionRT, FBT_DEPTH, RT_DEPTH_STENCIL);
-
-			Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
-			rapi.setViewport(area);
-
-			RenderAPI::instance().clearViewport(FBT_COLOR, Color::ZERO);
-		}
-		break;
-		default:
-		{
-			int readOnlyFlags = 0;
-			if (readOnlyDepthStencil)
-				readOnlyFlags = FBT_DEPTH | FBT_STENCIL;
-
-			SPtr<RenderTexture> rt = getRT(type);
-			if (rt)
-				rapi.setRenderTarget(rt, readOnlyFlags);
-		}
-		break;
-		}
-	}
-
-	void RenderTargets::generate(RenderTargetType type)
-	{
-		switch(type)
-		{
-		case RTT_HiZ:
-			mBuildHiZ.execute(mViewTarget, get(RTT_ResolvedDepth), mHiZ->texture);
-		break;
-		case RTT_ResolvedSceneColor:
-			if (mViewTarget.numSamples > 1)
-			{
-				RenderAPI::instance().setRenderTarget(mResolvedSceneColorTex1->renderTexture);
-				gRendererUtility().blit(mDepthTex->texture);
-			}
-			break;
-		default:
-			break;
-		}
-	}
-
-	SPtr<Texture> RenderTargets::get(RenderTargetType type, RenderSurfaceMaskBits surface) const
-	{
-		switch(type)
-		{
-		case RTT_ResolvedDepth:
-			if (mViewTarget.numSamples > 1)
-				return mResolvedDepthTex->texture;
-
-			return mDepthTex->texture;
-		case RTT_ResolvedSceneColor:
-			if (mViewTarget.numSamples > 1)
-				return mResolvedSceneColorTex1->texture;
-			else
-				return mSceneColorTex->texture;
-		default:
-		{
-			SPtr<PooledRenderTexture> pooledTex = getPooledTexture(type, surface);
-			if(pooledTex)
-				return pooledTex->texture;
-
-			return nullptr;
-		}
-		}
-	}
-
-	SPtr<RenderTexture> RenderTargets::getRT(RenderTargetType type) const
-	{
-		switch(type)
-		{
-		case RTT_GBuffer:
-			return mGBufferRT;
-		case RTT_SceneColor:
-			return mSceneColorRT;
-		case RTT_LightOcclusion:
-			return mLightOcclusionRT;
-		case RTT_LightAccumulation:
-			return mLightAccumulationRT;
-		case RTT_ResolvedSceneColor:
-			if (mViewTarget.numSamples > 1)
-				return mResolvedSceneColorTex1->renderTexture;
-			else
-				return mSceneColorRT;
-		default:
-		{
-			SPtr<PooledRenderTexture> pooledTex = getPooledTexture(type);
-
-			if(pooledTex)
-				return pooledTex->renderTexture;
-
-			return nullptr;
-		}
-		}
-	}
-
-	SPtr<PooledRenderTexture> RenderTargets::getPooledTexture(RenderTargetType type, RenderSurfaceMaskBits surface) const
-	{
-		switch(type)
-		{
-		case RTT_GBuffer:
-		{
-			switch (surface)
-			{
-			default:
-			case RT_COLOR0:
-				return mAlbedoTex;
-			case RT_COLOR1:
-				return mNormalTex;
-			case RT_COLOR2:
-				return mRoughMetalTex;
-			case RT_DEPTH_STENCIL:
-			case RT_DEPTH:
-				return mDepthTex;
-			}
-		}
-		case RTT_SceneColor:
-			return mSceneColorTex;
-		case RTT_LightAccumulation:
-			return mLightAccumulationTex;
-		case RTT_LightOcclusion:
-			return mLightOcclusionTex;
-		case RTT_ResolvedSceneColor:
-			return mResolvedSceneColorTex1;
-		case RTT_ResolvedSceneColorSecondary:
-			return mResolvedSceneColorTex2;
-		case RTT_HiZ:
-			return mHiZ;
-		case RTT_ResolvedDepth:
-			return mResolvedDepthTex;
-		case RTT_AmbientOcclusion:
-			return mAmbientOcclusionTex;
-		default:
-			return nullptr;
-		}
-	}
-
-	SPtr<GpuBuffer> RenderTargets::getSceneColorBuffer() const
-	{
-		return mFlattenedSceneColorBuffer->buffer;
-	}
-
-	SPtr<GpuBuffer> RenderTargets::getLightAccumulationBuffer() const
-	{
-		return mFlattenedLightAccumulationBuffer->buffer;
-	}
-}}

+ 190 - 0
Source/RenderBeast/Source/BsRendererTextures.cpp

@@ -0,0 +1,190 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsRendererTextures.h"
+#include "BsVector2.h"
+#include "BsColor.h"
+#include "BsMath.h"
+#include "BsTexture.h"
+#include "BsPixelData.h"
+
+namespace bs { namespace ct
+{
+	SPtr<Texture> generate4x4RandomizationTexture()
+	{
+		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);
+	}
+
+	// Reverse bits functions used for Hammersley sequence
+	float reverseBits(UINT32 bits)
+	{
+		bits = (bits << 16u) | (bits >> 16u);
+		bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+		bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+		bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+		bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+
+		return (float)(double(bits) / (double)0x100000000LL);
+	}
+
+	void hammersleySequence(UINT32 i, UINT32 count, float& e0, float& e1)
+	{
+		e0 = i / (float)count;
+		e1 = reverseBits(i);
+	}
+
+	Vector3 sphericalToCartesian(float cosTheta, float sinTheta, float phi)
+	{
+		Vector3 output;
+		output.x = sinTheta * cos(phi);
+		output.y = sinTheta * sin(phi);
+		output.z = cosTheta;
+
+		return output;
+	}
+
+	// Generates an angle in spherical coordinates, importance sampled for the specified roughness based on some uniformly
+	// distributed random variables in range [0, 1].
+	void importanceSampleGGX(float e0, float e1, float roughness4, float& cosTheta, float& phi)
+	{
+		// See GGXImportanceSample.nb for derivation (essentially, take base GGX, normalize it, generate PDF, split PDF into
+		// marginal probability for theta and conditional probability for phi. Plug those into the CDF, invert it.)				
+		cosTheta = sqrt((1.0f - e0) / (1.0f + (roughness4 - 1.0f) * e0));
+		phi = 2.0f * Math::PI * e1;
+	}
+
+	float calcMicrofacetShadowingSmithGGX(float roughness4, float NoV, float NoL)
+	{
+		// Note: See lighting shader for derivation. Includes microfacet BRDF divisor.
+		float g1V = NoV + sqrt(NoV * (NoV - NoV * roughness4) + roughness4);
+		float g1L = NoL + sqrt(NoL * (NoL - NoL * roughness4) + roughness4);
+		return 1.0f / (g1V * g1L);
+	}
+
+	SPtr<Texture> generatePreintegratedEnvBRDF()
+	{
+		TEXTURE_DESC desc;
+		desc.type = TEX_TYPE_2D;
+		desc.format = PF_FLOAT16_RG;
+		desc.width = 128;
+		desc.height = 32;
+
+		SPtr<Texture> texture = Texture::create(desc);
+		PixelData pixelData = texture->lock(GBL_WRITE_ONLY_DISCARD);
+
+		for (UINT32 y = 0; y < desc.height; y++)
+		{
+			float roughness = (float)(y + 0.5f) / desc.height;
+			float m = roughness * roughness;
+			float m2 = m*m;
+
+			for (UINT32 x = 0; x < desc.width; x++)
+			{
+				float NoV = (float)(x + 0.5f) / desc.width;
+
+				Vector3 V;
+				V.x = sqrt(1.0f - NoV * NoV); // sine
+				V.y = 0.0f;
+				V.z = NoV;
+
+				// These are the two integrals resulting from the second part of the split-sum approximation. Described in
+				// Epic's 2013 paper:
+				//    http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
+				float scale = 0.0f;
+				float offset = 0.0f;
+
+				// We use the same importance sampling function we use for reflection cube importance sampling, only we
+				// sample G and F, instead of D factors of the microfactet BRDF. See GGXImportanceSample.nb for derivation.
+				constexpr UINT32 NumSamples = 128;
+				for (UINT32 i = 0; i < NumSamples; i++)
+				{
+					float e0, e1;
+					hammersleySequence(i, NumSamples, e0, e1);
+
+					float cosTheta, phi;
+					importanceSampleGGX(e0, e1, m2, cosTheta, phi);
+
+					float sinTheta = sqrt(1.0f - cosTheta * cosTheta);
+					Vector3 H = sphericalToCartesian(cosTheta, sinTheta, phi);
+					Vector3 L = 2.0f * Vector3::dot(V, H) * H - V;
+
+					float VoH = std::max(Vector3::dot(V, H), 0.0f);
+					float NoL = std::max(L.z, 0.0f); // N assumed (0, 0, 1)
+					float NoH = std::max(H.z, 0.0f); // N assumed (0, 0, 1)
+
+					// Set second part of the split sum integral is split into two parts:
+					//   F0*I[G * (1 - (1 - v.h)^5) * cos(theta)] + I[G * (1 - v.h)^5 * cos(theta)] (F0 * scale + bias)
+
+					// We calculate the fresnel scale (1 - (1 - v.h)^5) and bias ((1 - v.h)^5) parts
+					float fc = pow(1.0f - VoH, 5.0f);
+					float fresnelScale = 1.0f - fc;
+					float fresnelOffset = fc;
+
+					// We calculate the G part
+					float G = calcMicrofacetShadowingSmithGGX(m2, NoV, NoL);
+
+					// When we factor out G and F, then divide D by PDF, this is what's left
+					// Note: This is based on PDF: D * NoH / (4 * VoH). (4 * VoH) factor comes from the Jacobian of the
+					// transformation from half vector to light vector
+					float pdfFactor = 4.0f * VoH / NoH;
+
+					if (NoL > 0.0f)
+					{
+						scale += NoL * pdfFactor * G * fresnelScale;
+						offset += NoL * pdfFactor * G * fresnelOffset;
+					}
+				}
+
+				scale /= NumSamples;
+				offset /= NumSamples;
+
+				Color color;
+				color.r = Math::clamp01(scale);
+				color.g = Math::clamp01(offset);
+
+				pixelData.setColorAt(color, x, y);
+			}
+		}
+
+		texture->unlock();
+
+		return texture;
+	}
+
+	SPtr<Texture> RendererTextures::preintegratedEnvGF;
+	SPtr<Texture> RendererTextures::ssaoRandomization4x4;
+
+	void RendererTextures::startUp()
+	{
+		preintegratedEnvGF = generatePreintegratedEnvBRDF();
+		ssaoRandomization4x4 = generate4x4RandomizationTexture();
+	}
+
+	void RendererTextures::shutDown()
+	{
+		preintegratedEnvGF = nullptr;
+		ssaoRandomization4x4 = nullptr;
+		
+	}
+}}

+ 0 - 20
Source/RenderBeast/Source/BsRendererView.cpp

@@ -5,7 +5,6 @@
 #include "BsRenderable.h"
 #include "BsMaterial.h"
 #include "BsShader.h"
-#include "BsRenderTargets.h"
 #include "BsRendererUtility.h"
 #include "BsLightRendering.h"
 #include "BsGpuParamsSet.h"
@@ -139,10 +138,6 @@ namespace bs { namespace ct
 
 	void RendererView::setView(const RENDERER_VIEW_DESC& desc)
 	{
-		if (mTargetDesc.targetWidth != desc.target.targetWidth ||
-			mTargetDesc.targetHeight != desc.target.targetHeight)
-			mRenderTargets = nullptr;
-
 		mCamera = desc.sceneCamera;
 		mProperties = desc;
 		mTargetDesc = desc.target;
@@ -152,18 +147,6 @@ namespace bs { namespace ct
 
 	void RendererView::beginFrame()
 	{
-		if (!mProperties.isOverlay)
-		{
-			// Render scene objects to g-buffer
-			bool createGBuffer = mRenderTargets == nullptr ||
-				mRenderTargets->getHDR() != mProperties.isHDR ||
-				mRenderTargets->getNumSamples() != mTargetDesc.numSamples;
-
-			if (createGBuffer)
-				mRenderTargets = RenderTargets::create(mTargetDesc, mProperties.isHDR);
-
-			mRenderTargets->prepare();
-		}
 	}
 
 	void RendererView::endFrame()
@@ -173,9 +156,6 @@ namespace bs { namespace ct
 
 		mOpaqueQueue->clear();
 		mTransparentQueue->clear();
-
-		if(!mProperties.isOverlay)
-			mRenderTargets->cleanup();
 	}
 
 	void RendererView::determineVisible(const Vector<RendererObject*>& renderables, const Vector<CullInfo>& cullInfos,

+ 0 - 3
Source/RenderBeast/Source/BsShadowRendering.cpp

@@ -860,8 +860,6 @@ namespace bs { namespace ct
 				bool viewerInsideVolume = (light->getPosition() - viewProps.viewOrigin).length() < lightRadius;
 
 				SPtr<Texture> shadowMap = mShadowCubemaps[shadowInfo.textureIdx].getTexture();
-				SPtr<RenderTargets> renderTargets = view->getRenderTargets();
-
 				ShadowProjectParams shadowParams(*light, shadowMap, 0, shadowOmniParamBuffer, perViewBuffer, gbuffer);
 
 				ShadowProjectOmniMat* mat = ShadowProjectOmniMat::getVariation(effectiveShadowQuality, viewerInsideVolume, 
@@ -985,7 +983,6 @@ namespace bs { namespace ct
 					shadowMapFace = shadowInfo->cascadeIdx;
 				}
 
-				SPtr<RenderTargets> renderTargets = view->getRenderTargets();
 				ShadowProjectParams shadowParams(*light, shadowMap, shadowMapFace, shadowParamBuffer, perViewBuffer, 
 					gbuffer);
 

+ 0 - 1
Source/RenderBeast/Source/BsStandardDeferredLighting.cpp

@@ -4,7 +4,6 @@
 #include "BsRendererUtility.h"
 #include "BsRendererView.h"
 #include "BsGpuParamsSet.h"
-#include "BsRenderTargets.h"
 #include "BsMesh.h"
 
 namespace bs { namespace ct {