Forráskód Böngészése

Merge branch 'render-refactor'

BearishSun 8 éve
szülő
commit
fbfbb339af
69 módosított fájl, 4730 hozzáadás és 3585 törlés
  1. 1 1
      Data/Raw/Engine/Shaders/Skybox.bsl
  2. 44 6
      Documentation/Manuals/Native/customRenderer.md
  3. 3 3
      Source/BansheeCore/CMakeSources.cmake
  4. 4 10
      Source/BansheeCore/Include/BsCCamera.h
  5. 35 66
      Source/BansheeCore/Include/BsCamera.h
  6. 2 4
      Source/BansheeCore/Include/BsCameraRTTI.h
  7. 8 1
      Source/BansheeCore/Include/BsCorePrerequisites.h
  8. 0 55
      Source/BansheeCore/Include/BsPostProcessSettings.h
  9. 0 43
      Source/BansheeCore/Include/BsPostProcessSettingsRTTI.h
  10. 61 18
      Source/BansheeCore/Include/BsRenderSettings.h
  11. 18 14
      Source/BansheeCore/Include/BsRenderSettingsRTTI.h
  12. 1 4
      Source/BansheeCore/Include/BsRenderer.h
  13. 1 1
      Source/BansheeCore/Source/BsAnimationManager.cpp
  14. 9 22
      Source/BansheeCore/Source/BsCamera.cpp
  15. 0 17
      Source/BansheeCore/Source/BsPostProcessSettings.cpp
  16. 23 11
      Source/BansheeCore/Source/BsRenderSettings.cpp
  17. 3 1
      Source/BansheeEditor/Source/BsEditorWindowBase.cpp
  18. 0 3
      Source/BansheeEngine/CMakeSources.cmake
  19. 27 24
      Source/BansheeEngine/Include/BsIBLUtility.h
  20. 7 8
      Source/BansheeEngine/Include/BsPrerequisites.h
  21. 166 8
      Source/BansheeEngine/Include/BsRendererMaterial.h
  22. 1 0
      Source/BansheeEngine/Include/BsRendererMaterialManager.h
  23. 24 20
      Source/BansheeEngine/Include/BsRendererUtility.h
  24. 81 70
      Source/BansheeEngine/Source/BsIBLUtility.cpp
  25. 70 0
      Source/BansheeEngine/Source/BsRendererMaterial.cpp
  26. 50 10
      Source/BansheeEngine/Source/BsRendererMaterialManager.cpp
  27. 91 73
      Source/BansheeEngine/Source/BsRendererUtility.cpp
  28. 25 1
      Source/BansheeUtility/Include/BsStringID.h
  29. 2 1
      Source/Examples/ExampleGettingStarted/Source/Main.cpp
  30. 15 25
      Source/MBansheeEditor/Inspectors/CameraInspector.cs
  31. 31 6
      Source/MBansheeEditor/Inspectors/RenderSettingsInspector.cs
  32. 1 1
      Source/MBansheeEditor/MBansheeEditor.csproj
  33. 1 1
      Source/MBansheeEditor/Windows/Scene/SceneAxesGUI.cs
  34. 1 1
      Source/MBansheeEditor/Windows/Scene/SceneWindow.cs
  35. 5 27
      Source/MBansheeEngine/Interop/NativeCamera.cs
  36. 1 1
      Source/MBansheeEngine/MBansheeEngine.csproj
  37. 5 29
      Source/MBansheeEngine/Rendering/Camera.cs
  38. 31 6
      Source/MBansheeEngine/Rendering/RenderSettings.cs
  39. 4 2
      Source/RenderBeast/CMakeSources.cmake
  40. 39 106
      Source/RenderBeast/Include/BsImageBasedLighting.h
  41. 0 3
      Source/RenderBeast/Include/BsLightGrid.h
  42. 24 65
      Source/RenderBeast/Include/BsLightRendering.h
  43. 147 332
      Source/RenderBeast/Include/BsPostProcessing.h
  44. 7 37
      Source/RenderBeast/Include/BsRenderBeast.h
  45. 567 0
      Source/RenderBeast/Include/BsRenderCompositor.h
  46. 0 190
      Source/RenderBeast/Include/BsRenderTargets.h
  47. 30 1
      Source/RenderBeast/Include/BsRendererScene.h
  48. 38 0
      Source/RenderBeast/Include/BsRendererTextures.h
  49. 71 30
      Source/RenderBeast/Include/BsRendererView.h
  50. 57 93
      Source/RenderBeast/Include/BsShadowRendering.h
  51. 21 14
      Source/RenderBeast/Include/BsStandardDeferredLighting.h
  52. 103 286
      Source/RenderBeast/Source/BsImageBasedLighting.cpp
  53. 25 13
      Source/RenderBeast/Source/BsLightGrid.cpp
  54. 90 101
      Source/RenderBeast/Source/BsLightRendering.cpp
  55. 1 1
      Source/RenderBeast/Source/BsObjectRendering.cpp
  56. 279 388
      Source/RenderBeast/Source/BsPostProcessing.cpp
  57. 142 490
      Source/RenderBeast/Source/BsRenderBeast.cpp
  58. 1577 0
      Source/RenderBeast/Source/BsRenderCompositor.cpp
  59. 0 496
      Source/RenderBeast/Source/BsRenderTargets.cpp
  60. 71 12
      Source/RenderBeast/Source/BsRendererScene.cpp
  61. 190 0
      Source/RenderBeast/Source/BsRendererTextures.cpp
  62. 81 52
      Source/RenderBeast/Source/BsRendererView.cpp
  63. 178 120
      Source/RenderBeast/Source/BsShadowRendering.cpp
  64. 77 75
      Source/RenderBeast/Source/BsStandardDeferredLighting.cpp
  65. 2 2
      Source/SBansheeEngine/CMakeSources.cmake
  66. 3 9
      Source/SBansheeEngine/Include/BsScriptCamera.h
  67. 11 7
      Source/SBansheeEngine/Include/BsScriptRenderSettings.h
  68. 12 49
      Source/SBansheeEngine/Source/BsScriptCamera.cpp
  69. 35 19
      Source/SBansheeEngine/Source/BsScriptRenderSettings.cpp

+ 1 - 1
Data/Raw/Engine/Shaders/Skybox.bsl

@@ -42,7 +42,7 @@ technique Skybox
 			in float4 inPos : SV_Position, 
 			in float4 inPos : SV_Position, 
 			in float3 dir : TEXCOORD0) : SV_Target
 			in float3 dir : TEXCOORD0) : SV_Target
 		{
 		{
-			#ifdef SOLID_COLOR
+			#if SOLID_COLOR
 				return gClearColor;
 				return gClearColor;
 			#else
 			#else
 				return gSkyTex.SampleLevel(gSkySamp, dir, 0);
 				return gSkyTex.SampleLevel(gSkySamp, dir, 0);

+ 44 - 6
Documentation/Manuals/Native/customRenderer.md

@@ -182,7 +182,14 @@ class DownsampleMat : public RendererMaterial<DownsampleMat>
 };
 };
 ~~~~~~~~~~~~~
 ~~~~~~~~~~~~~
 
 
-After that you can simply instantiate your renderer material, and access the underlying material by calling @ref bs::ct::RendererMaterial::getMaterial() "ct::RendererMaterial::getMaterial()", and the material parameters by calling @ref bs::ct::RendererMaterial::getParamsSet() "ct::RendererMaterial::getParamsSet()". Then you can bind the material for rendering as normal (using **RendererUtility** or directly through **RenderAPI**).
+Once defined the renderer material can be accessed through the static @ref bs::ct::RendererMaterial::get<T>() "ct::RendererMaterial::get<T>()" method. Underlying material can be accessed by calling @ref bs::ct::RendererMaterial::getMaterial() "ct::RendererMaterial::getMaterial()", and the material parameters by calling @ref bs::ct::RendererMaterial::getParamsSet() "ct::RendererMaterial::getParamsSet()". Then you can bind the material for rendering as normal (using **RendererUtility** or directly through **RenderAPI**).
+
+~~~~~~~~~~~~~{.cpp}
+DownsampleMat* renderMat = DownsampleMat::get():
+SPtr<Material> material = renderMat->getMaterial();
+
+// Render using the material as normal
+~~~~~~~~~~~~~
 
 
 You will normally also want to add a constructor in which you look up any necessary parameters the material might require, so they can be set more easily when rendering.
 You will normally also want to add a constructor in which you look up any necessary parameters the material might require, so they can be set more easily when rendering.
 ~~~~~~~~~~~~~{.cpp}
 ~~~~~~~~~~~~~{.cpp}
@@ -213,7 +220,7 @@ class DownsampleMat : public RendererMaterial<DownsampleMat>
 	// Set up parameters and render a full screen quad using the material
 	// Set up parameters and render a full screen quad using the material
 	void execute(const SPtr<Texture>& input)
 	void execute(const SPtr<Texture>& input)
 	{
 	{
-		// Actually assign parameters before rendering
+		// Assign parameters before rendering
 		mInputTexture.set(input);
 		mInputTexture.set(input);
 		
 		
 		const TextureProperties& props = input->getProperties();
 		const TextureProperties& props = input->getProperties();
@@ -233,17 +240,48 @@ class DownsampleMat : public RendererMaterial<DownsampleMat>
 };
 };
 ~~~~~~~~~~~~~
 ~~~~~~~~~~~~~
 
 
-Renderer materials also support variations for cases where you might require slightly different versions of a shader for different use cases. The variations are handled by setting up preprocessor \#defines, which the shader code can then use to conditionally add or remove parts of code (via \#ifdef or similar). To determine which defines are set implement the _initDefines() method in your **RendererMaterial** implementation, and append your defines to the @ref bs::ShaderDefines "ShaderDefines" object. Note that this method must be present, even if not using any defines.
+Renderer materials also support variations for cases where you might require slightly different versions of a shader for different use cases. The variations are handled by setting up preprocessor \#defines, which the shader code can then use to conditionally add or remove parts of code (via \#if or similar). To determine which defines are set implement the _initVariations() method in your **RendererMaterial** implementation, and append your defines to the @ref bs::ct::ShaderVariations "ShaderVariations" object. Note that this method must be present, even if not using any variations (simply leave it empty).
 
 
 ~~~~~~~~~~~~~{.cpp}
 ~~~~~~~~~~~~~{.cpp}
+// Make our downsample shader come in two variations
+class DownsampleMat : public RendererMaterial<DownsampleMat>
+{
+	RMAT_DEF("Downsample.bsl");
+	
+	// ... other DownsampleMat code ...
+	
+private:
+	static ShaderVariation VAR_PointFiltering;
+	static ShaderVariation VAR_BilinearFiltering;
+};
+
+// Set up optional defines to control shader compilation
+ShaderVariation DownsampleMat::VAR_PointFiltering = ShaderVariation({
+	ShaderVariation::Param("BILINEAR_FILTERING", false)
+});
+
+ShaderVariation DownsampleMat::VAR_BilinearFiltering = ShaderVariation({
+	ShaderVariation::Param("BILINEAR_FILTERING", true)
+});
+
 // Method defined in RMAT_DEF macro
 // Method defined in RMAT_DEF macro
-void DownsampleMat::_initDefines(ShaderDefines& defines)
+void DownsampleMat::_initVariations(ShaderVariations& variations)
 {
 {
-	// Set up optional defines to control shader compilation
-	defines.set("BILINEAR_FILTERING", 1);
+	variations.add(VAR_PointFiltering);
+	variations.add(VAR_BilinearFiltering);
 }
 }
 ~~~~~~~~~~~~~
 ~~~~~~~~~~~~~
 
 
+Specific variation of the material can the be retrieved by calling the static @ref bs::ct::RendererMaterial::get<T>(const ShaderVariation&) "ct::RendererMaterial::get<T>(const ShaderVariation&)" method.
+
+~~~~~~~~~~~~~{.cpp}
+// Get the variation that performs bilinear filtering
+DownsampleMat* renderMat = DownsampleMat::get(VAR_BilinearFiltering):
+SPtr<Material> material = renderMat->getMaterial();
+
+// Render using the material as normal
+~~~~~~~~~~~~~
+
 > All builtin shaders are cached. The system will automatically pick up any changes to shaders in *Data/Raw/Engine* folder and rebuild the cache when needed. However if you are changing defines as above you must manually force the system to rebuild by deleting the *Timestamp.asset* file in *Data/Engine* folder.
 > All builtin shaders are cached. The system will automatically pick up any changes to shaders in *Data/Raw/Engine* folder and rebuild the cache when needed. However if you are changing defines as above you must manually force the system to rebuild by deleting the *Timestamp.asset* file in *Data/Engine* folder.
 
 
 ## Parameter blocks {#renderer_c_d}
 ## Parameter blocks {#renderer_c_d}

+ 3 - 3
Source/BansheeCore/CMakeSources.cmake

@@ -97,7 +97,7 @@ set(BS_BANSHEECORE_INC_RENDERER
 	"Include/BsRendererMeshData.h"
 	"Include/BsRendererMeshData.h"
 	"Include/BsParamBlocks.h"
 	"Include/BsParamBlocks.h"
 	"Include/BsCamera.h"
 	"Include/BsCamera.h"
-	"Include/BsPostProcessSettings.h"
+	"Include/BsRenderSettings.h"
 	"Include/BsRendererExtension.h"
 	"Include/BsRendererExtension.h"
 	"Include/BsReflectionProbe.h"
 	"Include/BsReflectionProbe.h"
 	"Include/BsSkybox.h"
 	"Include/BsSkybox.h"
@@ -350,7 +350,7 @@ set(BS_BANSHEECORE_INC_RTTI
 	"Include/BsSkeletonRTTI.h"
 	"Include/BsSkeletonRTTI.h"
 	"Include/BsCCameraRTTI.h"
 	"Include/BsCCameraRTTI.h"
 	"Include/BsCameraRTTI.h"
 	"Include/BsCameraRTTI.h"
-	"Include/BsPostProcessSettingsRTTI.h"
+	"Include/BsRenderSettingsRTTI.h"
 	"Include/BsMorphShapesRTTI.h"
 	"Include/BsMorphShapesRTTI.h"
 	"Include/BsAudioClipImportOptionsRTTI.h"
 	"Include/BsAudioClipImportOptionsRTTI.h"
 	"Include/BsCRenderableRTTI.h"
 	"Include/BsCRenderableRTTI.h"
@@ -373,7 +373,7 @@ set(BS_BANSHEECORE_SRC_RENDERER
 	"Source/BsRendererMeshData.cpp"
 	"Source/BsRendererMeshData.cpp"
 	"Source/BsParamBlocks.cpp"
 	"Source/BsParamBlocks.cpp"
 	"Source/BsCamera.cpp"
 	"Source/BsCamera.cpp"
-	"Source/BsPostProcessSettings.cpp"
+	"Source/BsRenderSettings.cpp"
 	"Source/BsRendererExtension.cpp"
 	"Source/BsRendererExtension.cpp"
 	"Source/BsReflectionProbe.cpp"
 	"Source/BsReflectionProbe.cpp"
 	"Source/BsSkybox.cpp"
 	"Source/BsSkybox.cpp"

+ 4 - 10
Source/BansheeCore/Include/BsCCamera.h

@@ -142,17 +142,11 @@ namespace bs
 		/** @copydoc Camera::setMSAACount */
 		/** @copydoc Camera::setMSAACount */
 		void setMSAACount(UINT32 count) { mInternal->setMSAACount(count); }
 		void setMSAACount(UINT32 count) { mInternal->setMSAACount(count); }
 
 
-		/** Returns settings that are used for controling post-process operations like tonemapping. */
-		const SPtr<PostProcessSettings>& getPostProcessSettings() const { return mInternal->getPostProcessSettings(); }
+		/** @copydoc Camera::getRenderSettings() */
+		const SPtr<RenderSettings>& getRenderSettings() const { return mInternal->getRenderSettings(); }
 
 
-		/** Sets settings that are used for controling post-process operations like tonemapping. */
-		void setPostProcessSettings(const SPtr<PostProcessSettings>& settings) { mInternal->setPostProcessSettings(settings); }
-
-		/** @copydoc Camera::getFlags */
-		CameraFlags getFlags() const { return mInternal->getFlags(); }
-
-		/** @copydoc Camera::setFlag */
-		void setFlag(const CameraFlag& flag, bool enable) { mInternal->setFlag(flag, enable); }
+		/** @copydoc Camera::setRenderSettings() */
+		void setRenderSettings(const SPtr<RenderSettings>& settings) { mInternal->setRenderSettings(settings); }
 
 
 		/** @copydoc Camera::worldToScreenPoint */
 		/** @copydoc Camera::worldToScreenPoint */
 		Vector2I worldToScreenPoint(const Vector3& worldPoint) const { updateView(); return mInternal->worldToScreenPoint(worldPoint); }
 		Vector2I worldToScreenPoint(const Vector3& worldPoint) const { updateView(); return mInternal->worldToScreenPoint(worldPoint); }

+ 35 - 66
Source/BansheeCore/Include/BsCamera.h

@@ -13,7 +13,7 @@
 #include "BsRay.h"
 #include "BsRay.h"
 #include "BsCoreObject.h"
 #include "BsCoreObject.h"
 #include "BsConvexVolume.h"
 #include "BsConvexVolume.h"
-#include "BsPostProcessSettings.h"
+#include "BsRenderSettings.h"
 
 
 namespace bs 
 namespace bs 
 {
 {
@@ -26,36 +26,9 @@ namespace bs
 	{
 	{
 		Transform = 1<<0,
 		Transform = 1<<0,
 		Everything = 1<<1,
 		Everything = 1<<1,
-		PostProcess = 1<<2
+		RenderSettings = 1<<2
 	};
 	};
 
 
-	/**	Flags that describe a camera. */
-	enum class CameraFlag
-	{
-		/** 
-		 * This flag is a signal to the renderer that his camera will only render overlays and doesn't require depth   
-		 * buffer or multi-sampled render targets. Such cameras will not render any scene objects. This can improve
-		 * performance and memory usage. 
-		 */
-		Overlay = 1 << 0,
-		/** 
-		 * High dynamic range allows light intensity to be more correctly recorded when rendering by allowing for a larger
-		 * range of values. The stored light is then converted into visible color range using exposure and a tone mapping 
-		 * operator.
-		 */
-		HDR = 1 << 1,
-		/** 
-		 * Specify that no lighting should be applied to scene objects and everything should be rendered using their
-		 * albedo texture.
-		 */
-		NoLighting = 1 << 2,
-		/** Specify that no shadows should be applied to scene objects. Only relevant if lighting is turned on. */
-		NoShadows = 1 << 3
-	};
-
-	typedef Flags<CameraFlag> CameraFlags;
-	BS_FLAGS_OPERATORS(CameraFlag);
-
 	/** @} */
 	/** @} */
 	/** @addtogroup Implementation
 	/** @addtogroup Implementation
 	 *  @{
 	 *  @{
@@ -68,48 +41,48 @@ namespace bs
 	 * This class contains funcionality common to both core and non-core versions of the camera.
 	 * This class contains funcionality common to both core and non-core versions of the camera.
 	 */
 	 */
 	class BS_CORE_EXPORT CameraBase
 	class BS_CORE_EXPORT CameraBase
-    {
-    public:
+	{
+	public:
 		virtual ~CameraBase() { }
 		virtual ~CameraBase() { }
 
 
 		/**
 		/**
 		 * Sets the camera horizontal field of view. This determines how wide the camera viewing angle is along the
 		 * Sets the camera horizontal field of view. This determines how wide the camera viewing angle is along the
 		 * horizontal axis. Vertical FOV is calculated from the horizontal FOV and the aspect ratio.
 		 * horizontal axis. Vertical FOV is calculated from the horizontal FOV and the aspect ratio.
 		 */
 		 */
-        virtual void setHorzFOV(const Radian& fovy);
+		virtual void setHorzFOV(const Radian& fovy);
 
 
 		/**	Retrieves the camera horizontal field of view. */
 		/**	Retrieves the camera horizontal field of view. */
-        virtual const Radian& getHorzFOV() const;
+		virtual const Radian& getHorzFOV() const;
 
 
 		/**
 		/**
 		 * Sets the distance from the frustum to the near clipping plane. Anything closer than the near clipping plane will
 		 * Sets the distance from the frustum to the near clipping plane. Anything closer than the near clipping plane will
 		 * not be rendered. Decreasing this value decreases depth buffer precision.
 		 * not be rendered. Decreasing this value decreases depth buffer precision.
 		 */
 		 */
-        virtual void setNearClipDistance(float nearDist);
+		virtual void setNearClipDistance(float nearDist);
 
 
 		/**
 		/**
 		 * Retrieves the distance from the frustum to the near clipping plane. Anything closer than the near clipping plane
 		 * Retrieves the distance from the frustum to the near clipping plane. Anything closer than the near clipping plane
 		 * will not be rendered. Decreasing this value decreases depth buffer precision.
 		 * will not be rendered. Decreasing this value decreases depth buffer precision.
 		 */
 		 */
-        virtual float getNearClipDistance() const;
+		virtual float getNearClipDistance() const;
 
 
 		/**
 		/**
 		 * Sets the distance from the frustum to the far clipping plane. Anything farther than the far clipping plane will
 		 * Sets the distance from the frustum to the far clipping plane. Anything farther than the far clipping plane will
 		 * not be rendered. Increasing this value decreases depth buffer precision.
 		 * not be rendered. Increasing this value decreases depth buffer precision.
 		 */
 		 */
-        virtual void setFarClipDistance(float farDist);
+		virtual void setFarClipDistance(float farDist);
 
 
 		/**
 		/**
 		 * Retrieves the distance from the frustum to the far clipping plane. Anything farther than the far clipping plane
 		 * Retrieves the distance from the frustum to the far clipping plane. Anything farther than the far clipping plane
 		 * will not be rendered. Increasing this value decreases depth buffer precision.
 		 * will not be rendered. Increasing this value decreases depth buffer precision.
 		 */
 		 */
-        virtual float getFarClipDistance() const;
+		virtual float getFarClipDistance() const;
 
 
 		/**	Sets the current viewport aspect ratio (width / height). */
 		/**	Sets the current viewport aspect ratio (width / height). */
-        virtual void setAspectRatio(float ratio);
+		virtual void setAspectRatio(float ratio);
 
 
 		/**	Returns current viewport aspect ratio (width / height). */
 		/**	Returns current viewport aspect ratio (width / height). */
-        virtual float getAspectRatio() const;
+		virtual float getAspectRatio() const;
 
 
 		/**	Sets camera world space position. */
 		/**	Sets camera world space position. */
 		virtual void setPosition(const Vector3& position);
 		virtual void setPosition(const Vector3& position);
@@ -164,14 +137,14 @@ namespace bs
 		 * You should use this matrix when sending the matrix to the render system to make sure everything works 
 		 * You should use this matrix when sending the matrix to the render system to make sure everything works 
 		 * consistently when other render systems are used.
 		 * consistently when other render systems are used.
 		 */
 		 */
-        virtual const Matrix4& getProjectionMatrixRS() const;
+		virtual const Matrix4& getProjectionMatrixRS() const;
 
 
 		/** 
 		/** 
 		 * Returns the inverse of the render-system specific projection matrix.
 		 * Returns the inverse of the render-system specific projection matrix.
 		 *
 		 *
 		 * @see		getProjectionMatrixRS
 		 * @see		getProjectionMatrixRS
 		 */
 		 */
-        virtual const Matrix4& getProjectionMatrixRSInv() const;
+		virtual const Matrix4& getProjectionMatrixRSInv() const;
 
 
 		/** 
 		/** 
 		 * Returns the standard projection matrix that determines how are 3D points projected to two dimensions. Returned
 		 * Returns the standard projection matrix that determines how are 3D points projected to two dimensions. Returned
@@ -180,18 +153,18 @@ namespace bs
 		 * @note	
 		 * @note	
 		 * Different render systems will expect different projection matrix layouts, in which case use 
 		 * Different render systems will expect different projection matrix layouts, in which case use 
 		 * getProjectionMatrixRS().
 		 * getProjectionMatrixRS().
-         */
-        virtual const Matrix4& getProjectionMatrix() const;
+		 */
+		virtual const Matrix4& getProjectionMatrix() const;
 
 
 		/** 
 		/** 
 		 * Returns the inverse of the projection matrix.
 		 * Returns the inverse of the projection matrix.
 		 *
 		 *
 		 * @see		getProjectionMatrix
 		 * @see		getProjectionMatrix
 		 */
 		 */
-        virtual const Matrix4& getProjectionMatrixInv() const;
+		virtual const Matrix4& getProjectionMatrixInv() const;
 
 
 		/** Gets the camera view matrix. Used for positioning/orienting the camera. */
 		/** Gets the camera view matrix. Used for positioning/orienting the camera. */
-        virtual const Matrix4& getViewMatrix() const;
+		virtual const Matrix4& getViewMatrix() const;
 
 
 		/** 
 		/** 
 		 * Returns the inverse of the view matrix.
 		 * Returns the inverse of the view matrix.
@@ -203,7 +176,7 @@ namespace bs
 		/** 
 		/** 
 		 * Sets whether the camera should use the custom view matrix. When this is enabled camera will no longer calculate
 		 * Sets whether the camera should use the custom view matrix. When this is enabled camera will no longer calculate
 		 * its view matrix based on position/orientation and caller will be resonsible to keep the view matrix up to date.
 		 * its view matrix based on position/orientation and caller will be resonsible to keep the view matrix up to date.
-         */
+		 */
 		virtual void setCustomViewMatrix(bool enable, const Matrix4& viewMatrix = Matrix4::IDENTITY);
 		virtual void setCustomViewMatrix(bool enable, const Matrix4& viewMatrix = Matrix4::IDENTITY);
 
 
 		/** Returns true if a custom view matrix is used. */
 		/** Returns true if a custom view matrix is used. */
@@ -213,32 +186,32 @@ namespace bs
 		 * Sets whether the camera should use the custom projection matrix. When this is enabled camera will no longer
 		 * Sets whether the camera should use the custom projection matrix. When this is enabled camera will no longer
 		 * calculate its projection matrix based on field of view, aspect and other parameters and caller will be resonsible
 		 * calculate its projection matrix based on field of view, aspect and other parameters and caller will be resonsible
 		 * to keep the projection matrix up to date.
 		 * to keep the projection matrix up to date.
-         */
+		 */
 		virtual void setCustomProjectionMatrix(bool enable, const Matrix4& projectionMatrix = Matrix4::IDENTITY);
 		virtual void setCustomProjectionMatrix(bool enable, const Matrix4& projectionMatrix = Matrix4::IDENTITY);
 
 
 		/** Returns true if a custom projection matrix is used. */
 		/** Returns true if a custom projection matrix is used. */
 		virtual bool isCustomProjectionMatrixEnabled() const { return mCustomProjMatrix; }
 		virtual bool isCustomProjectionMatrixEnabled() const { return mCustomProjMatrix; }
 
 
 		/** Returns a convex volume representing the visible area of the camera, in local space. */
 		/** Returns a convex volume representing the visible area of the camera, in local space. */
-        virtual const ConvexVolume& getFrustum() const;
+		virtual const ConvexVolume& getFrustum() const;
 
 
 		/** Returns a convex volume representing the visible area of the camera, in world space. */
 		/** Returns a convex volume representing the visible area of the camera, in world space. */
-        virtual ConvexVolume getWorldFrustum() const;
+		virtual ConvexVolume getWorldFrustum() const;
 
 
 		/**	Returns the bounding of the frustum. */
 		/**	Returns the bounding of the frustum. */
-        const AABox& getBoundingBox() const;
+		const AABox& getBoundingBox() const;
 
 
 		/**
 		/**
 		 * Sets the type of projection used by the camera. Projection type controls how is 3D geometry projected onto a 
 		 * Sets the type of projection used by the camera. Projection type controls how is 3D geometry projected onto a 
 		 * 2D plane.
 		 * 2D plane.
 		 */
 		 */
-        virtual void setProjectionType(ProjectionType pt);
+		virtual void setProjectionType(ProjectionType pt);
 
 
 		/**
 		/**
 		 * Returns the type of projection used by the camera. Projection type controls how is 3D geometry projected onto a
 		 * Returns the type of projection used by the camera. Projection type controls how is 3D geometry projected onto a
 		 * 2D plane.
 		 * 2D plane.
 		 */
 		 */
-        virtual ProjectionType getProjectionType() const;
+		virtual ProjectionType getProjectionType() const;
 
 
 		/**
 		/**
 		 * Sets the orthographic window height, for use with orthographic rendering only. 
 		 * Sets the orthographic window height, for use with orthographic rendering only. 
@@ -309,17 +282,14 @@ namespace bs
 		 */
 		 */
 		void setMSAACount(UINT32 count) { mMSAA = count; _markCoreDirty(); }
 		void setMSAACount(UINT32 count) { mMSAA = count; _markCoreDirty(); }
 
 
-		/** Returns settings that are used for controling post-process operations like tonemapping. */
-		const SPtr<PostProcessSettings>& getPostProcessSettings() const { return mPPSettings; }
-
-		/** Sets settings that are used for controling post-process operations like tonemapping. */
-		void setPostProcessSettings(const SPtr<PostProcessSettings>& settings) { mPPSettings = settings; _markCoreDirty(CameraDirtyFlag::PostProcess); }
+		/** @copydoc setRenderSettings() */
+		const SPtr<RenderSettings>& getRenderSettings() const { return mRenderSettings; }
 
 
-		/**	Retrieves flags that define the camera. */
-		CameraFlags getFlags() const { return mCameraFlags; }
-
-		/**	Enables or disables flags that define the camera's behaviour. */
-		void setFlag(const CameraFlag& flag, bool enable);
+		/** 
+		 * Settings that control rendering for this view. They determine how will the renderer process this view, which
+		 * effects will be enabled, and what properties will those effects use.
+		 */
+		void setRenderSettings(const SPtr<RenderSettings>& settings) { mRenderSettings = settings; _markCoreDirty(CameraDirtyFlag::RenderSettings); }
 
 
 		/**
 		/**
 		 * Converts a point in world space to screen coordinates (in pixels corresponding to the render target attached to
 		 * Converts a point in world space to screen coordinates (in pixels corresponding to the render target attached to
@@ -456,9 +426,8 @@ namespace bs
 		 */
 		 */
 		virtual void _markCoreDirty(CameraDirtyFlag flag = CameraDirtyFlag::Everything) { }
 		virtual void _markCoreDirty(CameraDirtyFlag flag = CameraDirtyFlag::Everything) { }
 
 
-    protected:
+	protected:
 		UINT64 mLayers; /**< Bitfield that can be used for filtering what objects the camera sees. */
 		UINT64 mLayers; /**< Bitfield that can be used for filtering what objects the camera sees. */
-		CameraFlags mCameraFlags; /**< Flags that further determine type of camera. */
 
 
 		Vector3 mPosition; /**< World space position. */
 		Vector3 mPosition; /**< World space position. */
 		Quaternion mRotation; /**< World space rotation. */
 		Quaternion mRotation; /**< World space rotation. */
@@ -476,7 +445,7 @@ namespace bs
 		bool mCustomProjMatrix; /**< Is custom projection matrix set. */
 		bool mCustomProjMatrix; /**< Is custom projection matrix set. */
 		UINT8 mMSAA; /**< Number of samples to render the scene with. */
 		UINT8 mMSAA; /**< Number of samples to render the scene with. */
 
 
-		SPtr<PostProcessSettings> mPPSettings; /**< Settings used to control post-process operations. */
+		SPtr<RenderSettings> mRenderSettings; /**< Settings used to control rendering for this camera. */
 
 
 		bool mFrustumExtentsManuallySet; /**< Are frustum extents manually set. */
 		bool mFrustumExtentsManuallySet; /**< Are frustum extents manually set. */
 
 
@@ -572,7 +541,7 @@ namespace bs
 		friend class CameraRTTI;
 		friend class CameraRTTI;
 		static RTTITypeBase* getRTTIStatic();
 		static RTTITypeBase* getRTTIStatic();
 		RTTITypeBase* getRTTI() const override;
 		RTTITypeBase* getRTTI() const override;
-     };
+	};
 
 
 	namespace ct
 	namespace ct
 	{
 	{

+ 2 - 4
Source/BansheeCore/Include/BsCameraRTTI.h

@@ -38,10 +38,10 @@ namespace bs
 			BS_RTTI_MEMBER_PLAIN(mRight, 19)
 			BS_RTTI_MEMBER_PLAIN(mRight, 19)
 			BS_RTTI_MEMBER_PLAIN(mTop, 20)
 			BS_RTTI_MEMBER_PLAIN(mTop, 20)
 			BS_RTTI_MEMBER_PLAIN(mBottom, 21)
 			BS_RTTI_MEMBER_PLAIN(mBottom, 21)
-			BS_RTTI_MEMBER_PLAIN(mCameraFlags, 22)
+			//BS_RTTI_MEMBER_PLAIN(mCameraFlags, 22)
 			BS_RTTI_MEMBER_PLAIN(mMSAA, 23)
 			BS_RTTI_MEMBER_PLAIN(mMSAA, 23)
 			/** BS_RTTI_MEMBER_PLAIN(mPPSettings, 24) */
 			/** BS_RTTI_MEMBER_PLAIN(mPPSettings, 24) */
-			BS_RTTI_MEMBER_REFLPTR(mPPSettings, 25)
+			BS_RTTI_MEMBER_REFLPTR(mRenderSettings, 25)
 			/** BS_RTTI_MEMBER_REFL(mSkyTexture, 26) */
 			/** BS_RTTI_MEMBER_REFL(mSkyTexture, 26) */
 		BS_END_RTTI_MEMBERS
 		BS_END_RTTI_MEMBERS
 			
 			
@@ -75,8 +75,6 @@ namespace bs
 		}
 		}
 	};
 	};
 
 
-	BS_ALLOW_MEMCPY_SERIALIZATION(CameraFlags);
-
 	/** @} */
 	/** @} */
 	/** @endcond */
 	/** @endcond */
 }
 }

+ 8 - 1
Source/BansheeCore/Include/BsCorePrerequisites.h

@@ -562,7 +562,7 @@ namespace bs
 		TID_ImportedAnimationEvents = 1124,
 		TID_ImportedAnimationEvents = 1124,
 		TID_CBone = 1125,
 		TID_CBone = 1125,
 		TID_MaterialParamData = 1126,
 		TID_MaterialParamData = 1126,
-		TID_PostProcessSettings = 1127,
+		TID_RenderSettings = 1127,
 		TID_MorphShape = 1128,
 		TID_MorphShape = 1128,
 		TID_MorphShapes = 1129,
 		TID_MorphShapes = 1129,
 		TID_MorphChannel = 1130,
 		TID_MorphChannel = 1130,
@@ -580,6 +580,13 @@ namespace bs
 		TID_Renderable = 30004,
 		TID_Renderable = 30004,
 		TID_Light = 30011,
 		TID_Light = 30011,
 		TID_CLight = 30012,
 		TID_CLight = 30012,
+		TID_AutoExposureSettings = 30016,
+		TID_TonemappingSettings = 30017,
+		TID_WhiteBalanceSettings = 30018,
+		TID_ColorGradingSettings = 30019,
+		TID_DepthOfFieldSettings = 30020,
+		TID_AmbientOcclusionSettings = 30021,
+		TID_ScreenSpaceReflectionsSettings = 30022
 	};
 	};
 }
 }
 
 

+ 0 - 55
Source/BansheeCore/Include/BsPostProcessSettings.h

@@ -1,55 +0,0 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsIReflectable.h"
-
-namespace bs
-{
-	/** @addtogroup Renderer
-	 *  @{
-	 */
-	
-	/** Base class whose implementations contain settings that control post-process operations during rendering. */
-	struct BS_CORE_EXPORT PostProcessSettings : public IReflectable
-	{
-		PostProcessSettings() { }
-		virtual ~PostProcessSettings() { }
-
-		/** @name Internal
-		 *  @{
-		 */
-
-		/** 
-		 * Populates the provided buffer with data that can be used for syncing between two versions of this object.
-		 * Apply the retrieved buffer via _setSyncData().
-		 *
-		 * @param[in]		buffer		Pre-allocated buffer to store the sync data in. Set to null to calculate the size
-		 *								of the required buffer.
-		 * @param[in, out]	size		Size of the provided allocated buffer. Or if the buffer is null, this parameter will
-		 *								contain the required buffer size when the method executes.
-		 */
-		virtual void _getSyncData(UINT8* buffer, UINT32& size) = 0;
-
-		/** 
-		 * Updates the stored data from the provided buffer, allowing changes to be transfered between two versions of this
-		 * object. Buffer must be retrieved from _getSyncData(). 
-		 *
-		 * @param[in]		buffer		Buffer containing the dirty data.
-		 * @param[in, out]	size		Size of the provided buffer.
-		 */
-		virtual void _setSyncData(UINT8* buffer, UINT32 size) = 0;
-
-		/** @} */
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-	public:
-		friend class PostProcessSettingsRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		RTTITypeBase* getRTTI() const override;
-	};
-
-	/** @} */
-}

+ 0 - 43
Source/BansheeCore/Include/BsPostProcessSettingsRTTI.h

@@ -1,43 +0,0 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsRTTIType.h"
-#include "BsPostProcessSettings.h"
-
-namespace bs
-{
-	/** @cond RTTI */
-	/** @addtogroup RTTI-Impl-Engine
-	 *  @{
-	 */
-
-	class BS_CORE_EXPORT PostProcessSettingsRTTI : public RTTIType<PostProcessSettings, IReflectable, PostProcessSettingsRTTI>
-	{
-	private:
-
-	public:
-		PostProcessSettingsRTTI() { }
-
-		const String& getRTTIName() override
-		{
-			static String name = "PostProcessSettings";
-			return name;
-		}
-
-		UINT32 getRTTIId() override
-		{
-			return TID_PostProcessSettings;
-		}
-
-		SPtr<IReflectable> newRTTIObject() override
-		{
-			assert(false); // Abstract class
-			return nullptr;
-		}
-	};
-
-	/** @} */
-	/** @endcond */
-}

+ 61 - 18
Source/BansheeEngine/Include/BsStandardPostProcessSettings.h → Source/BansheeCore/Include/BsRenderSettings.h

@@ -2,8 +2,8 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #pragma once
 #pragma once
 
 
-#include "BsPrerequisites.h"
-#include "BsPostProcessSettings.h"
+#include "BsCorePrerequisites.h"
+#include "BsIReflectable.h"
 #include "BsVector3.h"
 #include "BsVector3.h"
 
 
 namespace bs
 namespace bs
@@ -13,7 +13,7 @@ namespace bs
 	 */
 	 */
 
 
 	/** Settings that control automatic exposure (eye adaptation) post-process. */
 	/** Settings that control automatic exposure (eye adaptation) post-process. */
-	struct BS_EXPORT AutoExposureSettings : public IReflectable
+	struct BS_CORE_EXPORT AutoExposureSettings : public IReflectable
 	{
 	{
 		AutoExposureSettings();
 		AutoExposureSettings();
 
 
@@ -85,7 +85,7 @@ namespace bs
 	};
 	};
 
 
 	/** Settings that control tonemap post-process. */
 	/** Settings that control tonemap post-process. */
-	struct BS_EXPORT TonemappingSettings : public IReflectable
+	struct BS_CORE_EXPORT TonemappingSettings : public IReflectable
 	{
 	{
 		TonemappingSettings();
 		TonemappingSettings();
 
 
@@ -132,7 +132,7 @@ namespace bs
 	};
 	};
 
 
 	/** Settings that control white balance post-process. */
 	/** Settings that control white balance post-process. */
-	struct BS_EXPORT WhiteBalanceSettings : public IReflectable
+	struct BS_CORE_EXPORT WhiteBalanceSettings : public IReflectable
 	{
 	{
 		WhiteBalanceSettings();
 		WhiteBalanceSettings();
 
 
@@ -162,7 +162,7 @@ namespace bs
 	};
 	};
 
 
 	/** Settings that control color grading post-process. */
 	/** Settings that control color grading post-process. */
-	struct BS_EXPORT ColorGradingSettings : public IReflectable
+	struct BS_CORE_EXPORT ColorGradingSettings : public IReflectable
 	{
 	{
 		ColorGradingSettings();
 		ColorGradingSettings();
 
 
@@ -200,7 +200,7 @@ namespace bs
 	};
 	};
 
 
 	/** Settings that control screen space ambient occlusion. */
 	/** Settings that control screen space ambient occlusion. */
-	struct BS_EXPORT AmbientOcclusionSettings : public IReflectable
+	struct BS_CORE_EXPORT AmbientOcclusionSettings : public IReflectable
 	{
 	{
 		AmbientOcclusionSettings();
 		AmbientOcclusionSettings();
 
 
@@ -263,7 +263,7 @@ namespace bs
 	};
 	};
 
 
 	/** Settings that control the depth-of-field effect. */
 	/** Settings that control the depth-of-field effect. */
-	struct BS_EXPORT DepthOfFieldSettings : public IReflectable
+	struct BS_CORE_EXPORT DepthOfFieldSettings : public IReflectable
 	{
 	{
 		DepthOfFieldSettings();
 		DepthOfFieldSettings();
 
 
@@ -322,7 +322,7 @@ namespace bs
 	 * for rougher (more glossy rather than mirror-like) surfaces. Those surfaces require a higher number of samples to
 	 * for rougher (more glossy rather than mirror-like) surfaces. Those surfaces require a higher number of samples to
 	 * achieve the glossy look, so we instead fall back to refl. probes which are pre-filtered and can be quickly sampled.
 	 * achieve the glossy look, so we instead fall back to refl. probes which are pre-filtered and can be quickly sampled.
 	 */
 	 */
-	struct BS_EXPORT ScreenSpaceReflectionsSettings : public IReflectable
+	struct BS_CORE_EXPORT ScreenSpaceReflectionsSettings : public IReflectable
 	{
 	{
 		ScreenSpaceReflectionsSettings();
 		ScreenSpaceReflectionsSettings();
 
 
@@ -353,11 +353,12 @@ namespace bs
 		static RTTITypeBase* getRTTIStatic();
 		static RTTITypeBase* getRTTIStatic();
 		RTTITypeBase* getRTTI() const override;
 		RTTITypeBase* getRTTI() const override;
 	};
 	};
-
-	/** Settings that control the post-process operations. */
-	struct BS_EXPORT StandardPostProcessSettings : public PostProcessSettings
+	
+	/** Settings that control rendering for a specific camera (view). */
+	struct BS_CORE_EXPORT RenderSettings : public IReflectable
 	{
 	{
-		StandardPostProcessSettings();
+		RenderSettings();
+		virtual ~RenderSettings() { }
 
 
 		/**
 		/**
 		 * Determines should automatic exposure be applied to the HDR image. When turned on the average scene brightness
 		 * Determines should automatic exposure be applied to the HDR image. When turned on the average scene brightness
@@ -430,17 +431,59 @@ namespace bs
 		 */
 		 */
 		float gamma;
 		float gamma;
 
 
-		/** @copydoc PostProcessSettings::_getSyncData */
-		void _getSyncData(UINT8* buffer, UINT32& size) override;
+		/** 
+		 * High dynamic range allows light intensity to be more correctly recorded when rendering by allowing for a larger
+		 * range of values. The stored light is then converted into visible color range using exposure and a tone mapping 
+		 * operator.
+		 */
+		bool enableHDR;
+
+		/** 
+		 * Determines if scene objects will be lit by lights. If disabled everything will be rendered using their albedo
+		 * texture with no lighting applied.
+		 */
+		bool enableLighting;
+
+		/** Determines if shadows cast by lights should be rendered. Only relevant if lighting is turned on. */
+		bool enableShadows;
+
+		/** 
+		 * Signals the renderer to only render overlays (like GUI), and not scene objects. Such rendering doesn't require
+		 * depth buffer or multi-sampled render targets and will not render any scene objects. This can improve performance
+		 * and memory usage for overlay-only views. 
+		 */
+		bool overlayOnly;
 
 
-		/** @copydoc PostProcessSettings::_setSyncData */
-		void _setSyncData(UINT8* buffer, UINT32 size) override;
+		/** @name Internal
+		 *  @{
+		 */
+
+		/** 
+		 * Populates the provided buffer with data that can be used for syncing between two versions of this object.
+		 * Apply the retrieved buffer via _setSyncData().
+		 *
+		 * @param[in]		buffer		Pre-allocated buffer to store the sync data in. Set to null to calculate the size
+		 *								of the required buffer.
+		 * @param[in, out]	size		Size of the provided allocated buffer. Or if the buffer is null, this parameter will
+		 *								contain the required buffer size when the method executes.
+		 */
+		void _getSyncData(UINT8* buffer, UINT32& size);
+
+		/** 
+		 * Updates the stored data from the provided buffer, allowing changes to be transfered between two versions of this
+		 * object. Buffer must be retrieved from _getSyncData(). 
+		 *
+		 * @param[in]		buffer		Buffer containing the dirty data.
+		 * @param[in, out]	size		Size of the provided buffer.
+		 */
+		void _setSyncData(UINT8* buffer, UINT32 size);
 
 
+		/** @} */
 		/************************************************************************/
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/* 								RTTI		                     		*/
 		/************************************************************************/
 		/************************************************************************/
 	public:
 	public:
-		friend class StandardPostProcessSettingsRTTI;
+		friend class RenderSettingsRTTI;
 		static RTTITypeBase* getRTTIStatic();
 		static RTTITypeBase* getRTTIStatic();
 		RTTITypeBase* getRTTI() const override;
 		RTTITypeBase* getRTTI() const override;
 	};
 	};

+ 18 - 14
Source/BansheeEngine/Include/BsStandardPostProcessSettingsRTTI.h → Source/BansheeCore/Include/BsRenderSettingsRTTI.h

@@ -2,9 +2,9 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #pragma once
 #pragma once
 
 
-#include "BsPrerequisites.h"
+#include "BsCorePrerequisites.h"
 #include "BsRTTIType.h"
 #include "BsRTTIType.h"
-#include "BsStandardPostProcessSettings.h"
+#include "BsRenderSettings.h"
 
 
 namespace bs
 namespace bs
 {
 {
@@ -13,7 +13,7 @@ namespace bs
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
-	class BS_EXPORT AutoExposureSettingsRTTI : public RTTIType <AutoExposureSettings, IReflectable, AutoExposureSettingsRTTI>
+	class BS_CORE_EXPORT AutoExposureSettingsRTTI : public RTTIType <AutoExposureSettings, IReflectable, AutoExposureSettingsRTTI>
 	{
 	{
 	private:
 	private:
 		BS_BEGIN_RTTI_MEMBERS
 		BS_BEGIN_RTTI_MEMBERS
@@ -49,7 +49,7 @@ namespace bs
 		}
 		}
 	};
 	};
 
 
-	class BS_EXPORT TonemappingSettingsRTTI : public RTTIType <TonemappingSettings, IReflectable, TonemappingSettingsRTTI>
+	class BS_CORE_EXPORT TonemappingSettingsRTTI : public RTTIType <TonemappingSettings, IReflectable, TonemappingSettingsRTTI>
 	{
 	{
 	private:
 	private:
 		BS_BEGIN_RTTI_MEMBERS
 		BS_BEGIN_RTTI_MEMBERS
@@ -84,7 +84,7 @@ namespace bs
 		}
 		}
 	};
 	};
 
 
-	class BS_EXPORT WhiteBalanceSettingsRTTI : public RTTIType <WhiteBalanceSettings, IReflectable, WhiteBalanceSettingsRTTI>
+	class BS_CORE_EXPORT WhiteBalanceSettingsRTTI : public RTTIType <WhiteBalanceSettings, IReflectable, WhiteBalanceSettingsRTTI>
 	{
 	{
 	private:
 	private:
 		BS_BEGIN_RTTI_MEMBERS
 		BS_BEGIN_RTTI_MEMBERS
@@ -114,7 +114,7 @@ namespace bs
 		}
 		}
 	};
 	};
 
 
-	class BS_EXPORT ColorGradingSettingsRTTI : public RTTIType <ColorGradingSettings, IReflectable, ColorGradingSettingsRTTI>
+	class BS_CORE_EXPORT ColorGradingSettingsRTTI : public RTTIType <ColorGradingSettings, IReflectable, ColorGradingSettingsRTTI>
 	{
 	{
 	private:
 	private:
 		BS_BEGIN_RTTI_MEMBERS
 		BS_BEGIN_RTTI_MEMBERS
@@ -146,7 +146,7 @@ namespace bs
 		}
 		}
 	};
 	};
 
 
-	class BS_EXPORT DepthOfFieldSettingsRTTI : public RTTIType <DepthOfFieldSettings, IReflectable, DepthOfFieldSettingsRTTI>
+	class BS_CORE_EXPORT DepthOfFieldSettingsRTTI : public RTTIType <DepthOfFieldSettings, IReflectable, DepthOfFieldSettingsRTTI>
 	{
 	{
 	private:
 	private:
 		BS_BEGIN_RTTI_MEMBERS
 		BS_BEGIN_RTTI_MEMBERS
@@ -181,7 +181,7 @@ namespace bs
 		}
 		}
 	};
 	};
 
 
-	class BS_EXPORT AmbientOcclusionSettingsRTTI : public RTTIType <AmbientOcclusionSettings, IReflectable, AmbientOcclusionSettingsRTTI>
+	class BS_CORE_EXPORT AmbientOcclusionSettingsRTTI : public RTTIType <AmbientOcclusionSettings, IReflectable, AmbientOcclusionSettingsRTTI>
 	{
 	{
 	private:
 	private:
 		BS_BEGIN_RTTI_MEMBERS
 		BS_BEGIN_RTTI_MEMBERS
@@ -217,7 +217,7 @@ namespace bs
 		}
 		}
 	};
 	};
 
 
-	class BS_EXPORT ScreenSpaceReflectionsSettingsRTTI : public RTTIType <ScreenSpaceReflectionsSettings, IReflectable, ScreenSpaceReflectionsSettingsRTTI>
+	class BS_CORE_EXPORT ScreenSpaceReflectionsSettingsRTTI : public RTTIType <ScreenSpaceReflectionsSettings, IReflectable, ScreenSpaceReflectionsSettingsRTTI>
 	{
 	{
 	private:
 	private:
 		BS_BEGIN_RTTI_MEMBERS
 		BS_BEGIN_RTTI_MEMBERS
@@ -249,7 +249,7 @@ namespace bs
 		}
 		}
 	};
 	};
 
 
-	class BS_EXPORT StandardPostProcessSettingsRTTI : public RTTIType <StandardPostProcessSettings, PostProcessSettings, StandardPostProcessSettingsRTTI>
+	class BS_CORE_EXPORT RenderSettingsRTTI : public RTTIType <RenderSettings, IReflectable, RenderSettingsRTTI>
 	{
 	{
 	private:
 	private:
 		BS_BEGIN_RTTI_MEMBERS
 		BS_BEGIN_RTTI_MEMBERS
@@ -265,27 +265,31 @@ namespace bs
 			BS_RTTI_MEMBER_PLAIN(enableFXAA, 9)
 			BS_RTTI_MEMBER_PLAIN(enableFXAA, 9)
 			BS_RTTI_MEMBER_REFL(ambientOcclusion, 10)
 			BS_RTTI_MEMBER_REFL(ambientOcclusion, 10)
 			BS_RTTI_MEMBER_REFL(screenSpaceReflections, 11)
 			BS_RTTI_MEMBER_REFL(screenSpaceReflections, 11)
+			BS_RTTI_MEMBER_PLAIN(enableHDR, 12)
+			BS_RTTI_MEMBER_PLAIN(enableLighting, 13)
+			BS_RTTI_MEMBER_PLAIN(enableShadows, 14)
+			BS_RTTI_MEMBER_PLAIN(overlayOnly, 15)
 		BS_END_RTTI_MEMBERS
 		BS_END_RTTI_MEMBERS
 			
 			
 	public:
 	public:
-		StandardPostProcessSettingsRTTI()
+		RenderSettingsRTTI()
 			:mInitMembers(this)
 			:mInitMembers(this)
 		{ }
 		{ }
 
 
 		const String& getRTTIName() override
 		const String& getRTTIName() override
 		{
 		{
-			static String name = "StandardPostProcessSettings";
+			static String name = "RenderSettings";
 			return name;
 			return name;
 		}
 		}
 
 
 		UINT32 getRTTIId() override
 		UINT32 getRTTIId() override
 		{
 		{
-			return TID_StandardPostProcessSettings;
+			return TID_RenderSettings;
 		}
 		}
 
 
 		SPtr<IReflectable> newRTTIObject() override
 		SPtr<IReflectable> newRTTIObject() override
 		{
 		{
-			return bs_shared_ptr_new<StandardPostProcessSettings>();
+			return bs_shared_ptr_new<RenderSettings>();
 		}
 		}
 	};
 	};
 
 

+ 1 - 4
Source/BansheeCore/Include/BsRenderer.h

@@ -10,7 +10,7 @@ namespace bs
 { 
 { 
 	class RendererExtension;
 	class RendererExtension;
 	class LightProbeVolume;
 	class LightProbeVolume;
-	struct PostProcessSettings;
+	struct RenderSettings;
 
 
 	namespace ct
 	namespace ct
 	{
 	{
@@ -224,9 +224,6 @@ namespace bs
 		/**	Returns current set of options used for controlling the rendering. */
 		/**	Returns current set of options used for controlling the rendering. */
 		virtual SPtr<RendererOptions> getOptions() const { return SPtr<RendererOptions>(); }
 		virtual SPtr<RendererOptions> getOptions() const { return SPtr<RendererOptions>(); }
 
 
-		/** Creates post process settings that can be attached to a camera and processed by the active renderer. */
-		virtual SPtr<PostProcessSettings> createPostProcessSettings() const = 0;
-
 	protected:
 	protected:
 		/**	Contains information about a render callback. */
 		/**	Contains information about a render callback. */
 		struct RenderCallbackData
 		struct RenderCallbackData

+ 1 - 1
Source/BansheeCore/Source/BsAnimationManager.cpp

@@ -88,7 +88,7 @@ namespace bs
 		auto& allCameras = gSceneManager().getAllCameras();
 		auto& allCameras = gSceneManager().getAllCameras();
 		for(auto& entry : allCameras)
 		for(auto& entry : allCameras)
 		{
 		{
-			bool isOverlayCamera = entry.second.camera->getFlags().isSet(CameraFlag::Overlay);
+			bool isOverlayCamera = entry.second.camera->getRenderSettings()->overlayOnly;
 			if (isOverlayCamera)
 			if (isOverlayCamera)
 				continue;
 				continue;
 
 

+ 9 - 22
Source/BansheeCore/Source/BsCamera.cpp

@@ -19,14 +19,14 @@ namespace bs
 	const float CameraBase::INFINITE_FAR_PLANE_ADJUST = 0.00001f;
 	const float CameraBase::INFINITE_FAR_PLANE_ADJUST = 0.00001f;
 
 
 	CameraBase::CameraBase()
 	CameraBase::CameraBase()
-		: mLayers(0xFFFFFFFFFFFFFFFF), mCameraFlags(CameraFlag::HDR), mPosition(BsZero), mRotation(BsIdentity)
+		: mLayers(0xFFFFFFFFFFFFFFFF), mPosition(BsZero), mRotation(BsIdentity)
 		, mIsActive(true), mProjType(PT_PERSPECTIVE), mHorzFOV(Degree(90.0f)), mFarDist(1000.0f), mNearDist(0.05f)
 		, mIsActive(true), mProjType(PT_PERSPECTIVE), mHorzFOV(Degree(90.0f)), mFarDist(1000.0f), mNearDist(0.05f)
 		, mAspect(1.33333333333333f), mOrthoHeight(5), mPriority(0), mCustomViewMatrix(false), mCustomProjMatrix(false)
 		, mAspect(1.33333333333333f), mOrthoHeight(5), mPriority(0), mCustomViewMatrix(false), mCustomProjMatrix(false)
 		, mMSAA(1), mFrustumExtentsManuallySet(false), mProjMatrixRS(BsZero), mProjMatrix(BsZero), mViewMatrix(BsZero)
 		, mMSAA(1), mFrustumExtentsManuallySet(false), mProjMatrixRS(BsZero), mProjMatrix(BsZero), mViewMatrix(BsZero)
 		, mProjMatrixRSInv(BsZero), mProjMatrixInv(BsZero), mViewMatrixInv(BsZero), mRecalcFrustum(true)
 		, mProjMatrixRSInv(BsZero), mProjMatrixInv(BsZero), mViewMatrixInv(BsZero), mRecalcFrustum(true)
 		, mRecalcFrustumPlanes(true), mRecalcView(true)
 		, mRecalcFrustumPlanes(true), mRecalcView(true)
 	{
 	{
-		mPPSettings = RendererManager::instance().getActive()->createPostProcessSettings();
+		mRenderSettings = bs_shared_ptr_new<RenderSettings>();
 
 
 		invalidateFrustum();
 		invalidateFrustum();
 	}
 	}
@@ -461,16 +461,6 @@ namespace bs
 		outbottom = mBottom;
 		outbottom = mBottom;
 	}
 	}
 
 
-	void CameraBase::setFlag(const CameraFlag& flag, bool enable)
-	{
-		if (enable)
-			mCameraFlags.set(flag);
-		else
-			mCameraFlags.unset(flag);
-			
-		_markCoreDirty();
-	}
-
 	void CameraBase::setPosition(const Vector3& position)
 	void CameraBase::setPosition(const Vector3& position)
 	{
 	{
 		mPosition = position;
 		mPosition = position;
@@ -758,14 +748,13 @@ namespace bs
 			size += rttiGetElemSize(mCustomViewMatrix);
 			size += rttiGetElemSize(mCustomViewMatrix);
 			size += rttiGetElemSize(mCustomProjMatrix);
 			size += rttiGetElemSize(mCustomProjMatrix);
 			size += rttiGetElemSize(mFrustumExtentsManuallySet);
 			size += rttiGetElemSize(mFrustumExtentsManuallySet);
-			size += rttiGetElemSize(mCameraFlags);
 			size += rttiGetElemSize(mIsActive);
 			size += rttiGetElemSize(mIsActive);
 			size += rttiGetElemSize(mMSAA);
 			size += rttiGetElemSize(mMSAA);
 			size += sizeof(UINT32);
 			size += sizeof(UINT32);
 
 
-			if(mPPSettings != nullptr)
+			if(mRenderSettings != nullptr)
 			{
 			{
-				mPPSettings->_getSyncData(nullptr, ppSize);
+				mRenderSettings->_getSyncData(nullptr, ppSize);
 				size += ppSize;
 				size += ppSize;
 			}
 			}
 		}
 		}
@@ -790,14 +779,13 @@ namespace bs
 			dataPtr = rttiWriteElem(mCustomViewMatrix, dataPtr);
 			dataPtr = rttiWriteElem(mCustomViewMatrix, dataPtr);
 			dataPtr = rttiWriteElem(mCustomProjMatrix, dataPtr);
 			dataPtr = rttiWriteElem(mCustomProjMatrix, dataPtr);
 			dataPtr = rttiWriteElem(mFrustumExtentsManuallySet, dataPtr);
 			dataPtr = rttiWriteElem(mFrustumExtentsManuallySet, dataPtr);
-			dataPtr = rttiWriteElem(mCameraFlags, dataPtr);
 			dataPtr = rttiWriteElem(mIsActive, dataPtr);
 			dataPtr = rttiWriteElem(mIsActive, dataPtr);
 			dataPtr = rttiWriteElem(mMSAA, dataPtr);
 			dataPtr = rttiWriteElem(mMSAA, dataPtr);
 
 
 			dataPtr = rttiWriteElem(ppSize, dataPtr);
 			dataPtr = rttiWriteElem(ppSize, dataPtr);
 
 
-			if(mPPSettings != nullptr)
-				mPPSettings->_getSyncData((UINT8*)dataPtr, ppSize);
+			if(mRenderSettings != nullptr)
+				mRenderSettings->_getSyncData((UINT8*)dataPtr, ppSize);
 
 
 			dataPtr += ppSize;
 			dataPtr += ppSize;
 		}
 		}
@@ -882,7 +870,6 @@ namespace bs
 			dataPtr = rttiReadElem(mCustomViewMatrix, dataPtr);
 			dataPtr = rttiReadElem(mCustomViewMatrix, dataPtr);
 			dataPtr = rttiReadElem(mCustomProjMatrix, dataPtr);
 			dataPtr = rttiReadElem(mCustomProjMatrix, dataPtr);
 			dataPtr = rttiReadElem(mFrustumExtentsManuallySet, dataPtr);
 			dataPtr = rttiReadElem(mFrustumExtentsManuallySet, dataPtr);
-			dataPtr = rttiReadElem(mCameraFlags, dataPtr);
 			dataPtr = rttiReadElem(mIsActive, dataPtr);
 			dataPtr = rttiReadElem(mIsActive, dataPtr);
 			dataPtr = rttiReadElem(mMSAA, dataPtr);
 			dataPtr = rttiReadElem(mMSAA, dataPtr);
 
 
@@ -891,10 +878,10 @@ namespace bs
 
 
 			if(ppSize > 0)
 			if(ppSize > 0)
 			{
 			{
-				if (mPPSettings == nullptr)
-					mPPSettings = RendererManager::instance().getActive()->createPostProcessSettings();
+				if (mRenderSettings == nullptr)
+					mRenderSettings = bs_shared_ptr_new<RenderSettings>();
 
 
-				mPPSettings->_setSyncData((UINT8*)dataPtr, ppSize);
+				mRenderSettings->_setSyncData((UINT8*)dataPtr, ppSize);
 				dataPtr += ppSize;
 				dataPtr += ppSize;
 			}
 			}
 		}
 		}

+ 0 - 17
Source/BansheeCore/Source/BsPostProcessSettings.cpp

@@ -1,17 +0,0 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPostProcessSettings.h"
-#include "BsPostProcessSettingsRTTI.h"
-
-namespace bs
-{
-	RTTITypeBase* PostProcessSettings::getRTTIStatic()
-	{
-		return PostProcessSettingsRTTI::instance();
-	}
-
-	RTTITypeBase* PostProcessSettings::getRTTI() const
-	{
-		return PostProcessSettings::getRTTIStatic();
-	}
-}

+ 23 - 11
Source/BansheeEngine/Source/BsStandardPostProcessSettings.cpp → Source/BansheeCore/Source/BsRenderSettings.cpp

@@ -1,8 +1,7 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsStandardPostProcessSettings.h"
-#include "BsBinarySerializer.h"
-#include "BsStandardPostProcessSettingsRTTI.h"
+#include "BsRenderSettings.h"
+#include "BsRenderSettingsRTTI.h"
 
 
 namespace bs
 namespace bs
 {
 {
@@ -109,21 +108,22 @@ namespace bs
 		return ScreenSpaceReflectionsSettings::getRTTIStatic();
 		return ScreenSpaceReflectionsSettings::getRTTIStatic();
 	}
 	}
 
 
-	StandardPostProcessSettings::StandardPostProcessSettings()
+	RenderSettings::RenderSettings()
 		: enableAutoExposure(true), enableTonemapping(true), enableFXAA(false), exposureScale(0.0f), gamma(2.2f)
 		: enableAutoExposure(true), enableTonemapping(true), enableFXAA(false), exposureScale(0.0f), gamma(2.2f)
+		, enableHDR(true), enableLighting(true), enableShadows(true), overlayOnly(false)
 	{ }
 	{ }
 
 
-	RTTITypeBase* StandardPostProcessSettings::getRTTIStatic()
+	RTTITypeBase* RenderSettings::getRTTIStatic()
 	{
 	{
-		return StandardPostProcessSettingsRTTI::instance();
+		return RenderSettingsRTTI::instance();
 	}
 	}
 
 
-	RTTITypeBase* StandardPostProcessSettings::getRTTI() const
+	RTTITypeBase* RenderSettings::getRTTI() const
 	{
 	{
-		return StandardPostProcessSettings::getRTTIStatic();
+		return RenderSettings::getRTTIStatic();
 	}
 	}
 
 
-	void StandardPostProcessSettings::_getSyncData(UINT8* buffer, UINT32& size)
+	void RenderSettings::_getSyncData(UINT8* buffer, UINT32& size)
 	{
 	{
 		UINT32 bufferSize = 0;
 		UINT32 bufferSize = 0;
 		bufferSize += rttiGetElemSize(enableAutoExposure);
 		bufferSize += rttiGetElemSize(enableAutoExposure);
@@ -131,6 +131,10 @@ namespace bs
 		bufferSize += rttiGetElemSize(exposureScale);
 		bufferSize += rttiGetElemSize(exposureScale);
 		bufferSize += rttiGetElemSize(gamma);
 		bufferSize += rttiGetElemSize(gamma);
 		bufferSize += rttiGetElemSize(enableFXAA);
 		bufferSize += rttiGetElemSize(enableFXAA);
+		bufferSize += rttiGetElemSize(enableHDR);
+		bufferSize += rttiGetElemSize(enableLighting);
+		bufferSize += rttiGetElemSize(enableShadows);
+		bufferSize += rttiGetElemSize(overlayOnly);
 
 
 		bufferSize += rttiGetElemSize(autoExposure.histogramLog2Min);
 		bufferSize += rttiGetElemSize(autoExposure.histogramLog2Min);
 		bufferSize += rttiGetElemSize(autoExposure.histogramLog2Max);
 		bufferSize += rttiGetElemSize(autoExposure.histogramLog2Max);
@@ -197,6 +201,10 @@ namespace bs
 		writeDst = rttiWriteElem(exposureScale, writeDst);
 		writeDst = rttiWriteElem(exposureScale, writeDst);
 		writeDst = rttiWriteElem(gamma, writeDst);
 		writeDst = rttiWriteElem(gamma, writeDst);
 		writeDst = rttiWriteElem(enableFXAA, writeDst);
 		writeDst = rttiWriteElem(enableFXAA, writeDst);
+		writeDst = rttiWriteElem(enableHDR, writeDst);
+		writeDst = rttiWriteElem(enableLighting, writeDst);
+		writeDst = rttiWriteElem(enableShadows, writeDst);
+		writeDst = rttiWriteElem(overlayOnly, writeDst);
 
 
 		writeDst = rttiWriteElem(autoExposure.histogramLog2Min, writeDst);
 		writeDst = rttiWriteElem(autoExposure.histogramLog2Min, writeDst);
 		writeDst = rttiWriteElem(autoExposure.histogramLog2Max, writeDst);
 		writeDst = rttiWriteElem(autoExposure.histogramLog2Max, writeDst);
@@ -246,7 +254,7 @@ namespace bs
 		writeDst = rttiWriteElem(screenSpaceReflections.quality, writeDst);
 		writeDst = rttiWriteElem(screenSpaceReflections.quality, writeDst);
 	}
 	}
 
 
-	void StandardPostProcessSettings::_setSyncData(UINT8* buffer, UINT32 size)
+	void RenderSettings::_setSyncData(UINT8* buffer, UINT32 size)
 	{
 	{
 		char* readSource = (char*)buffer;
 		char* readSource = (char*)buffer;
 
 
@@ -255,6 +263,10 @@ namespace bs
 		readSource = rttiReadElem(exposureScale, readSource);
 		readSource = rttiReadElem(exposureScale, readSource);
 		readSource = rttiReadElem(gamma, readSource);
 		readSource = rttiReadElem(gamma, readSource);
 		readSource = rttiReadElem(enableFXAA, readSource);
 		readSource = rttiReadElem(enableFXAA, readSource);
+		readSource = rttiReadElem(enableHDR, readSource);
+		readSource = rttiReadElem(enableLighting, readSource);
+		readSource = rttiReadElem(enableShadows, readSource);
+		readSource = rttiReadElem(overlayOnly, readSource);
 
 
 		readSource = rttiReadElem(autoExposure.histogramLog2Min, readSource);
 		readSource = rttiReadElem(autoExposure.histogramLog2Min, readSource);
 		readSource = rttiReadElem(autoExposure.histogramLog2Max, readSource);
 		readSource = rttiReadElem(autoExposure.histogramLog2Max, readSource);
@@ -303,4 +315,4 @@ namespace bs
 		readSource = rttiReadElem(screenSpaceReflections.maxRoughness, readSource);
 		readSource = rttiReadElem(screenSpaceReflections.maxRoughness, readSource);
 		readSource = rttiReadElem(screenSpaceReflections.quality, readSource);
 		readSource = rttiReadElem(screenSpaceReflections.quality, readSource);
 	}
 	}
-}
+}

+ 3 - 1
Source/BansheeEditor/Source/BsEditorWindowBase.cpp

@@ -88,7 +88,9 @@ namespace bs
 		mCamera->setNearClipDistance(5);
 		mCamera->setNearClipDistance(5);
 		mCamera->setAspectRatio(1.0f);
 		mCamera->setAspectRatio(1.0f);
 		mCamera->setLayers(0);
 		mCamera->setLayers(0);
-		mCamera->setFlag(CameraFlag::Overlay, true);
+
+		SPtr<RenderSettings> settings = mCamera->getRenderSettings();
+		settings->overlayOnly = true;
 
 
 		mGUI = mSceneObject->addComponent<CGUIWidget>(mCamera);
 		mGUI = mSceneObject->addComponent<CGUIWidget>(mCamera);
 		mGUI->setDepth(128);
 		mGUI->setDepth(128);

+ 0 - 3
Source/BansheeEngine/CMakeSources.cmake

@@ -87,7 +87,6 @@ set(BS_BANSHEEENGINE_INC_RENDERER
 	"Include/BsRendererMaterialManager.h"
 	"Include/BsRendererMaterialManager.h"
 	"Include/BsRenderQueue.h"
 	"Include/BsRenderQueue.h"
 	"Include/BsRendererUtility.h"
 	"Include/BsRendererUtility.h"
-	"Include/BsStandardPostProcessSettings.h"	
 	"Include/BsLightProbeCache.h"
 	"Include/BsLightProbeCache.h"
 	"Include/BsIBLUtility.h"
 	"Include/BsIBLUtility.h"
 )
 )
@@ -136,7 +135,6 @@ set(BS_BANSHEEENGINE_INC_RTTI
 	"Include/BsCGUIWidgetRTTI.h"
 	"Include/BsCGUIWidgetRTTI.h"
 	"Include/BsGameSettingsRTTI.h"
 	"Include/BsGameSettingsRTTI.h"
 	"Include/BsResourceMappingRTTI.h"
 	"Include/BsResourceMappingRTTI.h"
-	"Include/BsStandardPostProcessSettingsRTTI.h"
 )
 )
 
 
 set(BS_BANSHEEENGINE_INC_NOFILTER
 set(BS_BANSHEEENGINE_INC_NOFILTER
@@ -176,7 +174,6 @@ set(BS_BANSHEEENGINE_SRC_RENDERER
 	"Source/BsRendererMaterialManager.cpp"
 	"Source/BsRendererMaterialManager.cpp"
 	"Source/BsRenderQueue.cpp"
 	"Source/BsRenderQueue.cpp"
 	"Source/BsRendererUtility.cpp"
 	"Source/BsRendererUtility.cpp"
-	"Source/BsStandardPostProcessSettings.cpp"
 	"Source/BsLightProbeCache.cpp"
 	"Source/BsLightProbeCache.cpp"
 	"Source/BsIBLUtility.cpp"
 	"Source/BsIBLUtility.cpp"
 )
 )

+ 27 - 24
Source/BansheeEngine/Include/BsIBLUtility.h

@@ -112,14 +112,8 @@ namespace bs { namespace ct
 
 
 	extern IrradianceComputeSHParamDef gIrradianceComputeSHParamDef;
 	extern IrradianceComputeSHParamDef gIrradianceComputeSHParamDef;
 
 
-	/** 
-	 * Computes spherical harmonic coefficients from a radiance cubemap. 
-	 * 
-	 * @tparam ORDER	SH order, which defines the number of coefficients and quality. Only values of 3 and 5 are 
-	 *					supported.
-	 */
-	template<int ORDER = 5>
-	class IrradianceComputeSHMat : public RendererMaterial<IrradianceComputeSHMat<ORDER>>
+	/** Computes spherical harmonic coefficients from a radiance cubemap. */
+	class IrradianceComputeSHMat : public RendererMaterial<IrradianceComputeSHMat>
 	{
 	{
 		RMAT_DEF("IrradianceComputeSH.bsl")
 		RMAT_DEF("IrradianceComputeSH.bsl")
 
 
@@ -134,12 +128,23 @@ namespace bs { namespace ct
 		void execute(const SPtr<Texture>& source, UINT32 face, const SPtr<GpuBuffer>& output);
 		void execute(const SPtr<Texture>& source, UINT32 face, const SPtr<GpuBuffer>& output);
 
 
 		/** Creates a buffer of adequate size to be used as output for this material. */
 		/** Creates a buffer of adequate size to be used as output for this material. */
-		static SPtr<GpuBuffer> createOutputBuffer(const SPtr<Texture>& source, UINT32& numCoeffSets);
+		SPtr<GpuBuffer> createOutputBuffer(const SPtr<Texture>& source, UINT32& numCoeffSets);
+
+		/** 
+		 * Returns the material variation matching the provided parameters.
+		 *
+		 * @param order		SH order, which defines the number of coefficients and quality. Only values of 3 and 5 are 
+		 *					supported.
+		 */
+		static IrradianceComputeSHMat* getVariation(int order = 5);
 
 
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		GpuParamTexture mInputTexture;
 		GpuParamTexture mInputTexture;
 		GpuParamBuffer mOutputBuffer;
 		GpuParamBuffer mOutputBuffer;
+
+		static ShaderVariation VAR_Order3;
+		static ShaderVariation VAR_Order5;
 	};
 	};
 
 
 	BS_PARAM_BLOCK_BEGIN(IrradianceReduceSHParamDef)
 	BS_PARAM_BLOCK_BEGIN(IrradianceReduceSHParamDef)
@@ -152,12 +157,8 @@ namespace bs { namespace ct
 	/** 
 	/** 
 	 * Sums spherical harmonic coefficients calculated by each thread group of IrradianceComputeSHMat and outputs a single
 	 * Sums spherical harmonic coefficients calculated by each thread group of IrradianceComputeSHMat and outputs a single
 	 * set of normalized coefficients. 
 	 * set of normalized coefficients. 
-	 *
-	 * @tparam ORDER	SH order, which defines the number of coefficients and quality. Only values of 3 and 5 are 
-	 *					supported.
 	 */
 	 */
-	template<int ORDER = 5>
-	class IrradianceReduceSHMat : public RendererMaterial<IrradianceReduceSHMat<ORDER>>
+	class IrradianceReduceSHMat : public RendererMaterial<IrradianceReduceSHMat>
 	{
 	{
 		RMAT_DEF("IrradianceReduceSH.bsl")
 		RMAT_DEF("IrradianceReduceSH.bsl")
 
 
@@ -172,12 +173,23 @@ namespace bs { namespace ct
 		void execute(const SPtr<GpuBuffer>& source, UINT32 numCoeffSets, const SPtr<GpuBuffer>& output, UINT32 outputIdx);
 		void execute(const SPtr<GpuBuffer>& source, UINT32 numCoeffSets, const SPtr<GpuBuffer>& output, UINT32 outputIdx);
 
 
 		/** Creates a buffer of adequate size to be used as output for this material. */
 		/** Creates a buffer of adequate size to be used as output for this material. */
-		static SPtr<GpuBuffer> createOutputBuffer(UINT32 numEntries);
+		SPtr<GpuBuffer> createOutputBuffer(UINT32 numEntries);
+
+		/** 
+		 * Returns the material variation matching the provided parameters.
+		 *
+		 * @param order		SH order, which defines the number of coefficients and quality. Only values of 3 and 5 are 
+		 *					supported.
+		 */
+		static IrradianceReduceSHMat* getVariation(int order = 5);
 
 
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		GpuParamBuffer mInputBuffer;
 		GpuParamBuffer mInputBuffer;
 		GpuParamBuffer mOutputBuffer;
 		GpuParamBuffer mOutputBuffer;
+
+		static ShaderVariation VAR_Order3;
+		static ShaderVariation VAR_Order5;
 	};
 	};
 
 
 	BS_PARAM_BLOCK_BEGIN(IrradianceProjectSHParamDef)
 	BS_PARAM_BLOCK_BEGIN(IrradianceProjectSHParamDef)
@@ -212,12 +224,6 @@ namespace bs { namespace ct
 	class BS_EXPORT IBLUtility
 	class BS_EXPORT IBLUtility
 	{
 	{
 	public:
 	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
 		 * Performs filtering on the cubemap, populating its mip-maps with filtered values that can be used for
 		 * evaluating specular reflections.
 		 * evaluating specular reflections.
@@ -275,9 +281,6 @@ namespace bs { namespace ct
 		 * @param[in]   dstMip			Determines which mip level of the destination texture to scale.
 		 * @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);
 		static void downsampleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, UINT32 dstMip);
-
-		struct Members;
-		static Members* m;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 7 - 8
Source/BansheeEngine/Include/BsPrerequisites.h

@@ -227,13 +227,12 @@ namespace bs
 		/* TID_CLight = 30012, */
 		/* TID_CLight = 30012, */
 		TID_GameSettings = 30013,
 		TID_GameSettings = 30013,
 		TID_ResourceMapping = 30014,
 		TID_ResourceMapping = 30014,
-		TID_StandardPostProcessSettings = 30015,
-		TID_AutoExposureSettings = 30016,
-		TID_TonemappingSettings = 30017,
-		TID_WhiteBalanceSettings = 30018,
-		TID_ColorGradingSettings = 30019,
-		TID_DepthOfFieldSettings = 30020,
-		TID_AmbientOcclusionSettings = 30021,
-		TID_ScreenSpaceReflectionsSettings = 30022
+		//TID_AutoExposureSettings = 30016,
+		//TID_TonemappingSettings = 30017,
+		//TID_WhiteBalanceSettings = 30018,
+		//TID_ColorGradingSettings = 30019,
+		//TID_DepthOfFieldSettings = 30020,
+		//TID_AmbientOcclusionSettings = 30021,
+		//TID_ScreenSpaceReflectionsSettings = 30022
 	};
 	};
 }
 }

+ 166 - 8
Source/BansheeEngine/Include/BsRendererMaterial.h

@@ -16,10 +16,10 @@
 	public:																	\
 	public:																	\
 	static void _initMetaData()												\
 	static void _initMetaData()												\
 	{																		\
 	{																		\
-		_initDefines(mMetaData.defines);									\
+		_initVariations(mMetaData.variations);								\
 		RendererMaterialManager::_registerMaterial(&mMetaData, path);		\
 		RendererMaterialManager::_registerMaterial(&mMetaData, path);		\
 	};																		\
 	};																		\
-	static void _initDefines(ShaderDefines& defines);
+	static void _initVariations(ShaderVariations& variations);
 
 
 /** @} */
 /** @} */
 
 
@@ -29,17 +29,131 @@ namespace bs { namespace ct
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
+	/** 
+	 * Contains information about a single variation of a RendererMaterial. Each variation can have a separate set of
+	 * \#defines that control shader compilation.
+	 */
+	class BS_EXPORT ShaderVariation
+	{
+	public:
+		/** Possible types of a variation parameter. */
+		enum ParamType
+		{
+			Int,
+			UInt,
+			Float,
+			Bool
+		};
+
+		/** Name, type and value of a variation parameter. */
+		struct Param
+		{
+			Param()
+				:i(0), type(Int)
+			{ }
+
+			Param(const String& name, INT32 val)
+				:i(val), name(name), type(Int)
+			{ }
+
+			Param(const String& name, UINT32 val)
+				:ui(val), name(name), type(Int)
+			{ }
+
+			Param(const String& name, float val)
+				:f(val), name(name), type(Float)
+			{ }
+
+			Param(const String& name, bool val)
+				:i(val ? 1 : 0), name(name), type(Bool)
+			{ }
+
+			union
+			{
+				INT32 i;
+				UINT32 ui;
+				float f;
+			};
+
+			String name;
+			ParamType type;
+		};
+
+		ShaderVariation() { }
+		
+		/** Creates a new shader variation with the specified parameters. */
+		ShaderVariation(const SmallVector<Param, 4>& params);
+
+		/** 
+		 * Returns the value of a signed integer parameter with the specified name. Returns 0 if the parameter cannot be 
+		 * found.
+		 */
+		INT32 getInt(const String& name);
+
+		/** 
+		 * Returns the value of a unsigned integer parameter with the specified name. Returns 0 if the parameter cannot be
+		 * found.
+		 */
+		UINT32 getUInt(const String& name);
+
+		/** Returns the value of a float parameter with the specified name. Returns 0 if the parameter cannot be found.  */
+		float getFloat(const String& name);
+
+		/** 
+		 * Returns the value of a boolean parameter with the specified name. Returns false if the parameter cannot be 
+		 * found.
+		 */
+		bool getBool(const String& name);
+
+		/** Converts all the variation parameters in a ShaderDefines object, that may be consumed by the shader compiler. */
+		ShaderDefines getDefines() const;
+
+		/** 
+		 * Returns a unique index of this variation, relative to all other variations registered in ShaderVariations object.
+		 */
+		UINT32 getIdx() const { return mIdx;  }
+
+		/** Returns all the variation parameters. */
+		const UnorderedMap<String, Param>& getParams() const { return mParams; }
+
+	private:
+		friend class ShaderVariations;
+
+		UnorderedMap<String, Param> mParams;
+		UINT32 mIdx = -1;
+	};
+
+	/** A container for all variations of a single RendererMaterial. */
+	class BS_EXPORT ShaderVariations
+	{
+	public:
+		/** Registers a new variation. */
+		void add(ShaderVariation& variation);
+
+		/** Returns a variation at the specified index. Variations are indexed sequentially as they are added. */
+		const ShaderVariation& get(UINT32 idx) { return mVariations[idx]; }
+
+		/** Returns a list of all variations. */
+		const SmallVector<ShaderVariation, 4>& getVariations() const { return mVariations; }
+
+	private:
+		SmallVector<ShaderVariation, 4> mVariations;
+		UINT32 mNextIdx = 0;
+	};
+
 	/**	Contains data common to all render material instances of a specific type. */
 	/**	Contains data common to all render material instances of a specific type. */
 	struct RendererMaterialMetaData
 	struct RendererMaterialMetaData
 	{
 	{
-		SPtr<Shader> shader;
-		ShaderDefines defines;
+		SmallVector<SPtr<Shader>, 4> shaders;
+		SmallVector<RendererMaterialBase*, 4> instances;
+		ShaderVariations variations;
 	};
 	};
 
 
 	/**	Base class for all RendererMaterial instances, containing common data and methods. */
 	/**	Base class for all RendererMaterial instances, containing common data and methods. */
 	class BS_EXPORT RendererMaterialBase
 	class BS_EXPORT RendererMaterialBase
 	{
 	{
 	public:
 	public:
+		RendererMaterialBase() { }
 		virtual ~RendererMaterialBase() { }
 		virtual ~RendererMaterialBase() { }
 
 
 		/**	Returns the internal material. */
 		/**	Returns the internal material. */
@@ -48,11 +162,17 @@ namespace bs { namespace ct
 		/** Returns the internal parameter set containing GPU bindable parameters. */
 		/** Returns the internal parameter set containing GPU bindable parameters. */
 		SPtr<GpuParamsSet> getParamsSet() const { return mParamsSet; }
 		SPtr<GpuParamsSet> getParamsSet() const { return mParamsSet; }
 
 
+		/** 
+		 * Helper field to be set before construction. Identifiers the variation of the material to initialize this 
+		 * object with. 
+		 */
+		UINT32 _varIdx;
 	protected:
 	protected:
 		friend class RendererMaterialManager;
 		friend class RendererMaterialManager;
 
 
 		SPtr<Material> mMaterial;
 		SPtr<Material> mMaterial;
 		SPtr<GpuParamsSet> mParamsSet;
 		SPtr<GpuParamsSet> mParamsSet;
+		ShaderVariation mVariation;
 	};
 	};
 
 
 	/**	Helper class to initialize all renderer materials as soon as the library is loaded. */
 	/**	Helper class to initialize all renderer materials as soon as the library is loaded. */
@@ -74,16 +194,54 @@ namespace bs { namespace ct
 	class RendererMaterial : public RendererMaterialBase
 	class RendererMaterial : public RendererMaterialBase
 	{
 	{
 	public:
 	public:
+		virtual ~RendererMaterial() { }
+
+		/** 
+		 * Retrieves an instance of this renderer material. If material has multiple variations the first available
+		 * variation will be returned. 
+		 */
+		static T* get()
+		{
+			if(mMetaData.instances[0] == nullptr)
+			{
+				RendererMaterialBase* mat = bs_alloc<T>();
+				mat->_varIdx = 0;
+				new (mat) T();
+				
+				mMetaData.instances[0] = mat;
+			}
+
+			return (T*)mMetaData.instances[0];
+		}
+
+		/** Retrieves an instance of a particular variation of this renderer material. */
+		static T* get(const ShaderVariation& variation)
+		{
+			UINT32 varIdx = variation.getIdx();
+
+			if(mMetaData.instances[varIdx] == nullptr)
+			{
+				RendererMaterialBase* mat = bs_alloc<T>();
+				mat->_varIdx = varIdx;
+				new (mat) T();
+				
+				mMetaData.instances[varIdx] = mat;
+			}
+
+			return (T*)mMetaData.instances[varIdx];
+		}
+
+	protected:
 		RendererMaterial()
 		RendererMaterial()
 		{
 		{
 			mInitOnStart.instantiate();
 			mInitOnStart.instantiate();
-			mMaterial = Material::create(mMetaData.shader);
+			mMaterial = Material::create(mMetaData.shaders[_varIdx]);
 			mParamsSet = mMaterial->createParamsSet();
 			mParamsSet = mMaterial->createParamsSet();
-		}
 
 
-		virtual ~RendererMaterial() { }
+			if(!mMetaData.variations.getVariations().empty())
+				mVariation = mMetaData.variations.get(_varIdx);
+		}
 
 
-	protected:
 		friend class RendererMaterialManager;
 		friend class RendererMaterialManager;
 
 
 		static RendererMaterialMetaData mMetaData;
 		static RendererMaterialMetaData mMetaData;

+ 1 - 0
Source/BansheeEngine/Include/BsRendererMaterialManager.h

@@ -26,6 +26,7 @@ namespace bs
 			ct::RendererMaterialMetaData* metaData;
 			ct::RendererMaterialMetaData* metaData;
 			Path shaderPath;
 			Path shaderPath;
 			Path resourcePath;
 			Path resourcePath;
+			UINT32 variationIdx;
 		};
 		};
 
 
 	public:
 	public:

+ 24 - 20
Source/BansheeEngine/Include/BsRendererUtility.h

@@ -15,18 +15,8 @@ namespace bs { namespace ct
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
-	/** 
-	 * Shader that copies a source texture into a render target, and optionally resolves it. 
-	 * 
-	 * @tparam	MSAA_COUNT		Number of MSAA samples in the input texture. If larger than 1 the texture will be resolved
-	 *							before written to the destination.
-	 * @tparam	IS_COLOR		If true the input is assumed to be a 4-component color texture. If false it is assumed
-	 *							the input is a 1-component depth texture. This controls how is the texture resolve and is
-	 *							only relevant if MSAA_COUNT > 1. Color texture MSAA samples will be averaged, while for
-	 *							depth textures the minimum of all samples will be used.
-	 */
-	template<int MSAA_COUNT, bool IS_COLOR = true>
-	class BlitMat : public RendererMaterial<BlitMat<MSAA_COUNT, IS_COLOR>>
+	/** Shader that copies a source texture into a render target, and optionally resolves it. */
+	class BlitMat : public RendererMaterial<BlitMat>
 	{
 	{
 		RMAT_DEF("Blit.bsl");
 		RMAT_DEF("Blit.bsl");
 
 
@@ -35,8 +25,30 @@ namespace bs { namespace ct
 
 
 		/** Updates the parameter buffers used by the material. */
 		/** Updates the parameter buffers used by the material. */
 		void setParameters(const SPtr<Texture>& source);
 		void setParameters(const SPtr<Texture>& source);
+
+		/** 
+		 * Returns the material variation matching the provided parameters.
+		 *
+		 * @param	msaaCount		Number of MSAA samples in the input texture. If larger than 1 the texture will be resolved
+		 *							before written to the destination.
+		 * @param	isColor			If true the input is assumed to be a 4-component color texture. If false it is assumed
+		 *							the input is a 1-component depth texture. This controls how is the texture resolve and is
+		 *							only relevant if @p msaaCount > 1. Color texture MSAA samples will be averaged, while for
+		 *							depth textures the minimum of all samples will be used.
+		 */
+		static BlitMat* getVariation(UINT32 msaaCount, bool isColor);
 	private:
 	private:
 		MaterialParamTexture mSource;
 		MaterialParamTexture mSource;
+
+		static ShaderVariation VAR_1MSAA_Color;
+		static ShaderVariation VAR_2MSAA_Color;
+		static ShaderVariation VAR_4MSAA_Color;
+		static ShaderVariation VAR_8MSAA_Color;
+
+		static ShaderVariation VAR_1MSAA_Depth;
+		static ShaderVariation VAR_2MSAA_Depth;
+		static ShaderVariation VAR_4MSAA_Depth;
+		static ShaderVariation VAR_8MSAA_Depth;
 	};
 	};
 
 
 	/**
 	/**
@@ -182,14 +194,6 @@ namespace bs { namespace ct
 		SPtr<Mesh> mPointLightStencilMesh;
 		SPtr<Mesh> mPointLightStencilMesh;
 		SPtr<Mesh> mSpotLightStencilMesh;
 		SPtr<Mesh> mSpotLightStencilMesh;
 		SPtr<Mesh> mSkyBoxMesh;
 		SPtr<Mesh> mSkyBoxMesh;
-
-		BlitMat<1, true> mBlitMat_Color_NoMSAA;
-		BlitMat<2, true> mBlitMat_Color_MSAA2x;
-		BlitMat<4, true> mBlitMat_Color_MSAA4x;
-		BlitMat<8, true> mBlitMat_Color_MSAA8x;
-		BlitMat<2, false> mBlitMat_Depth_MSAA2x;
-		BlitMat<4, false> mBlitMat_Depth_MSAA4x;
-		BlitMat<8, false> mBlitMat_Depth_MSAA8x;
 	};
 	};
 
 
 	/** Provides easy access to RendererUtility. */
 	/** Provides easy access to RendererUtility. */

+ 81 - 70
Source/BansheeEngine/Source/BsIBLUtility.cpp

@@ -8,30 +8,6 @@
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
-	struct IBLUtility::Members
-	{
-		ReflectionCubeDownsampleMat downsampleMat;
-		ReflectionCubeImportanceSampleMat importanceSampleMat;
-
-		IrradianceComputeSHMat<3> shCompute3;
-		IrradianceComputeSHMat<5> shCompute5;
-		IrradianceReduceSHMat<3> shReduce3;
-		IrradianceReduceSHMat<5> shReduce5;
-		IrradianceProjectSHMat shProject5;
-	};
-
-	IBLUtility::Members* IBLUtility::m = nullptr;
-
-	void IBLUtility::startUp()
-	{
-		m = bs_new<Members>();
-	}
-
-	void IBLUtility::shutDown()
-	{
-		bs_delete(m);
-	}
-
 	ReflectionCubeDownsampleParamDef gReflectionCubeDownsampleParamDef;
 	ReflectionCubeDownsampleParamDef gReflectionCubeDownsampleParamDef;
 
 
 	ReflectionCubeDownsampleMat::ReflectionCubeDownsampleMat()
 	ReflectionCubeDownsampleMat::ReflectionCubeDownsampleMat()
@@ -42,7 +18,7 @@ namespace bs { namespace ct
 		mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
 		mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
 	}
 	}
 
 
-	void ReflectionCubeDownsampleMat::_initDefines(ShaderDefines& defines)
+	void ReflectionCubeDownsampleMat::_initVariations(ShaderVariations& variations)
 	{
 	{
 		// Do nothing
 		// Do nothing
 	}
 	}
@@ -72,13 +48,17 @@ namespace bs { namespace ct
 		mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
 		mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
 	}
 	}
 
 
-	void ReflectionCubeImportanceSampleMat::_initDefines(ShaderDefines& defines)
+	void ReflectionCubeImportanceSampleMat::_initVariations(ShaderVariations& variations)
 	{
 	{
-		defines.set("NUM_SAMPLES", NUM_SAMPLES); 
+		ShaderVariation variation({
+			ShaderVariation::Param("NUM_SAMPLES", NUM_SAMPLES)
+		});
+
+		variations.add(variation);
 	}
 	}
 
 
 	void ReflectionCubeImportanceSampleMat::execute(const SPtr<Texture>& source, UINT32 face, UINT32 mip, 
 	void ReflectionCubeImportanceSampleMat::execute(const SPtr<Texture>& source, UINT32 face, UINT32 mip, 
-													const SPtr<RenderTarget>& target)
+		const SPtr<RenderTarget>& target)
 	{
 	{
 		mInputTexture.set(source);
 		mInputTexture.set(source);
 		gReflectionCubeImportanceSampleParamDef.gCubeFace.set(mParamBuffer, face);
 		gReflectionCubeImportanceSampleParamDef.gCubeFace.set(mParamBuffer, face);
@@ -103,12 +83,28 @@ namespace bs { namespace ct
 
 
 	IrradianceComputeSHParamDef gIrradianceComputeSHParamDef;
 	IrradianceComputeSHParamDef gIrradianceComputeSHParamDef;
 
 
+	// TILE_WIDTH * TILE_HEIGHT must be pow2 because of parallel reduction algorithm
 	const static UINT32 TILE_WIDTH = 8;
 	const static UINT32 TILE_WIDTH = 8;
 	const static UINT32 TILE_HEIGHT = 8;
 	const static UINT32 TILE_HEIGHT = 8;
+
+	// For very small textures this should be reduced so number of launched threads can properly utilize GPU cores
 	const static UINT32 PIXELS_PER_THREAD = 4;
 	const static UINT32 PIXELS_PER_THREAD = 4;
 
 
-	template<int ORDER>
-	IrradianceComputeSHMat<ORDER>::IrradianceComputeSHMat()
+	ShaderVariation IrradianceComputeSHMat::VAR_Order3 = ShaderVariation({
+		ShaderVariation::Param("TILE_WIDTH", TILE_WIDTH),
+		ShaderVariation::Param("TILE_HEIGHT", TILE_HEIGHT),
+		ShaderVariation::Param("PIXELS_PER_THREAD", PIXELS_PER_THREAD),
+		ShaderVariation::Param("ORDER", 3),
+	});
+
+	ShaderVariation IrradianceComputeSHMat::VAR_Order5 = ShaderVariation({
+		ShaderVariation::Param("TILE_WIDTH", TILE_WIDTH),
+		ShaderVariation::Param("TILE_HEIGHT", TILE_HEIGHT),
+		ShaderVariation::Param("PIXELS_PER_THREAD", PIXELS_PER_THREAD),
+		ShaderVariation::Param("ORDER", 5),
+	});
+
+	IrradianceComputeSHMat::IrradianceComputeSHMat()
 	{
 	{
 		mParamBuffer = gIrradianceComputeSHParamDef.createBuffer();
 		mParamBuffer = gIrradianceComputeSHParamDef.createBuffer();
 
 
@@ -119,21 +115,13 @@ namespace bs { namespace ct
 		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputBuffer);
 		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputBuffer);
 	}
 	}
 
 
-	template<int ORDER>
-	void IrradianceComputeSHMat<ORDER>::_initDefines(ShaderDefines& defines)
+	void IrradianceComputeSHMat::_initVariations(ShaderVariations& variations)
 	{
 	{
-		// TILE_WIDTH * TILE_HEIGHT must be pow2 because of parallel reduction algorithm
-		defines.set("TILE_WIDTH", TILE_WIDTH);
-		defines.set("TILE_HEIGHT", TILE_HEIGHT);
-
-		// For very small textures this should be reduced so number of launched threads can properly utilize GPU cores
-		defines.set("PIXELS_PER_THREAD", PIXELS_PER_THREAD);
-
-		defines.set("ORDER", ORDER);
+		variations.add(VAR_Order3);
+		variations.add(VAR_Order5);
 	}
 	}
 
 
-	template<int ORDER>
-	void IrradianceComputeSHMat<ORDER>::execute(const SPtr<Texture>& source, UINT32 face, const SPtr<GpuBuffer>& output)
+	void IrradianceComputeSHMat::execute(const SPtr<Texture>& source, UINT32 face, const SPtr<GpuBuffer>& output)
 	{
 	{
 		auto& props = source->getProperties();
 		auto& props = source->getProperties();
 		UINT32 faceSize = props.getWidth();
 		UINT32 faceSize = props.getWidth();
@@ -157,8 +145,7 @@ namespace bs { namespace ct
 		rapi.dispatchCompute(dispatchSize.x, dispatchSize.y);
 		rapi.dispatchCompute(dispatchSize.x, dispatchSize.y);
 	}
 	}
 
 
-	template<int ORDER>
-	SPtr<GpuBuffer> IrradianceComputeSHMat<ORDER>::createOutputBuffer(const SPtr<Texture>& source, UINT32& numCoeffSets)
+	SPtr<GpuBuffer> IrradianceComputeSHMat::createOutputBuffer(const SPtr<Texture>& source, UINT32& numCoeffSets)
 	{
 	{
 		auto& props = source->getProperties();
 		auto& props = source->getProperties();
 		UINT32 faceSize = props.getWidth();
 		UINT32 faceSize = props.getWidth();
@@ -176,7 +163,7 @@ namespace bs { namespace ct
 		bufferDesc.format = BF_UNKNOWN;
 		bufferDesc.format = BF_UNKNOWN;
 		bufferDesc.randomGpuWrite = true;
 		bufferDesc.randomGpuWrite = true;
 
 
-		if(ORDER == 3)
+		if(mVariation.getInt("ORDER") == 3)
 			bufferDesc.elementSize = sizeof(SHCoeffsAndWeight3);
 			bufferDesc.elementSize = sizeof(SHCoeffsAndWeight3);
 		else
 		else
 			bufferDesc.elementSize = sizeof(SHCoeffsAndWeight5);
 			bufferDesc.elementSize = sizeof(SHCoeffsAndWeight5);
@@ -184,13 +171,25 @@ namespace bs { namespace ct
 		return GpuBuffer::create(bufferDesc);
 		return GpuBuffer::create(bufferDesc);
 	}
 	}
 
 
-	template class IrradianceComputeSHMat<3>;
-	template class IrradianceComputeSHMat<5>;
+	IrradianceComputeSHMat* IrradianceComputeSHMat::getVariation(int order)
+	{
+		if (order == 3)
+			return get(VAR_Order3);
+
+		return get(VAR_Order5);
+	}
 
 
 	IrradianceReduceSHParamDef gIrradianceReduceSHParamDef;
 	IrradianceReduceSHParamDef gIrradianceReduceSHParamDef;
 
 
-	template<int ORDER>
-	IrradianceReduceSHMat<ORDER>::IrradianceReduceSHMat()
+	ShaderVariation IrradianceReduceSHMat::VAR_Order3 = ShaderVariation({
+		ShaderVariation::Param("ORDER", 3),
+	});
+
+	ShaderVariation IrradianceReduceSHMat::VAR_Order5 = ShaderVariation({
+		ShaderVariation::Param("ORDER", 5),
+	});
+
+	IrradianceReduceSHMat::IrradianceReduceSHMat()
 	{
 	{
 		mParamBuffer = gIrradianceReduceSHParamDef.createBuffer();
 		mParamBuffer = gIrradianceReduceSHParamDef.createBuffer();
 
 
@@ -201,14 +200,13 @@ namespace bs { namespace ct
 		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputBuffer);
 		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputBuffer);
 	}
 	}
 
 
-	template<int ORDER>
-	void IrradianceReduceSHMat<ORDER>::_initDefines(ShaderDefines& defines)
+	void IrradianceReduceSHMat::_initVariations(ShaderVariations& variations)
 	{
 	{
-		defines.set("ORDER", ORDER);
+		variations.add(VAR_Order3);
+		variations.add(VAR_Order5);
 	}
 	}
 
 
-	template<int ORDER>
-	void IrradianceReduceSHMat<ORDER>::execute(const SPtr<GpuBuffer>& source, UINT32 numCoeffSets, 
+	void IrradianceReduceSHMat::execute(const SPtr<GpuBuffer>& source, UINT32 numCoeffSets, 
 		const SPtr<GpuBuffer>& output, UINT32 outputIdx)
 		const SPtr<GpuBuffer>& output, UINT32 outputIdx)
 	{
 	{
 		gIrradianceReduceSHParamDef.gNumEntries.set(mParamBuffer, numCoeffSets);
 		gIrradianceReduceSHParamDef.gNumEntries.set(mParamBuffer, numCoeffSets);
@@ -224,8 +222,7 @@ namespace bs { namespace ct
 		rapi.dispatchCompute(1);
 		rapi.dispatchCompute(1);
 	}
 	}
 
 
-	template<int ORDER>
-	SPtr<GpuBuffer> IrradianceReduceSHMat<ORDER>::createOutputBuffer(UINT32 numEntries)
+	SPtr<GpuBuffer> IrradianceReduceSHMat::createOutputBuffer(UINT32 numEntries)
 	{
 	{
 		GPU_BUFFER_DESC bufferDesc;
 		GPU_BUFFER_DESC bufferDesc;
 		bufferDesc.type = GBT_STRUCTURED;
 		bufferDesc.type = GBT_STRUCTURED;
@@ -233,7 +230,7 @@ namespace bs { namespace ct
 		bufferDesc.format = BF_UNKNOWN;
 		bufferDesc.format = BF_UNKNOWN;
 		bufferDesc.randomGpuWrite = true;
 		bufferDesc.randomGpuWrite = true;
 
 
-		if(ORDER == 3)
+		if(mVariation.getInt("ORDER") == 3)
 			bufferDesc.elementSize = sizeof(SHVector3RGB);
 			bufferDesc.elementSize = sizeof(SHVector3RGB);
 		else
 		else
 			bufferDesc.elementSize = sizeof(SHVector5RGB);
 			bufferDesc.elementSize = sizeof(SHVector5RGB);
@@ -241,8 +238,13 @@ namespace bs { namespace ct
 		return GpuBuffer::create(bufferDesc);
 		return GpuBuffer::create(bufferDesc);
 	}
 	}
 
 
-	template class IrradianceReduceSHMat<3>;
-	template class IrradianceReduceSHMat<5>;
+	IrradianceReduceSHMat* IrradianceReduceSHMat::getVariation(int order)
+	{
+		if (order == 3)
+			return get(VAR_Order3);
+
+		return get(VAR_Order5);
+	}
 
 
 	IrradianceProjectSHParamDef gIrradianceProjectSHParamDef;
 	IrradianceProjectSHParamDef gIrradianceProjectSHParamDef;
 
 
@@ -256,7 +258,7 @@ namespace bs { namespace ct
 		params->getBufferParam(GPT_FRAGMENT_PROGRAM, "gSHCoeffs", mInputBuffer);
 		params->getBufferParam(GPT_FRAGMENT_PROGRAM, "gSHCoeffs", mInputBuffer);
 	}
 	}
 
 
-	void IrradianceProjectSHMat::_initDefines(ShaderDefines& defines)
+	void IrradianceProjectSHMat::_initVariations(ShaderVariations& variations)
 	{
 	{
 		// Do nothing
 		// Do nothing
 	}
 	}
@@ -331,7 +333,8 @@ namespace bs { namespace ct
 
 
 				SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
 				SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
 
 
-				m->importanceSampleMat.execute(scratchCubemap, face, mip, target);
+				ReflectionCubeImportanceSampleMat* material = ReflectionCubeImportanceSampleMat::get();
+				material->execute(scratchCubemap, face, mip, target);
 			}
 			}
 		}
 		}
 
 
@@ -341,13 +344,17 @@ namespace bs { namespace ct
 
 
 	void IBLUtility::filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<Texture>& output)
 	void IBLUtility::filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<Texture>& output)
 	{
 	{
+		IrradianceComputeSHMat* shCompute = IrradianceComputeSHMat::getVariation(5);
+		IrradianceReduceSHMat* shReduce = IrradianceReduceSHMat::getVariation(5);
+		IrradianceProjectSHMat* shProject = IrradianceProjectSHMat::get();
+
 		UINT32 numCoeffSets;
 		UINT32 numCoeffSets;
-		SPtr<GpuBuffer> coeffSetBuffer = IrradianceComputeSHMat<5>::createOutputBuffer(cubemap, numCoeffSets);
+		SPtr<GpuBuffer> coeffSetBuffer = shCompute->createOutputBuffer(cubemap, numCoeffSets);
 		for (UINT32 face = 0; face < 6; face++)
 		for (UINT32 face = 0; face < 6; face++)
-			m->shCompute5.execute(cubemap, face, coeffSetBuffer);
+			shCompute->execute(cubemap, face, coeffSetBuffer);
 
 
-		SPtr<GpuBuffer> coeffBuffer = IrradianceReduceSHMat<5>::createOutputBuffer(1);
-		m->shReduce5.execute(coeffSetBuffer, numCoeffSets, coeffBuffer, 0);
+		SPtr<GpuBuffer> coeffBuffer = shReduce->createOutputBuffer(1);
+		shReduce->execute(coeffSetBuffer, numCoeffSets, coeffBuffer, 0);
 
 
 		for (UINT32 face = 0; face < 6; face++)
 		for (UINT32 face = 0; face < 6; face++)
 		{
 		{
@@ -358,19 +365,22 @@ namespace bs { namespace ct
 			cubeFaceRTDesc.colorSurfaces[0].mipLevel = 0;
 			cubeFaceRTDesc.colorSurfaces[0].mipLevel = 0;
 
 
 			SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
 			SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
-			m->shProject5.execute(coeffBuffer, face, target);
+			shProject->execute(coeffBuffer, face, target);
 		}
 		}
 	}
 	}
 
 
 	void IBLUtility::filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<GpuBuffer>& output, 
 	void IBLUtility::filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<GpuBuffer>& output, 
 		UINT32 outputIdx)
 		UINT32 outputIdx)
 	{
 	{
+		IrradianceComputeSHMat* shCompute = IrradianceComputeSHMat::getVariation(3);
+		IrradianceReduceSHMat* shReduce = IrradianceReduceSHMat::getVariation(3);
+
 		UINT32 numCoeffSets;
 		UINT32 numCoeffSets;
-		SPtr<GpuBuffer> coeffSetBuffer = IrradianceComputeSHMat<3>::createOutputBuffer(cubemap, numCoeffSets);
+		SPtr<GpuBuffer> coeffSetBuffer = shCompute->createOutputBuffer(cubemap, numCoeffSets);
 		for (UINT32 face = 0; face < 6; face++)
 		for (UINT32 face = 0; face < 6; face++)
-			m->shCompute3.execute(cubemap, face, coeffSetBuffer);
+			shCompute->execute(cubemap, face, coeffSetBuffer);
 
 
-		m->shReduce3.execute(coeffSetBuffer, numCoeffSets, output, outputIdx);
+		shReduce->execute(coeffSetBuffer, numCoeffSets, output, outputIdx);
 	}
 	}
 
 
 	void IBLUtility::scaleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, UINT32 dstMip)
 	void IBLUtility::scaleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst, UINT32 dstMip)
@@ -431,7 +441,8 @@ namespace bs { namespace ct
 			SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
 			SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
 
 
 			TextureSurface sourceSurface(srcMip, 1, 0, 6);
 			TextureSurface sourceSurface(srcMip, 1, 0, 6);
-			m->downsampleMat.execute(src, face, sourceSurface, target);
+			ReflectionCubeDownsampleMat* material = ReflectionCubeDownsampleMat::get();
+			material->execute(src, face, sourceSurface, target);
 		}
 		}
 	}
 	}
 }}
 }}

+ 70 - 0
Source/BansheeEngine/Source/BsRendererMaterial.cpp

@@ -4,5 +4,75 @@
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
+	ShaderVariation::ShaderVariation(const SmallVector<Param, 4>& params)
+	{
+		for (auto& entry : params)
+			mParams[entry.name] = entry;
+	}
 
 
+	INT32 ShaderVariation::getInt(const String& name)
+	{
+		auto iterFind = mParams.find(name);
+		if (iterFind == mParams.end())
+			return 0;
+		else
+			return iterFind->second.i;
+	}
+
+	UINT32 ShaderVariation::getUInt(const String& name)
+	{
+		auto iterFind = mParams.find(name);
+		if (iterFind == mParams.end())
+			return 0;
+		else
+			return iterFind->second.ui;
+	}
+
+	float ShaderVariation::getFloat(const String& name)
+	{
+		auto iterFind = mParams.find(name);
+		if (iterFind == mParams.end())
+			return 0.0f;
+		else
+			return iterFind->second.f;
+	}
+
+	bool ShaderVariation::getBool(const String& name)
+	{
+		auto iterFind = mParams.find(name);
+		if (iterFind == mParams.end())
+			return false;
+		else
+			return iterFind->second.i > 0 ? true : false;
+	}
+
+	ShaderDefines ShaderVariation::getDefines() const
+	{
+		ShaderDefines defines;
+		for (auto& entry : mParams)
+		{
+			switch (entry.second.type)
+			{
+			case Int:
+			case Bool:
+				defines.set(entry.first, entry.second.i);
+				break;
+			case UInt:
+				defines.set(entry.first, entry.second.ui);
+				break;
+			case Float:
+				defines.set(entry.first, entry.second.f);
+				break;
+			}
+		}
+
+		return defines;
+	}
+
+	void ShaderVariations::add(ShaderVariation& variation)
+	{
+		variation.mIdx = mNextIdx++;
+
+		mVariations.push_back(variation);
+	}
 }}
 }}

+ 50 - 10
Source/BansheeEngine/Source/BsRendererMaterialManager.cpp

@@ -12,6 +12,8 @@ namespace bs
 	{
 	{
 		BuiltinResources& br = BuiltinResources::instance();
 		BuiltinResources& br = BuiltinResources::instance();
 
 
+		// Note: Ideally I want to avoid loading all materials, and instead just load those that are used. This might be a
+		// problem on lower end systems that don't support all renderer features.
 		Vector<RendererMaterialData>& materials = getMaterials();
 		Vector<RendererMaterialData>& materials = getMaterials();
 		Vector<SPtr<ct::Shader>> shaders;
 		Vector<SPtr<ct::Shader>> shaders;
 		for (auto& material : materials)
 		for (auto& material : materials)
@@ -36,15 +38,33 @@ namespace bs
 		Lock lock(getMutex());
 		Lock lock(getMutex());
 
 
 		Vector<RendererMaterialData>& materials = getMaterials();
 		Vector<RendererMaterialData>& materials = getMaterials();
-		UINT32 variationIdx = 0;
-		for (auto& entry : materials)
+
+		const SmallVector<ct::ShaderVariation, 4>& variations = metaData->variations.getVariations();
+
+		if(variations.empty())
 		{
 		{
-			if (entry.shaderPath == shaderPath)
-				variationIdx++;
+			metaData->shaders.resize(1);
+			metaData->instances.resize(1);
+
+			Path resourcePath = _getVariationPath(shaderPath, 0);
+			materials.push_back({ metaData, shaderPath, resourcePath, 0 });
 		}
 		}
+		else
+		{
+			metaData->shaders.resize(variations.size());
+			metaData->instances.resize(variations.size());
 
 
-		Path resourcePath = _getVariationPath(shaderPath, variationIdx);
-		materials.push_back({metaData, shaderPath, resourcePath });
+			UINT32 variationIdx = 0;
+			for (auto& variation : variations)
+			{
+				assert(variation.getIdx() == variationIdx);
+
+				Path resourcePath = _getVariationPath(shaderPath, variationIdx);
+				materials.push_back({ metaData, shaderPath, resourcePath, variationIdx });
+
+				variationIdx++;
+			}
+		}
 	}
 	}
 
 
 	Vector<ShaderDefines> RendererMaterialManager::_getVariations(const Path& shaderPath)
 	Vector<ShaderDefines> RendererMaterialManager::_getVariations(const Path& shaderPath)
@@ -55,7 +75,17 @@ namespace bs
 		for (auto& entry : materials)
 		for (auto& entry : materials)
 		{
 		{
 			if (entry.shaderPath == shaderPath)
 			if (entry.shaderPath == shaderPath)
-				output.push_back(entry.metaData->defines);
+			{
+				if(entry.metaData->variations.getVariations().empty())
+				{
+					output.push_back(ShaderDefines());
+				}
+				else
+				{
+					const ct::ShaderVariation& variation = entry.metaData->variations.get(entry.variationIdx);
+					output.push_back(variation.getDefines());
+				}
+			}
 		}
 		}
 
 
 		return output;
 		return output;
@@ -83,7 +113,7 @@ namespace bs
 
 
 		Vector<RendererMaterialData>& materials = getMaterials();
 		Vector<RendererMaterialData>& materials = getMaterials();
 		for (UINT32 i = 0; i < materials.size(); i++)
 		for (UINT32 i = 0; i < materials.size(); i++)
-			materials[i].metaData->shader = shaders[i];
+			materials[i].metaData->shaders[materials[i].variationIdx] = shaders[i];
 	}
 	}
 
 
 	void RendererMaterialManager::destroyOnCore()
 	void RendererMaterialManager::destroyOnCore()
@@ -92,7 +122,17 @@ namespace bs
 
 
 		Vector<RendererMaterialData>& materials = getMaterials();
 		Vector<RendererMaterialData>& materials = getMaterials();
 		for (UINT32 i = 0; i < materials.size(); i++)
 		for (UINT32 i = 0; i < materials.size(); i++)
-			materials[i].metaData->shader = nullptr;
+		{
+			materials[i].metaData->shaders.clear();
+
+			for (auto& entry : materials[i].metaData->instances)
+			{
+				if(entry != nullptr)
+					bs_delete(entry);
+			}
+
+			materials[i].metaData->instances.clear();
+		}
 	}
 	}
 
 
 	Vector<RendererMaterialManager::RendererMaterialData>& RendererMaterialManager::getMaterials()
 	Vector<RendererMaterialManager::RendererMaterialData>& RendererMaterialManager::getMaterials()
@@ -106,4 +146,4 @@ namespace bs
 		static Mutex mutex;
 		static Mutex mutex;
 		return mutex;
 		return mutex;
 	}
 	}
-}
+}

+ 91 - 73
Source/BansheeEngine/Source/BsRendererUtility.cpp

@@ -122,14 +122,10 @@ namespace bs { namespace ct
 
 
 			mSkyBoxMesh = Mesh::create(meshData);
 			mSkyBoxMesh = Mesh::create(meshData);
 		}
 		}
-
-		IBLUtility::startUp();
 	}
 	}
 
 
 	RendererUtility::~RendererUtility()
 	RendererUtility::~RendererUtility()
-	{
-		IBLUtility::shutDown();
-	}
+	{ }
 
 
 	void RendererUtility::setPass(const SPtr<Material>& material, UINT32 passIdx, UINT32 techniqueIdx)
 	void RendererUtility::setPass(const SPtr<Material>& material, UINT32 passIdx, UINT32 techniqueIdx)
 	{
 	{
@@ -253,61 +249,12 @@ namespace bs { namespace ct
 	void RendererUtility::blit(const SPtr<Texture>& texture, const Rect2I& area, bool flipUV, bool isDepth)
 	void RendererUtility::blit(const SPtr<Texture>& texture, const Rect2I& area, bool flipUV, bool isDepth)
 	{
 	{
 		auto& texProps = texture->getProperties();
 		auto& texProps = texture->getProperties();
-		SPtr<Material> mat;
-		SPtr<GpuParamsSet> params;
-
-#define PICK_MATERIAL(Type)									\
-			mat = mBlitMat_##Type.getMaterial();			\
-			params = mBlitMat_##Type.getParamsSet();		\
-			mBlitMat_##Type.setParameters(texture);
-
-		if (texProps.getNumSamples() > 1)
-		{
-			if(texProps.getNumSamples() > 8)
-				LOGWRN("Unsupported sample count in an MSAA texture");
-
-			if(isDepth)
-			{
-				switch(texProps.getNumSamples())
-				{
-				case 2:
-					PICK_MATERIAL(Depth_MSAA2x)
-					break;
-				case 4:
-					PICK_MATERIAL(Depth_MSAA4x)
-					break;
-				default:
-				case 8:
-					PICK_MATERIAL(Depth_MSAA8x)
-					break;
-				}
-			}
-			else
-			{
-				switch(texProps.getNumSamples())
-				{
-				case 2:
-					PICK_MATERIAL(Color_MSAA2x)
-					break;
-				case 4:
-					PICK_MATERIAL(Color_MSAA4x)
-					break;
-				default:
-				case 8:
-					PICK_MATERIAL(Color_MSAA8x)
-					break;
-				}
-			}
-		}
-		else
-		{
-			PICK_MATERIAL(Color_NoMSAA)
-		}
 
 
-#undef PICK_MATERIAL
+		BlitMat* blitMat = BlitMat::getVariation(texProps.getNumSamples(), !isDepth);
+		blitMat->setParameters(texture);
 
 
-		setPass(mat);
-		setPassParams(params);
+		setPass(blitMat->getMaterial());
+		setPassParams(blitMat->getParamsSet());
 
 
 		Rect2 fArea((float)area.x, (float)area.y, (float)area.width, (float)area.height);
 		Rect2 fArea((float)area.x, (float)area.y, (float)area.width, (float)area.height);
 		if (area.width == 0 || area.height == 0)
 		if (area.width == 0 || area.height == 0)
@@ -393,31 +340,102 @@ namespace bs { namespace ct
 		return RendererUtility::instance();
 		return RendererUtility::instance();
 	}
 	}
 
 
-	template<int MSAA_COUNT, bool IS_COLOR>
-	BlitMat<MSAA_COUNT, IS_COLOR>::BlitMat()
+	ShaderVariation BlitMat::VAR_1MSAA_Color = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 1),
+		ShaderVariation::Param("COLOR", true)
+	});
+	ShaderVariation BlitMat::VAR_2MSAA_Color = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 2),
+		ShaderVariation::Param("COLOR", true)
+	});
+
+	ShaderVariation BlitMat::VAR_4MSAA_Color = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 4),
+		ShaderVariation::Param("COLOR", true)
+	});
+
+	ShaderVariation BlitMat::VAR_8MSAA_Color = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 8),
+		ShaderVariation::Param("COLOR", true)
+	});
+
+	ShaderVariation BlitMat::VAR_1MSAA_Depth = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 1),
+		ShaderVariation::Param("COLOR", false)
+	});
+
+	ShaderVariation BlitMat::VAR_2MSAA_Depth = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 2),
+		ShaderVariation::Param("COLOR", false)
+	});
+
+	ShaderVariation BlitMat::VAR_4MSAA_Depth = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 4),
+		ShaderVariation::Param("COLOR", false)
+	});
+
+	ShaderVariation BlitMat::VAR_8MSAA_Depth = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 8),
+		ShaderVariation::Param("COLOR", false)
+	});
+
+
+	BlitMat::BlitMat()
 	{
 	{
 		mSource = mMaterial->getParamTexture("gSource");
 		mSource = mMaterial->getParamTexture("gSource");
 	}
 	}
 
 
-	template<int MSAA_COUNT, bool IS_COLOR>
-	void BlitMat<MSAA_COUNT, IS_COLOR>::_initDefines(ShaderDefines& defines)
+	void BlitMat::_initVariations(ShaderVariations& variations)
 	{
 	{
-		defines.set("MSAA_COUNT", MSAA_COUNT);
-		defines.set("COLOR", IS_COLOR ? 1 : 0);
+		variations.add(VAR_1MSAA_Color);
+		variations.add(VAR_2MSAA_Color);
+		variations.add(VAR_4MSAA_Color);
+		variations.add(VAR_8MSAA_Color);
+
+		variations.add(VAR_1MSAA_Depth);
+		variations.add(VAR_2MSAA_Depth);
+		variations.add(VAR_4MSAA_Depth);
+		variations.add(VAR_8MSAA_Depth);
 	}
 	}
 
 
-	template<int MSAA_COUNT, bool IS_COLOR>
-	void BlitMat<MSAA_COUNT, IS_COLOR>::setParameters(const SPtr<Texture>& source)
+	void BlitMat::setParameters(const SPtr<Texture>& source)
 	{
 	{
 		mSource.set(source);
 		mSource.set(source);
 		mMaterial->updateParamsSet(mParamsSet);
 		mMaterial->updateParamsSet(mParamsSet);
 	}
 	}
 
 
-	template class BlitMat<1, true>;
-	template class BlitMat<2, true>;
-	template class BlitMat<4, true>;
-	template class BlitMat<8, true>;
-	template class BlitMat<2, false>;
-	template class BlitMat<4, false>;
-	template class BlitMat<8, false>;
+	BlitMat* BlitMat::getVariation(UINT32 msaaCount, bool isColor)
+	{
+		if (msaaCount > 1)
+		{
+			if(isColor)
+			{
+				switch(msaaCount)
+				{
+				case 2:
+					return get(VAR_2MSAA_Color);
+				case 4:
+					return get(VAR_4MSAA_Color);
+				default:
+				case 8:
+					return get(VAR_8MSAA_Color);
+				}
+			}
+			else
+			{
+				switch(msaaCount)
+				{
+				case 2:
+					return get(VAR_2MSAA_Depth);
+				case 4:
+					return get(VAR_4MSAA_Depth);
+				default:
+				case 8:
+					return get(VAR_8MSAA_Depth);
+				}
+			}
+		}
+		else
+			return get(VAR_1MSAA_Color);
+	}
 }}
 }}

+ 25 - 1
Source/BansheeUtility/Include/BsStringID.h

@@ -101,6 +101,9 @@ namespace bs
 			return mData->chars;
 			return mData->chars;
 		}
 		}
 
 
+		/** Returns the unique identifier of the string. */
+		UINT32 id() const { return mData ? mData->id : -1; }
+
 		static const StringID NONE;
 		static const StringID NONE;
 
 
 	private:
 	private:
@@ -193,4 +196,25 @@ namespace bs
 
 
 	/** @endcond */
 	/** @endcond */
 	/** @} */
 	/** @} */
-}
+}
+
+/** @cond STDLIB */
+/** @addtogroup String
+ *  @{
+ */
+
+namespace std
+{
+/**	Hash value generator for StringID. */
+template<>
+struct hash<bs::StringID>
+{
+	size_t operator()(const bs::StringID& value) const
+	{
+		return (size_t)value.id();
+	}
+};
+}
+
+/** @} */
+/** @endcond */

+ 2 - 1
Source/Examples/ExampleGettingStarted/Source/Main.cpp

@@ -390,7 +390,8 @@ namespace bs
 		HCamera guiCamera = guiSO->addComponent<CCamera>(window);
 		HCamera guiCamera = guiSO->addComponent<CCamera>(window);
 
 
 		// Notify the renderer that the camera will only be used for overlays (e.g. GUI) so it can optimize its usage
 		// Notify the renderer that the camera will only be used for overlays (e.g. GUI) so it can optimize its usage
-		guiCamera->setFlag(CameraFlag::Overlay, true);
+		SPtr<RenderSettings> settings = guiCamera->getRenderSettings();
+		settings->overlayOnly = true;
 
 
 		// Set up GUI camera properties. 
 		// Set up GUI camera properties. 
 		// We don't care about aspect ratio for GUI camera.
 		// We don't care about aspect ratio for GUI camera.

+ 15 - 25
Source/MBansheeEditor/Inspectors/CameraInspector.cs

@@ -31,12 +31,11 @@ namespace BansheeEditor
         private GUIColorField clearColorField = new GUIColorField(new LocEdString("Clear color"));
         private GUIColorField clearColorField = new GUIColorField(new LocEdString("Clear color"));
         private GUIIntField priorityField = new GUIIntField(new LocEdString("Render priority"));
         private GUIIntField priorityField = new GUIIntField(new LocEdString("Render priority"));
         private GUIListBoxField layersField = new GUIListBoxField(Layers.Names, true, new LocEdString("Layers"));
         private GUIListBoxField layersField = new GUIListBoxField(Layers.Names, true, new LocEdString("Layers"));
-        private GUIToggleField hdrField = new GUIToggleField(new LocEdString("HDR"));
         private GUIToggleField mainField = new GUIToggleField(new LocEdString("Main"));
         private GUIToggleField mainField = new GUIToggleField(new LocEdString("Main"));
 
 
-        private GUIToggle postProcessFoldout = new GUIToggle(new LocEdString("Post processing"), EditorStyles.Foldout);
-        private PostProcessSettingsGUI postProcessGUI;
-        private GUILayout postProcessLayout;
+        private GUIToggle renderSettingsFoldout = new GUIToggle(new LocEdString("Render settings"), EditorStyles.Foldout);
+        private RenderSettingsGUI renderSettingsGUI;
+        private GUILayout renderSettingsLayout;
 
 
         private ulong layersValue = 0;
         private ulong layersValue = 0;
         private InspectableState modifyState;
         private InspectableState modifyState;
@@ -76,8 +75,7 @@ namespace BansheeEditor
             clearColorField.Value = camera.ClearColor;
             clearColorField.Value = camera.ClearColor;
             priorityField.Value = camera.Priority;
             priorityField.Value = camera.Priority;
             mainField.Value = camera.Main;
             mainField.Value = camera.Main;
-            hdrField.Value = camera.HDR;
-            postProcessGUI.Settings = camera.PostProcess;
+            renderSettingsGUI.Settings = camera.RenderSettings;
 
 
             if (layersValue != camera.Layers)
             if (layersValue != camera.Layers)
             {
             {
@@ -223,13 +221,6 @@ namespace BansheeEditor
                     ConfirmModify();
                     ConfirmModify();
                 };
                 };
 
 
-                hdrField.OnChanged += x =>
-                {
-                    camera.HDR = x;
-                    MarkAsModified();
-                    ConfirmModify();
-                };
-
                 Layout.AddElement(projectionTypeField);
                 Layout.AddElement(projectionTypeField);
                 Layout.AddElement(fieldOfView);
                 Layout.AddElement(fieldOfView);
                 Layout.AddElement(orthoHeight);
                 Layout.AddElement(orthoHeight);
@@ -255,27 +246,26 @@ namespace BansheeEditor
                 Layout.AddElement(priorityField);
                 Layout.AddElement(priorityField);
                 Layout.AddElement(layersField);
                 Layout.AddElement(layersField);
                 Layout.AddElement(mainField);
                 Layout.AddElement(mainField);
-                Layout.AddElement(hdrField);
 
 
-                postProcessFoldout.OnToggled += x =>
+                renderSettingsFoldout.OnToggled += x =>
                 {
                 {
-                    Persistent.SetBool("postProcess_Expanded", x);
-                    postProcessLayout.Active = x;
+                    Persistent.SetBool("renderSettings_Expanded", x);
+                    renderSettingsLayout.Active = x;
                 };
                 };
-                Layout.AddElement(postProcessFoldout);
+                Layout.AddElement(renderSettingsFoldout);
 
 
-                postProcessLayout = Layout.AddLayoutX();
+                renderSettingsLayout = Layout.AddLayoutX();
                 {
                 {
-                    postProcessLayout.AddSpace(10);
+                    renderSettingsLayout.AddSpace(10);
 
 
-                    GUILayoutY contentsLayout = postProcessLayout.AddLayoutY();
-                    postProcessGUI = new PostProcessSettingsGUI(camera.PostProcess, contentsLayout, Persistent);
-                    postProcessGUI.OnChanged += x => { camera.PostProcess = x; MarkAsModified(); };
-                    postProcessGUI.OnConfirmed += ConfirmModify;
+                    GUILayoutY contentsLayout = renderSettingsLayout.AddLayoutY();
+                    renderSettingsGUI = new RenderSettingsGUI(camera.RenderSettings, contentsLayout, Persistent);
+                    renderSettingsGUI.OnChanged += x => { camera.RenderSettings = x; MarkAsModified(); };
+                    renderSettingsGUI.OnConfirmed += ConfirmModify;
                 }
                 }
 
 
                 ToggleTypeSpecificFields(camera.ProjectionType);
                 ToggleTypeSpecificFields(camera.ProjectionType);
-                postProcessLayout.Active = Persistent.GetBool("postProcess_Expanded");
+                renderSettingsLayout.Active = Persistent.GetBool("renderSettings_Expanded");
             }
             }
         }
         }
 
 

+ 31 - 6
Source/MBansheeEditor/Inspectors/PostProcessSettingsInspector.cs → Source/MBansheeEditor/Inspectors/RenderSettingsInspector.cs

@@ -351,13 +351,18 @@ namespace BansheeEditor
     }
     }
 
 
     /// <summary>
     /// <summary>
-    /// Draws GUI elements for inspecting an <see cref="PostProcessSettings"/> object.
+    /// Draws GUI elements for inspecting an <see cref="RenderSettings"/> object.
     /// </summary>
     /// </summary>
-    internal class PostProcessSettingsGUI
+    internal class RenderSettingsGUI
     {
     {
-        private PostProcessSettings settings;
+        private RenderSettings settings;
         private SerializableProperties properties;
         private SerializableProperties properties;
 
 
+        private GUIToggleField enableHDRField = new GUIToggleField(new LocEdString("Enable HDR"));
+        private GUIToggleField enableLightingField = new GUIToggleField(new LocEdString("Enable lighting"));
+        private GUIToggleField enableShadowsField = new GUIToggleField(new LocEdString("Enable shadows"));
+        private GUIToggleField overlayOnlyField = new GUIToggleField(new LocEdString("Overlay only"));
+
         private GUIToggleField enableAutoExposureField = new GUIToggleField(new LocEdString("Enable auto exposure"));
         private GUIToggleField enableAutoExposureField = new GUIToggleField(new LocEdString("Enable auto exposure"));
         private GUIToggle autoExposureFoldout = new GUIToggle(new LocEdString("Auto exposure"), EditorStyles.Foldout);
         private GUIToggle autoExposureFoldout = new GUIToggle(new LocEdString("Auto exposure"), EditorStyles.Foldout);
         private AutoExposureSettingsGUI autoExposureGUI;
         private AutoExposureSettingsGUI autoExposureGUI;
@@ -378,13 +383,13 @@ namespace BansheeEditor
         private GUILayout whiteBalanceLayout;
         private GUILayout whiteBalanceLayout;
         private GUILayout colorGradingLayout;
         private GUILayout colorGradingLayout;
 
 
-        public Action<PostProcessSettings> OnChanged;
+        public Action<RenderSettings> OnChanged;
         public Action OnConfirmed;
         public Action OnConfirmed;
 
 
         /// <summary>
         /// <summary>
         /// Current value of the settings object.
         /// Current value of the settings object.
         /// </summary>
         /// </summary>
-        public PostProcessSettings Settings
+        public RenderSettings Settings
         {
         {
             get { return settings; }
             get { return settings; }
             set
             set
@@ -399,6 +404,10 @@ namespace BansheeEditor
                 colorGradingGUI.Settings = value.ColorGrading;
                 colorGradingGUI.Settings = value.ColorGrading;
                 gammaField.Value = value.Gamma;
                 gammaField.Value = value.Gamma;
                 exposureScaleField.Value = value.ExposureScale;
                 exposureScaleField.Value = value.ExposureScale;
+                enableHDRField.Value = value.EnableHDR;
+                enableLightingField.Value = value.EnableLighting;
+                enableShadowsField.Value = value.EnableShadows;
+                overlayOnlyField.Value = value.OverlayOnly;
             }
             }
         }
         }
 
 
@@ -409,11 +418,27 @@ namespace BansheeEditor
         /// <param name="layout">Layout to append the GUI elements to.</param>
         /// <param name="layout">Layout to append the GUI elements to.</param>
         /// <param name="properties">A set of properties that are persisted by the parent inspector. Used for saving state.
         /// <param name="properties">A set of properties that are persisted by the parent inspector. Used for saving state.
         ///                          </param>
         ///                          </param>
-        public PostProcessSettingsGUI(PostProcessSettings settings, GUILayout layout, SerializableProperties properties)
+        public RenderSettingsGUI(RenderSettings settings, GUILayout layout, SerializableProperties properties)
         {
         {
             this.settings = settings;
             this.settings = settings;
             this.properties = properties;
             this.properties = properties;
 
 
+            // Enable HDR
+            enableHDRField.OnChanged += x => { this.settings.EnableHDR = x; MarkAsModified(); ConfirmModify(); };
+            layout.AddElement(enableHDRField);
+
+            // Enable lighting
+            enableLightingField.OnChanged += x => { this.settings.EnableLighting = x; MarkAsModified(); ConfirmModify(); };
+            layout.AddElement(enableLightingField);
+
+            // Enable shadows
+            enableShadowsField.OnChanged += x => { this.settings.EnableShadows = x; MarkAsModified(); ConfirmModify(); };
+            layout.AddElement(enableShadowsField);
+
+            // Overlay only
+            overlayOnlyField.OnChanged += x => { this.settings.OverlayOnly = x; MarkAsModified(); ConfirmModify(); };
+            layout.AddElement(overlayOnlyField);
+
             // Auto exposure
             // Auto exposure
             enableAutoExposureField.OnChanged += x => { this.settings.EnableAutoExposure = x; MarkAsModified(); ConfirmModify(); };
             enableAutoExposureField.OnChanged += x => { this.settings.EnableAutoExposure = x; MarkAsModified(); ConfirmModify(); };
             layout.AddElement(enableAutoExposureField);
             layout.AddElement(enableAutoExposureField);

+ 1 - 1
Source/MBansheeEditor/MBansheeEditor.csproj

@@ -46,7 +46,7 @@
     <Compile Include="Inspectors\AudioListenerInspector.cs" />
     <Compile Include="Inspectors\AudioListenerInspector.cs" />
     <Compile Include="Inspectors\AudioSourceInspector.cs" />
     <Compile Include="Inspectors\AudioSourceInspector.cs" />
     <Compile Include="Inspectors\BoneInspector.cs" />
     <Compile Include="Inspectors\BoneInspector.cs" />
-    <Compile Include="Inspectors\PostProcessSettingsInspector.cs" />
+    <Compile Include="Inspectors\RenderSettingsInspector.cs" />
     <Compile Include="Utility\EdAnimationCurve.cs" />
     <Compile Include="Utility\EdAnimationCurve.cs" />
     <Compile Include="Utility\SerializedSceneObject.cs" />
     <Compile Include="Utility\SerializedSceneObject.cs" />
     <Compile Include="Utility\SerializedDiff.cs" />
     <Compile Include="Utility\SerializedDiff.cs" />

+ 1 - 1
Source/MBansheeEditor/Windows/Scene/SceneAxesGUI.cs

@@ -59,7 +59,7 @@ namespace BansheeEditor
             camera.Layers = SceneAxesHandle.LAYER;
             camera.Layers = SceneAxesHandle.LAYER;
             camera.AspectRatio = 1.0f;
             camera.AspectRatio = 1.0f;
             camera.OrthoHeight = 2.0f;
             camera.OrthoHeight = 2.0f;
-            camera.HDR = false;
+            camera.RenderSettings.EnableHDR = false;
 
 
             renderTextureGUI = new GUIRenderTexture(renderTexture, true);
             renderTextureGUI = new GUIRenderTexture(renderTexture, true);
 
 

+ 1 - 1
Source/MBansheeEditor/Windows/Scene/SceneWindow.cs

@@ -826,7 +826,7 @@ namespace BansheeEditor
                     profilerCamera.ClearFlags = ClearFlags.None;
                     profilerCamera.ClearFlags = ClearFlags.None;
                     profilerCamera.Priority = 1;
                     profilerCamera.Priority = 1;
                     profilerCamera.Layers = 0;
                     profilerCamera.Layers = 0;
-                    profilerCamera.HDR = false;
+                    profilerCamera.RenderSettings.EnableHDR = false;
 
 
                     activeProfilerOverlay = profilerSO.AddComponent<ProfilerOverlay>();
                     activeProfilerOverlay = profilerSO.AddComponent<ProfilerOverlay>();
                 }
                 }

+ 5 - 27
Source/MBansheeEngine/Interop/NativeCamera.cs

@@ -125,22 +125,10 @@ namespace BansheeEngine
             set { Internal_SetPriority(mCachedPtr, value); }
             set { Internal_SetPriority(mCachedPtr, value); }
         }
         }
 
 
-        internal bool HDR
+        internal RenderSettings RenderSettings
         {
         {
-            get { return Internal_GetHDR(mCachedPtr); }
-            set { Internal_SetHDR(mCachedPtr, value); }
-        }
-
-        internal bool noLighting
-        {
-            get { return Internal_GetNoLighting(mCachedPtr); }
-            set { Internal_SetNoLighting(mCachedPtr, value); }
-        }
-
-        internal PostProcessSettings PostProcess
-        {
-            get { return Internal_GetPostProcessSettings(mCachedPtr); }
-            set { Internal_SetPostProcessSettings(mCachedPtr, value); }
+            get { return Internal_GetRenderSettings(mCachedPtr); }
+            set { Internal_SetRenderSettings(mCachedPtr, value); }
         }
         }
 
 
         internal ulong layers
         internal ulong layers
@@ -430,19 +418,9 @@ namespace BansheeEngine
         private static extern void Internal_SetPriority(IntPtr instance, int value);
         private static extern void Internal_SetPriority(IntPtr instance, int value);
 
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_GetHDR(IntPtr instance);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetHDR(IntPtr instance, bool value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_GetNoLighting(IntPtr instance);
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetNoLighting(IntPtr instance, bool value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern PostProcessSettings Internal_GetPostProcessSettings(IntPtr instance);
+        private static extern RenderSettings Internal_GetRenderSettings(IntPtr instance);
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetPostProcessSettings(IntPtr instance, PostProcessSettings value);
+        private static extern void Internal_SetRenderSettings(IntPtr instance, RenderSettings value);
 
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern ulong Internal_GetLayers(IntPtr instance);
         private static extern ulong Internal_GetLayers(IntPtr instance);

+ 1 - 1
Source/MBansheeEngine/MBansheeEngine.csproj

@@ -57,7 +57,7 @@
     <Compile Include="Audio\Interop\NativeAudioSource.cs" />
     <Compile Include="Audio\Interop\NativeAudioSource.cs" />
     <Compile Include="GUI\GUICanvas.cs" />
     <Compile Include="GUI\GUICanvas.cs" />
     <Compile Include="GUI\GUIScrollBar.cs" />
     <Compile Include="GUI\GUIScrollBar.cs" />
-    <Compile Include="Rendering\PostProcessSettings.cs" />
+    <Compile Include="Rendering\RenderSettings.cs" />
     <Compile Include="Serialization\ShowInInspector.cs" />
     <Compile Include="Serialization\ShowInInspector.cs" />
     <Compile Include="Serialization\Step.cs" />
     <Compile Include="Serialization\Step.cs" />
     <Compile Include="Utility\AsyncOp.cs" />
     <Compile Include="Utility\AsyncOp.cs" />

+ 5 - 29
Source/MBansheeEngine/Rendering/Camera.cs

@@ -155,36 +155,14 @@ namespace BansheeEngine
             set { native.priority = value; serializableData.priority = value; }
             set { native.priority = value; serializableData.priority = value; }
         }
         }
 
 
-        /// <summary>
-        /// Determines should high dynamic range be enabled. High dynamic range allows light intensity to be more correctly
-        /// recorded when rendering by allowing for a larger range of values. The stored light is then converted into
-        /// visible color range using exposure and a tone mapping operator. Use <see cref="PostProcess"/> to customize
-        /// those operations.
-        /// </summary>
-        public bool HDR
-        {
-            get { return native.HDR; }
-            set { native.HDR = value; serializableData.HDR = value; }
-        }
-
-        /// <summary>
-        /// If enabled no lighting will be applied to scene objects and everything should be rendered using their
-        /// albedo texture.
-        /// </summary>
-        public bool NoLighting
-        {
-            get { return native.noLighting; }
-            set { native.noLighting = value; serializableData.noLighting = value; }
-        }
-
         /// <summary>
         /// <summary>
         /// Allows you to customize various post process operations that will be executed on the image produced by this 
         /// Allows you to customize various post process operations that will be executed on the image produced by this 
         /// camera.
         /// camera.
         /// </summary>
         /// </summary>
-        public PostProcessSettings PostProcess
+        public RenderSettings RenderSettings
         {
         {
-            get { return native.PostProcess; }
-            set { native.PostProcess = value;  serializableData.postProcessSettings = value; }
+            get { return native.RenderSettings; }
+            set { native.RenderSettings = value;  serializableData.renderSettings = value; }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -436,7 +414,6 @@ namespace BansheeEngine
             native.priority = serializableData.priority;
             native.priority = serializableData.priority;
             native.layers = serializableData.layers;
             native.layers = serializableData.layers;
             native.main = serializableData.main;
             native.main = serializableData.main;
-            native.noLighting = serializableData.noLighting;
 
 
             // TODO - Make RenderTexture a resource so I can save/restore it?
             // TODO - Make RenderTexture a resource so I can save/restore it?
         }
         }
@@ -459,7 +436,7 @@ namespace BansheeEngine
         {
         {
             internal SerializableData()
             internal SerializableData()
             {
             {
-                postProcessSettings = PostProcessSettings.CreateDefault();
+                renderSettings = RenderSettings.CreateDefault();
             }
             }
 
 
             public float aspectRatio = 1.333f;
             public float aspectRatio = 1.333f;
@@ -475,8 +452,7 @@ namespace BansheeEngine
             public ClearFlags clearFlags = ClearFlags.Color | ClearFlags.Depth | ClearFlags.Stencil;
             public ClearFlags clearFlags = ClearFlags.Color | ClearFlags.Depth | ClearFlags.Stencil;
             public int priority;
             public int priority;
             public bool HDR = true;
             public bool HDR = true;
-            public bool noLighting;
-            public PostProcessSettings postProcessSettings;
+            public RenderSettings renderSettings;
             public ulong layers = 0xFFFFFFFFFFFFFFFF;
             public ulong layers = 0xFFFFFFFFFFFFFFFF;
             public bool main;
             public bool main;
         }
         }

+ 31 - 6
Source/MBansheeEngine/Rendering/PostProcessSettings.cs → Source/MBansheeEngine/Rendering/RenderSettings.cs

@@ -172,10 +172,10 @@ namespace BansheeEngine
     };
     };
 
 
     /// <summary>
     /// <summary>
-    /// Settings that control the post-process operations.
+    /// Settings that control rendering operations for a single camera.
     /// </summary>
     /// </summary>
     [SerializeObject]
     [SerializeObject]
-    public class PostProcessSettings
+    public class RenderSettings
     {
     {
         /// <summary>
         /// <summary>
         /// Determines should automatic exposure be applied to the HDR image. When turned on the average scene brightness
         /// Determines should automatic exposure be applied to the HDR image. When turned on the average scene brightness
@@ -235,15 +235,40 @@ namespace BansheeEngine
         public float Gamma;
         public float Gamma;
 
 
         /// <summary>
         /// <summary>
-        /// Creates a new instance of post process settings with the optimal default values.
+        /// High dynamic range allows light intensity to be more correctly recorded when rendering by allowing for a larger
+        /// range of values. The stored light is then converted into visible color range using exposure and a tone mapping 
+        /// operator.
         /// </summary>
         /// </summary>
-        /// <returns>New instance of post process settings.</returns>
-        public static PostProcessSettings CreateDefault()
+        public bool EnableHDR;
+
+        /// <summary>
+        /// Determines if scene objects will be lit by lights. If disabled everything will be rendered using their albedo
+        /// texture with no lighting applied.
+        /// </summary>
+        public bool EnableLighting;
+
+        /// <summary>
+        /// Determines if shadows cast by lights should be rendered. Only relevant if lighting is turned on.
+        /// </summary>
+        public bool EnableShadows;
+
+        /// <summary>
+        /// Signals the renderer to only render overlays (like GUI), and not scene objects. Such rendering doesn't require
+        /// depth buffer or multi-sampled render targets and will not render any scene objects. This can improve performance
+        /// and memory usage for overlay-only views. 
+        /// </summary>
+        public bool OverlayOnly;
+
+        /// <summary>
+        /// Creates a new instance of render settings with the optimal default values.
+        /// </summary>
+        /// <returns>New instance of render settings.</returns>
+        public static RenderSettings CreateDefault()
         {
         {
             return Internal_CreateDefault();
             return Internal_CreateDefault();
         }
         }
 
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern PostProcessSettings Internal_CreateDefault();
+        private static extern RenderSettings Internal_CreateDefault();
     }
     }
 }
 }

+ 4 - 2
Source/RenderBeast/CMakeSources.cmake

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

+ 39 - 106
Source/RenderBeast/Include/BsImageBasedLighting.h

@@ -5,9 +5,11 @@
 #include "BsRenderBeastPrerequisites.h"
 #include "BsRenderBeastPrerequisites.h"
 #include "BsRendererMaterial.h"
 #include "BsRendererMaterial.h"
 #include "BsParamBlocks.h"
 #include "BsParamBlocks.h"
+#include "BsLightRendering.h"
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
+	struct SkyInfo;
 	struct SceneInfo;
 	struct SceneInfo;
 	class RendererViewGroup;
 	class RendererViewGroup;
 
 
@@ -93,7 +95,7 @@ namespace bs { namespace ct
 	struct ImageBasedLightingParams
 	struct ImageBasedLightingParams
 	{
 	{
 		/** 
 		/** 
-		 * Initializes the parameters from the provided @p params object. 
+		 * Initializes the parameters from the provided parameters. 
 		 *
 		 *
 		 * @param[in]	paramsSet	GPU parameters object to look for the parameters in.
 		 * @param[in]	paramsSet	GPU parameters object to look for the parameters in.
 		 * @param[in]	programType	Type of the GPU program to look up the parameters for.
 		 * @param[in]	programType	Type of the GPU program to look up the parameters for.
@@ -103,12 +105,9 @@ namespace bs { namespace ct
 		void populate(const SPtr<GpuParamsSet>& paramsSet, GpuProgramType programType, bool optional, bool gridIndices);
 		void populate(const SPtr<GpuParamsSet>& paramsSet, GpuProgramType programType, bool optional, bool gridIndices);
 
 
 		GpuParamTexture skyReflectionsTexParam;
 		GpuParamTexture skyReflectionsTexParam;
-		GpuParamSampState skyReflectionsSampParam;
-
 		GpuParamTexture skyIrradianceTexParam;
 		GpuParamTexture skyIrradianceTexParam;
 
 
 		GpuParamTexture reflectionProbeCubemapsTexParam;
 		GpuParamTexture reflectionProbeCubemapsTexParam;
-		GpuParamSampState reflectionProbeCubemapsSampParam;
 
 
 		GpuParamTexture preintegratedEnvBRDFParam;
 		GpuParamTexture preintegratedEnvBRDFParam;
 		GpuParamBuffer reflectionProbesParam;
 		GpuParamBuffer reflectionProbesParam;
@@ -117,45 +116,45 @@ namespace bs { namespace ct
 		UINT32 reflProbeParamsBindingIdx;
 		UINT32 reflProbeParamsBindingIdx;
 	};
 	};
 
 
-	/** Functionality common to all versions of TiledDeferredImageBasedLightingMat<T>. */
-	class TiledDeferredImageBasedLighting
+	/** Parameter buffer containing information about reflection probes. */
+	struct ReflProbeParamBuffer
 	{
 	{
-	public:
-		TiledDeferredImageBasedLighting(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet, 
-			UINT32 sampleCount);
+		ReflProbeParamBuffer();
 
 
-		/** Binds the material for rendering, sets up parameters and executes it. */
-		void execute(const SPtr<RenderTargets>& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera,
-					 const SPtr<Texture>& preintegratedGF);
+		/** Updates the parameter buffer contents with require refl. probe data. */
+		void populate(const SkyInfo& sky, const VisibleReflProbeData& probeData, 
+			const SPtr<Texture>& reflectionCubemaps, bool capturingReflections);
 
 
-		/** Binds all the active reflection probes. */
-		void setReflectionProbes(const VisibleReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps, 
-			bool capturingReflections);
+		SPtr<GpuParamBlockBuffer> buffer;
+	};
 
 
-		/** Binds the sky reflection & irradiance textures. Set textures to null if not available. */
-		void setSky(const SPtr<Texture>& skyReflections, const SPtr<Texture>& skyIrradiance, float brightness);
+	/** Shader that performs a lighting pass over data stored in the Gbuffer. */
+	class TiledDeferredImageBasedLightingMat : public RendererMaterial<TiledDeferredImageBasedLightingMat>
+	{
+		RMAT_DEF("TiledDeferredImageBasedLighting.bsl");
 
 
-		/** Returns a param buffer containing information required to evaluate reflection probe data. */
-		SPtr<GpuParamBlockBuffer> getReflectionsParamBuffer() const { return mReflectionsParamBuffer; }
+	public:
+		/** Container for parameters to be passed to the execute() method. */
+		struct Inputs
+		{
+			GBufferInput gbuffer;
+			SPtr<Texture> lightAccumulation;
+			SPtr<Texture> sceneColorTex;
+			SPtr<GpuBuffer> sceneColorBuffer;
+			SPtr<Texture> preIntegratedGF;
+		};
+
+		TiledDeferredImageBasedLightingMat();
 
 
-		/** Returns a sampler state object that should be used for evaluating reflection maps. */
-		SPtr<SamplerState> getReflectionsSamplerState() const { return mReflectionSamplerState; }
+		/** Binds the material for rendering, sets up parameters and executes it. */
+		void execute(const RendererView& view, const SceneInfo& sceneInfo, const VisibleReflProbeData& probeData, 
+			const Inputs& inputs);
 
 
-		/**
-		 * Generates 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> generatePreintegratedEnvBRDF();
+		/** Returns the material variation matching the provided parameters. */
+		static TiledDeferredImageBasedLightingMat* getVariation(UINT32 msaaCount);
 
 
-		static const UINT32 TILE_SIZE;
 	private:
 	private:
 		UINT32 mSampleCount;
 		UINT32 mSampleCount;
-		SPtr<Material> mMaterial;
-		SPtr<GpuParamsSet> mParamsSet;
 
 
 		GpuParamTexture mGBufferA;
 		GpuParamTexture mGBufferA;
 		GpuParamTexture mGBufferB;
 		GpuParamTexture mGBufferB;
@@ -170,81 +169,15 @@ namespace bs { namespace ct
 		GpuParamBuffer mOutputBufferParam;
 		GpuParamBuffer mOutputBufferParam;
 
 
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
-		SPtr<GpuParamBlockBuffer> mReflectionsParamBuffer;
-		SPtr<SamplerState> mReflectionSamplerState;
-	};
-
-	/** Interface implemented by all versions of TTiledDeferredImageBasedLightingMat<T>. */
-	class ITiledDeferredImageBasedLightingMat
-	{
-	public:
-		virtual ~ITiledDeferredImageBasedLightingMat() {}
-
-		/** @copydoc TiledDeferredImageBasedLighting::execute() */
-		virtual void execute(const SPtr<RenderTargets>& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera,
-			const SPtr<Texture>& preintegratedGF) = 0;
-
-		/** @copydoc TiledDeferredImageBasedLighting::setReflectionProbes() */
-		virtual void setReflectionProbes(const VisibleReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps,
-			bool capturingReflections) = 0;
-
-		/** @copydoc TiledDeferredImageBasedLighting::setSky() */
-		virtual void setSky(const SPtr<Texture>& skyReflections, const SPtr<Texture>& skyIrradiance, float brightness) = 0;
-
-		/** @copydoc TiledDeferredImageBasedLighting::getReflectionsParamBuffer() */
-		virtual SPtr<GpuParamBlockBuffer> getReflectionsParamBuffer() const = 0;
-
-		/** @copydoc TiledDeferredImageBasedLighting::getReflectionsSamplerState() */
-		virtual SPtr<SamplerState> getReflectionsSamplerState() const = 0;
-	};
+		ReflProbeParamBuffer mReflProbeParamBuffer;
 
 
-	/** Shader that performs a lighting pass over data stored in the Gbuffer. */
-	template<int MSAA_COUNT>
-	class TTiledDeferredImageBasedLightingMat : public ITiledDeferredImageBasedLightingMat, 
-		public RendererMaterial<TTiledDeferredImageBasedLightingMat<MSAA_COUNT>>
-	{
-		RMAT_DEF("TiledDeferredImageBasedLighting.bsl");
-
-	public:
-		TTiledDeferredImageBasedLightingMat();
-
-		/** @copydoc ITiledDeferredImageBasedLightingMat::execute() */
-		void execute(const SPtr<RenderTargets>& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera,
-			const SPtr<Texture>& preintegratedGF) override;
-
-		/** @copydoc ITiledDeferredImageBasedLightingMat::setReflectionProbes() */
-		void setReflectionProbes(const VisibleReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps, 
-			bool capturingReflections) override;
-
-		/** @copydoc ITiledDeferredImageBasedLightingMat::setSky() */
-		void setSky(const SPtr<Texture>& skyReflections, const SPtr<Texture>& skyIrradiance, float brightness) override;
-
-		/** @copydoc ITiledDeferredImageBasedLightingMat::getReflectionsParamBuffer() */
-		SPtr<GpuParamBlockBuffer> getReflectionsParamBuffer() const override;
-
-		/** @copydoc ITiledDeferredImageBasedLightingMat::getReflectionsSamplerState() */
-		SPtr<SamplerState> getReflectionsSamplerState() const override;
-	private:
-		TiledDeferredImageBasedLighting mInternal;
-	};
-
-	/** Contains instances for all types of tile deferred image based lighting materials. */
-	class TiledDeferredImageBasedLightingMaterials
-	{
-	public:
-		TiledDeferredImageBasedLightingMaterials();
-		~TiledDeferredImageBasedLightingMaterials();
-
-		/**
-		 * Returns a version of the tile-deferred image based lighting material that matches the parameters.
-		 *
-		 * @param[in]   msaa						Number of samples per pixel.
-		 */
-		ITiledDeferredImageBasedLightingMat* get(UINT32 msaa);
+		static const UINT32 TILE_SIZE;
 
 
-	private:
-		ITiledDeferredImageBasedLightingMat* mInstances[4];
+		static ShaderVariation VAR_1MSAA;
+		static ShaderVariation VAR_2MSAA;
+		static ShaderVariation VAR_4MSAA;
+		static ShaderVariation VAR_8MSAA;
 	};
 	};
 
 
 	/** @} */
 	/** @} */
-}}
+}}

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

@@ -152,9 +152,6 @@ namespace bs { namespace ct
 			SPtr<GpuParamBlockBuffer>& gridParams) const;
 			SPtr<GpuParamBlockBuffer>& gridParams) const;
 
 
 	private:
 	private:
-		LightGridLLCreationMat mLLCreationMat;
-		LightGridLLReductionMat mLLReductionMat;
-
 		SPtr<GpuParamBlockBuffer> mGridParamBuffer;
 		SPtr<GpuParamBlockBuffer> mGridParamBuffer;
 	};
 	};
 
 

+ 24 - 65
Source/RenderBeast/Include/BsLightRendering.h

@@ -56,6 +56,15 @@ namespace bs { namespace ct
 		Light* internal;
 		Light* internal;
 	};
 	};
 
 
+	/** Container for all GBuffer textures. */
+	struct GBufferInput
+	{
+		SPtr<Texture> albedo;
+		SPtr<Texture> normals;
+		SPtr<Texture> roughMetal;
+		SPtr<Texture> depth;
+	};
+
 	/** Allows you to easily bind GBuffer textures to some material. */
 	/** Allows you to easily bind GBuffer textures to some material. */
 	class GBufferParams
 	class GBufferParams
 	{
 	{
@@ -63,8 +72,7 @@ namespace bs { namespace ct
 		GBufferParams(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet);
 		GBufferParams(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet);
 
 
 		/** Binds the GBuffer textures to the pipeline. */
 		/** Binds the GBuffer textures to the pipeline. */
-		void bind(const RenderTargets& renderTargets);
-
+		void bind(const GBufferInput& gbuffer);
 	private:
 	private:
 		SPtr<Material> mMaterial;
 		SPtr<Material> mMaterial;
 		SPtr<GpuParamsSet> mParamsSet;
 		SPtr<GpuParamsSet> mParamsSet;
@@ -134,86 +142,37 @@ namespace bs { namespace ct
 
 
 	extern TiledLightingParamDef gTiledLightingParamDef;
 	extern TiledLightingParamDef gTiledLightingParamDef;
 
 
-	/** Functionality common to all versions of TiledDeferredLightingMat<T>. */
-	class TiledDeferredLighting
+	/** Shader that performs a lighting pass over data stored in the Gbuffer. */
+	class TiledDeferredLightingMat : public RendererMaterial<TiledDeferredLightingMat>
 	{
 	{
+		RMAT_DEF("TiledDeferredLighting.bsl");
+
 	public:
 	public:
-		TiledDeferredLighting(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet, UINT32 sampleCount);
+		TiledDeferredLightingMat();
 
 
 		/** Binds the material for rendering, sets up parameters and executes it. */
 		/** Binds the material for rendering, sets up parameters and executes it. */
-		void execute(const SPtr<RenderTargets>& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera, bool noLighting,
-			bool noShadows);
+		void execute(const RendererView& view, const VisibleLightData& lightData, const GBufferInput& gbuffer,
+			const SPtr<Texture>& lightAccumTex, const SPtr<GpuBuffer>& lightAccumBuffer);
 
 
-		/** Binds all the active lights. */
-		void setLights(const VisibleLightData& lightData);
+		/** Returns the material variation matching the provided parameters. */
+		static TiledDeferredLightingMat* getVariation(UINT32 msaaCount);
 
 
-		static const UINT32 TILE_SIZE;
 	private:
 	private:
 		UINT32 mSampleCount;
 		UINT32 mSampleCount;
-		SPtr<Material> mMaterial;
-		SPtr<GpuParamsSet> mParamsSet;
-
 		GBufferParams mGBufferParams;
 		GBufferParams mGBufferParams;
 
 
-		Vector4I mUnshadowedLightCounts;
-		Vector4I mLightCounts;
-		Vector2I mLightStrides;
 		GpuParamBuffer mLightBufferParam;
 		GpuParamBuffer mLightBufferParam;
 		GpuParamLoadStoreTexture mOutputTextureParam;
 		GpuParamLoadStoreTexture mOutputTextureParam;
 		GpuParamBuffer mOutputBufferParam;
 		GpuParamBuffer mOutputBufferParam;
 
 
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
-	};
-
-	/** Interface implemented by all versions of TTiledDeferredLightingMat<T>. */
-	class ITiledDeferredLightingMat
-	{
-	public:
-		virtual ~ITiledDeferredLightingMat() {}
-
-		/** @copydoc TiledDeferredLighting::execute() */
-		virtual void execute(const SPtr<RenderTargets>& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera,
-			bool noLighting, bool noShadows) = 0;
-
-		/** @copydoc TiledDeferredLighting::setLights() */
-		virtual void setLights(const VisibleLightData& lightData) = 0;
-	};
-
-	/** Shader that performs a lighting pass over data stored in the Gbuffer. */
-	template<int MSAA_COUNT>
-	class TTiledDeferredLightingMat : public ITiledDeferredLightingMat, public RendererMaterial<TTiledDeferredLightingMat<MSAA_COUNT>>
-	{
-		RMAT_DEF("TiledDeferredLighting.bsl");
 
 
-	public:
-		TTiledDeferredLightingMat();
-
-		/** @copydoc ITiledDeferredLightingMat::execute() */
-		void execute(const SPtr<RenderTargets>& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera,
-			bool noLighting, bool noShaodws) override;
-
-		/** @copydoc ITiledDeferredLightingMat::setLights() */
-		void setLights(const VisibleLightData& lightData) override;
-	private:
-		TiledDeferredLighting mInternal;
-	};
-
-	/** Contains instances for all types of tile deferred lighting materials. */
-	class TiledDeferredLightingMaterials
-	{
-	public:
-		TiledDeferredLightingMaterials();
-		~TiledDeferredLightingMaterials();
-
-		/**
-		 * Returns a version of the tile-deferred lighting material that matches the parameters.
-		 * 
-		 * @param[in]   msaa					Number of samples per pixel.
-		 */
-		ITiledDeferredLightingMat* get(UINT32 msaa);
+		static const UINT32 TILE_SIZE;
 
 
-	private:
-		ITiledDeferredLightingMat* mInstances[4];
+		static ShaderVariation VAR_1MSAA;
+		static ShaderVariation VAR_2MSAA;
+		static ShaderVariation VAR_4MSAA;
+		static ShaderVariation VAR_8MSAA;
 	};
 	};
 
 
 	BS_PARAM_BLOCK_BEGIN(FlatFramebufferToTextureParamDef)
 	BS_PARAM_BLOCK_BEGIN(FlatFramebufferToTextureParamDef)

+ 147 - 332
Source/RenderBeast/Include/BsPostProcessing.h

@@ -6,8 +6,8 @@
 #include "BsRendererMaterial.h"
 #include "BsRendererMaterial.h"
 #include "BsParamBlocks.h"
 #include "BsParamBlocks.h"
 #include "BsGpuResourcePool.h"
 #include "BsGpuResourcePool.h"
-#include "BsStandardPostProcessSettings.h"
 #include "BsLightRendering.h"
 #include "BsLightRendering.h"
+#include "BsRenderSettings.h"
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
@@ -17,35 +17,14 @@ namespace bs { namespace ct
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
-	/** Contains per-camera data used by post process effects. */
-	struct PostProcessInfo
-	{
-		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)
 	BS_PARAM_BLOCK_BEGIN(DownsampleParamDef)
 		BS_PARAM_BLOCK_ENTRY_ARRAY(Vector2, gOffsets, 4)
 		BS_PARAM_BLOCK_ENTRY_ARRAY(Vector2, gOffsets, 4)
 	BS_PARAM_BLOCK_END
 	BS_PARAM_BLOCK_END
 
 
 	extern DownsampleParamDef gDownsampleParamDef;
 	extern DownsampleParamDef gDownsampleParamDef;
 
 
-	/** 
-	 * Shader that downsamples a texture to half its size. 
-	 * 
-	 * @tparam	Quality		0 for a 2x2 filtered sample, 1 or higher for 4x4 filtered sample
-	 * @tparam	MSAA		True if the input texture is multi-sampled. Only first sample will be used, the rest will be
-	 *						discarded.
-	 */
-	template<int Quality, bool MSAA>
-	class DownsampleMat : public RendererMaterial<DownsampleMat<Quality, MSAA>>
+	/** Shader that downsamples a texture to half its size. */
+	class DownsampleMat : public RendererMaterial<DownsampleMat>
 	{
 	{
 		RMAT_DEF("PPDownsample.bsl");
 		RMAT_DEF("PPDownsample.bsl");
 
 
@@ -53,48 +32,22 @@ namespace bs { namespace ct
 		DownsampleMat();
 		DownsampleMat();
 
 
 		/** Renders the post-process effect with the provided parameters. */
 		/** Renders the post-process effect with the provided parameters. */
-		void execute(const SPtr<Texture>& target, PostProcessInfo& ppInfo);
+		void execute(const SPtr<Texture>& input, const SPtr<RenderTarget>& output);
 
 
-		/** Releases the output render target. */
-		void release(PostProcessInfo& ppInfo);
+		/** Returns the texture descriptor that can be used for initializing the output render target. */
+		static POOLED_RENDER_TEXTURE_DESC getOutputDesc(const SPtr<Texture>& target);
+
+		/** Returns the downsample material variation matching the provided parameters. */
+		static DownsampleMat* getVariation(UINT32 quality, bool msaa);
 
 
-		/** Returns the render texture where the output will be written. */
-		SPtr<RenderTexture> getOutput() const { return mOutput; }
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		GpuParamTexture mInputTexture;
 		GpuParamTexture mInputTexture;
 
 
-		POOLED_RENDER_TEXTURE_DESC mOutputDesc;
-		SPtr<RenderTexture> mOutput;
-	};
-
-	/** Contains all variations of the DownsampleMat material. */
-	class DownsampleMaterials
-	{
-	public:
-		/**
-		 * Executes the appropriate downsampling material.
-		 * 
-		 * @param[in]	quality		Determines quality of the downsampling filer. Specify 0 to use a 2x2 filter block, and
-		 *							1 or higher for a 4x4 filter block.
-		 * @param[in]	msaa		If true the input texture is assumed to have multiple samples. The downsampling shader
-		 *							will discard all samples except the first one.
-		 * @param[in]	target		Texture to downsample.
-		 * @param[in]	ppInfo		Information about the current post processing pass.
-		 */
-		void execute(UINT32 quality, bool msaa, const SPtr<Texture>& target, PostProcessInfo& ppInfo);
-
-		/**
-		 * Releases any resources allocated by execute(). Must be called using the same @p quality and @p msaa parameters as
-		 * the corresponding execute() call. @see execute().
-		 */
-		void release(UINT32 quality, bool msaa, PostProcessInfo& ppInfo);
-	private:
-		DownsampleMat<0, false> m0_NoMSAA;
-		DownsampleMat<0, true> m0_MSAA;
-		
-		DownsampleMat<1, false> m1_NoMSAA;
-		DownsampleMat<1, true> m1_MSAA;
+		static ShaderVariation VAR_LowQuality_NoMSAA;
+		static ShaderVariation VAR_LowQuality_MSAA;
+		static ShaderVariation VAR_HighQuality_NoMSAA;
+		static ShaderVariation VAR_HighQuality_MSAA;
 	};
 	};
 
 
 	BS_PARAM_BLOCK_BEGIN(EyeAdaptHistogramParamDef)
 	BS_PARAM_BLOCK_BEGIN(EyeAdaptHistogramParamDef)
@@ -114,22 +67,19 @@ namespace bs { namespace ct
 		EyeAdaptHistogramMat();
 		EyeAdaptHistogramMat();
 
 
 		/** Executes the post-process effect with the provided parameters. */
 		/** Executes the post-process effect with the provided parameters. */
-		void execute(PostProcessInfo& ppInfo);
+		void execute(const SPtr<Texture>& input, const SPtr<Texture>& output, const AutoExposureSettings& settings);
 
 
-		/** Releases the output render target. */
-		void release(PostProcessInfo& ppInfo);
+		/** Returns the texture descriptor that can be used for initializing the output render target. */
+		static POOLED_RENDER_TEXTURE_DESC getOutputDesc(const SPtr<Texture>& target);
 
 
-		/** Returns the render texture where the output was written. */
-		SPtr<RenderTexture> getOutput() const { return mOutput; }
-
-		/** Calculates the number of thread groups that need to execute to cover the provided render target. */
-		static Vector2I getThreadGroupCount(const SPtr<RenderTexture>& target);
+		/** Calculates the number of thread groups that need to execute to cover the provided texture. */
+		static Vector2I getThreadGroupCount(const SPtr<Texture>& target);
 
 
 		/** 
 		/** 
 		 * Returns a vector containing scale and offset (in that order) that will be applied to luminance values
 		 * Returns a vector containing scale and offset (in that order) that will be applied to luminance values
 		 * to determine their position in the histogram. 
 		 * to determine their position in the histogram. 
 		 */
 		 */
-		static Vector2 getHistogramScaleOffset(const PostProcessInfo& ppInfo);
+		static Vector2 getHistogramScaleOffset(const AutoExposureSettings& settings);
 
 
 		static const UINT32 THREAD_GROUP_SIZE_X = 8;
 		static const UINT32 THREAD_GROUP_SIZE_X = 8;
 		static const UINT32 THREAD_GROUP_SIZE_Y = 8;
 		static const UINT32 THREAD_GROUP_SIZE_Y = 8;
@@ -140,9 +90,6 @@ namespace bs { namespace ct
 		GpuParamTexture mSceneColor;
 		GpuParamTexture mSceneColor;
 		GpuParamLoadStoreTexture mOutputTex;
 		GpuParamLoadStoreTexture mOutputTex;
 
 
-		POOLED_RENDER_TEXTURE_DESC mOutputDesc;
-		SPtr<RenderTexture> mOutput;
-
 		static const UINT32 LOOP_COUNT_X = 8;
 		static const UINT32 LOOP_COUNT_X = 8;
 		static const UINT32 LOOP_COUNT_Y = 8;
 		static const UINT32 LOOP_COUNT_Y = 8;
 	};
 	};
@@ -162,21 +109,16 @@ namespace bs { namespace ct
 		EyeAdaptHistogramReduceMat();
 		EyeAdaptHistogramReduceMat();
 
 
 		/** Executes the post-process effect with the provided parameters. */
 		/** Executes the post-process effect with the provided parameters. */
-		void execute(PostProcessInfo& ppInfo);
+		void execute(const SPtr<Texture>& sceneColor, const SPtr<Texture>& histogram, const SPtr<Texture>& prevFrame,
+			const SPtr<RenderTarget>& output);
 
 
-		/** Releases the output render target. */
-		void release(PostProcessInfo& ppInfo);
-
-		/** Returns the render texture where the output was written. */
-		SPtr<RenderTexture> getOutput() const { return mOutput; }
+		/** Returns the texture descriptor that can be used for initializing the output render target. */
+		static POOLED_RENDER_TEXTURE_DESC getOutputDesc();
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 
 
 		GpuParamTexture mHistogramTex;
 		GpuParamTexture mHistogramTex;
 		GpuParamTexture mEyeAdaptationTex;
 		GpuParamTexture mEyeAdaptationTex;
-
-		POOLED_RENDER_TEXTURE_DESC mOutputDesc;
-		SPtr<RenderTexture> mOutput;
 	};
 	};
 
 
 	BS_PARAM_BLOCK_BEGIN(EyeAdaptationParamDef)
 	BS_PARAM_BLOCK_BEGIN(EyeAdaptationParamDef)
@@ -194,7 +136,11 @@ namespace bs { namespace ct
 		EyeAdaptationMat();
 		EyeAdaptationMat();
 
 
 		/** Executes the post-process effect with the provided parameters. */
 		/** Executes the post-process effect with the provided parameters. */
-		void execute(PostProcessInfo& ppInfo, float frameDelta);
+		void execute(const SPtr<Texture>& reducedHistogram, const SPtr<RenderTarget>& output, float frameDelta, 
+			const AutoExposureSettings& settings, float exposureScale);
+
+		/** Returns the texture descriptor that can be used for initializing the output render target. */
+		static POOLED_RENDER_TEXTURE_DESC getOutputDesc();
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		GpuParamTexture mReducedHistogramTex;
 		GpuParamTexture mReducedHistogramTex;
@@ -231,10 +177,10 @@ namespace bs { namespace ct
 		CreateTonemapLUTMat();
 		CreateTonemapLUTMat();
 
 
 		/** Executes the post-process effect with the provided parameters. */
 		/** Executes the post-process effect with the provided parameters. */
-		void execute(PostProcessInfo& ppInfo);
+		void execute(const SPtr<Texture>& output, const RenderSettings& settings);
 
 
-		/** Releases the output render target. */
-		void release(PostProcessInfo& ppInfo);
+		/** Returns the texture descriptor that can be used for initializing the output render target. */
+		static POOLED_RENDER_TEXTURE_DESC getOutputDesc();
 
 
 		/** Size of the 3D color lookup table. */
 		/** Size of the 3D color lookup table. */
 		static const UINT32 LUT_SIZE = 32;
 		static const UINT32 LUT_SIZE = 32;
@@ -254,8 +200,7 @@ namespace bs { namespace ct
 	extern TonemappingParamDef gTonemappingParamDef;
 	extern TonemappingParamDef gTonemappingParamDef;
 
 
 	/** Shader that applies tonemapping and converts a HDR image into a LDR image. */
 	/** Shader that applies tonemapping and converts a HDR image into a LDR image. */
-	template<bool GammaOnly, bool AutoExposure, bool MSAA>
-	class TonemappingMat : public RendererMaterial<TonemappingMat<GammaOnly, AutoExposure, MSAA>>
+	class TonemappingMat : public RendererMaterial<TonemappingMat>
 	{
 	{
 		RMAT_DEF("PPTonemapping.bsl");
 		RMAT_DEF("PPTonemapping.bsl");
 
 
@@ -263,8 +208,11 @@ namespace bs { namespace ct
 		TonemappingMat();
 		TonemappingMat();
 
 
 		/** Executes the post-process effect with the provided parameters. */
 		/** Executes the post-process effect with the provided parameters. */
-		void execute(const SPtr<Texture>& sceneColor, const SPtr<RenderTarget>& outputRT, const Rect2& outputRect,
-			PostProcessInfo& ppInfo);
+		void execute(const SPtr<Texture>& sceneColor, const SPtr<Texture>& eyeAdaptation, const SPtr<Texture>& colorLUT,
+			const SPtr<RenderTarget>& output, const RenderSettings& settings);
+
+		/** Returns the material variation matching the provided parameters. */
+		static TonemappingMat* getVariation(bool gammaOnly, bool autoExposure, bool MSAA);
 
 
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
@@ -272,38 +220,15 @@ namespace bs { namespace ct
 		GpuParamTexture mInputTex;
 		GpuParamTexture mInputTex;
 		GpuParamTexture mColorLUT;
 		GpuParamTexture mColorLUT;
 		GpuParamTexture mEyeAdaptationTex;
 		GpuParamTexture mEyeAdaptationTex;
-	};
-
-	/** Container for all variations of the TonemappingMat material. */
-	class TonemappingMaterials
-	{
-	public:
-		/** 
-		 * Finds a valid tonemapping material according to the requested parameters and executes it. 
-		 *
-		 * @param[in]	gammaOnly		If true no color correction, white balancing or curve tonemapping will take place. 
-		 *								Instead the image will only be scaled by the exposure value and gamma corrected.
-		 * @param[in]	autoExposure	If true, the automatically calculated eye-adapatation exposure value will be used
-		 *								as the exposure scale. If false, the user provided value will be used instead.
-		 * @param[in]	MSAA			True if the input texture has multiple samples. This will ensure that the samples
-		 *								are resolved properly into a non-MSAA output texture.
-		 * @param[in]	sceneColor		Texture to apply tonemapping to.
-		 * @param[in]	outputRT		Render target to write the results to.
-		 * @param[in]	outputRect		Normalized rectangle determining to which part of the output texture to write to.
-		 * @param[in]	ppInfo			Information about the current post processing pass.
-		 */
-		void execute(bool gammaOnly, bool autoExposure, bool MSAA, const SPtr<Texture>& sceneColor,
-			const SPtr<RenderTarget>& outputRT, const Rect2& outputRect, PostProcessInfo& ppInfo);
 
 
-	private:
-		TonemappingMat<false, false, false> mFFF;
-		TonemappingMat<false, false, true> mFFT;
-		TonemappingMat<false, true, false> mFTF;
-		TonemappingMat<false, true, true> mFTT;
-		TonemappingMat<true, false, false> mTFF;
-		TonemappingMat<true, false, true> mTFT;
-		TonemappingMat<true, true, false> mTTF;
-		TonemappingMat<true, true, true> mTTT;
+		static ShaderVariation VAR_Gamma_AutoExposure_MSAA;
+		static ShaderVariation VAR_Gamma_AutoExposure_NoMSAA;
+		static ShaderVariation VAR_Gamma_NoAutoExposure_MSAA;
+		static ShaderVariation VAR_Gamma_NoAutoExposure_NoMSAA;
+		static ShaderVariation VAR_NoGamma_AutoExposure_MSAA;
+		static ShaderVariation VAR_NoGamma_AutoExposure_NoMSAA;
+		static ShaderVariation VAR_NoGamma_NoAutoExposure_MSAA;
+		static ShaderVariation VAR_NoGamma_NoAutoExposure_NoMSAA;
 	};
 	};
 
 
 	const int MAX_BLUR_SAMPLES = 128;
 	const int MAX_BLUR_SAMPLES = 128;
@@ -362,11 +287,18 @@ namespace bs { namespace ct
 
 
 	extern GaussianDOFParamDef sGaussianDOFParamDef;
 	extern GaussianDOFParamDef sGaussianDOFParamDef;
 
 
-	/** Common interface for all variations of GaussianDOFSeparateMat. */
-	class IGaussianDOFSeparateMat
+	/** 
+	 * Shader that masks pixels from the input color texture into one or two output textures. The masking is done by
+	 * determining if the pixel falls into near or far unfocused plane, as determined by depth-of-field parameters. User
+	 * can pick whether to output pixels just on the near plane, just on the far plane, or both.
+	 *
+	 */
+	class GaussianDOFSeparateMat : public RendererMaterial<GaussianDOFSeparateMat>
 	{
 	{
+		RMAT_DEF("PPGaussianDOFSeparate.bsl");
+
 	public:
 	public:
-		virtual ~IGaussianDOFSeparateMat() { }
+		GaussianDOFSeparateMat();
 
 
 		/** 
 		/** 
 		 * Renders the post-process effect with the provided parameters. 
 		 * Renders the post-process effect with the provided parameters. 
@@ -376,48 +308,29 @@ namespace bs { namespace ct
 		 * @param[in]	view		View through which the depth of field effect is viewed.
 		 * @param[in]	view		View through which the depth of field effect is viewed.
 		 * @param[in]	settings	Settings used to control depth of field rendering. 
 		 * @param[in]	settings	Settings used to control depth of field rendering. 
 		 */
 		 */
-		virtual void execute(const SPtr<Texture>& color, const SPtr<Texture>& depth, const RendererView& view, 
-			const DepthOfFieldSettings& settings) = 0;
+		void execute(const SPtr<Texture>& color, const SPtr<Texture>& depth, const RendererView& view, 
+			const DepthOfFieldSettings& settings);
 
 
 		/**
 		/**
 		 * Returns the texture generated after the shader was executed. Only valid to call this in-between calls to
 		 * Returns the texture generated after the shader was executed. Only valid to call this in-between calls to
 		 * execute() & release(), with @p idx value 0 or 1.
 		 * execute() & release(), with @p idx value 0 or 1.
 		 */
 		 */
-		virtual SPtr<PooledRenderTexture> getOutput(UINT32 idx) = 0;
+		SPtr<PooledRenderTexture> getOutput(UINT32 idx);
 
 
 		/**
 		/**
 		 * Releases the interally allocated output render textures. Must be called after each call to execute(), when the 
 		 * Releases the interally allocated output render textures. Must be called after each call to execute(), when the 
 		 * caller is done using the textures.
 		 * caller is done using the textures.
 		 */
 		 */
-		virtual void release() = 0;
-	};
-
-	/** 
-	 * Shader that masks pixels from the input color texture into one or two output textures. The masking is done by
-	 * determining if the pixel falls into near or far unfocused plane, as determined by depth-of-field parameters. User
-	 * can pick whether to output pixels just on the near plane, just on the far plane, or both.
-	 *
-	 * @tparam	Near	If true, near plane pixels are output to the first render target.
-	 * @tparam	Far		If true, far plane pixels are output to the first render target. If @p Near is also enabled, the
-	 *					pixels are output to the second render target instead.
-	 */
-	template<bool Near, bool Far>
-	class GaussianDOFSeparateMat : public IGaussianDOFSeparateMat, public RendererMaterial<GaussianDOFSeparateMat<Near, Far>>
-	{
-		RMAT_DEF("PPGaussianDOFSeparate.bsl");
-
-	public:
-		GaussianDOFSeparateMat();
+		void release();
 
 
-		/** @copydoc IGaussianDOFSeparateMat::execute() */
-		void execute(const SPtr<Texture>& color, const SPtr<Texture>& depth, const RendererView& view, 
-			const DepthOfFieldSettings& settings) override;
-
-		/** @copydoc IGaussianDOFSeparateMat::getOutput() */
-		SPtr<PooledRenderTexture> getOutput(UINT32 idx) override;
-
-		/** @copydoc IGaussianDOFSeparateMat::release() */
-		void release() override;
+		/** 
+		 * Returns the material variation matching the provided parameters.
+		 *
+		 * @param	near	If true, near plane pixels are output to the first render target.
+		 * @param	far		If true, far plane pixels are output to the first render target. If @p near is also enabled, the
+		 *					pixels are output to the second render target instead.
+		 */
+		static GaussianDOFSeparateMat* getVariation(bool near, bool far);
 
 
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
@@ -426,13 +339,22 @@ namespace bs { namespace ct
 
 
 		SPtr<PooledRenderTexture> mOutput0;
 		SPtr<PooledRenderTexture> mOutput0;
 		SPtr<PooledRenderTexture> mOutput1;
 		SPtr<PooledRenderTexture> mOutput1;
+
+		static ShaderVariation VAR_Near_Far;
+		static ShaderVariation VAR_NoNear_Far;
+		static ShaderVariation VAR_Near_NoFar;
 	};
 	};
 
 
-	/** Common interface for all variations of GaussianDOFCombineMat. */
-	class IGaussianDOFCombineMat
+	/** 
+	 * Shader that combines pixels for near unfocused, focused and far unfocused planes, as calculated by 
+	 * GaussianDOFSeparateMat. Outputs final depth-of-field filtered image.
+	 */
+	class GaussianDOFCombineMat : public RendererMaterial<GaussianDOFCombineMat>
 	{
 	{
+		RMAT_DEF("PPGaussianDOFCombine.bsl");
+
 	public:
 	public:
-		virtual ~IGaussianDOFCombineMat() { }
+		GaussianDOFCombineMat();
 
 
 		/** 
 		/** 
 		 * Renders the post-process effect with the provided parameters. 
 		 * Renders the post-process effect with the provided parameters. 
@@ -447,67 +369,30 @@ namespace bs { namespace ct
 		 * @param[in]	view		View through which the depth of field effect is viewed.
 		 * @param[in]	view		View through which the depth of field effect is viewed.
 		 * @param[in]	settings	Settings used to control depth of field rendering. 
 		 * @param[in]	settings	Settings used to control depth of field rendering. 
 		 */
 		 */
-		virtual void execute(const SPtr<Texture>& focused, const SPtr<Texture>& near, const SPtr<Texture>& far, 
+		void execute(const SPtr<Texture>& focused, const SPtr<Texture>& near, const SPtr<Texture>& far, 
 			const SPtr<Texture>& depth, const SPtr<RenderTarget>& output, const RendererView& view, 
 			const SPtr<Texture>& depth, const SPtr<RenderTarget>& output, const RendererView& view, 
-			const DepthOfFieldSettings& settings) = 0;
-	};
-
-	/** 
-	 * Shader that combines pixels for near unfocused, focused and far unfocused planes, as calculated by 
-	 * GaussianDOFSeparateMat. Outputs final depth-of-field filtered image.
-	 *
-	 * @tparam	Near	If true, near plane pixels are read from the near plane texture, otherwise near plane is assumed
-	 *					not to exist.
-	 * @tparam	Far		If true, far plane pixels are read from the far plane texture, otherwise far plane is assumed not
-	 *					to exist.
-	 */
-	template<bool Near, bool Far>
-	class GaussianDOFCombineMat : public IGaussianDOFCombineMat, public RendererMaterial<GaussianDOFCombineMat<Near, Far>>
-	{
-		RMAT_DEF("PPGaussianDOFCombine.bsl");
+			const DepthOfFieldSettings& settings);
 
 
-	public:
-		GaussianDOFCombineMat();
+		/** 
+		 * Returns the material variation matching the provided parameters.
+		 *
+		 * @param	near	If true, near plane pixels are read from the near plane texture, otherwise near plane is assumed
+		 *					not to exist.
+		 * @param	far		If true, far plane pixels are read from the far plane texture, otherwise far plane is assumed not
+		 *					to exist.
+		 */
+		static GaussianDOFCombineMat* getVariation(bool near, bool far);
 
 
-		void execute(const SPtr<Texture>& focused, const SPtr<Texture>& near, const SPtr<Texture>& far, 
-			const SPtr<Texture>& depth, const SPtr<RenderTarget>& output, const RendererView& view, 
-			const DepthOfFieldSettings& settings) override;
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		GpuParamTexture mFocusedTexture;
 		GpuParamTexture mFocusedTexture;
 		GpuParamTexture mNearTexture;
 		GpuParamTexture mNearTexture;
 		GpuParamTexture mFarTexture;
 		GpuParamTexture mFarTexture;
 		GpuParamTexture mDepthTexture;
 		GpuParamTexture mDepthTexture;
-	};
-
-	/** Performs Gaussian depth of field effect with the help of various related shaders. */
-	class GaussianDOF
-	{
-	public:
-		/** 
-		 * Executes the depth of field effect on the provided scene color texture.
-		 * 
-		 * @param[in]	sceneColor	Input texture containing scene color.
-		 * @param[in]	sceneDepth	Input depth buffer texture that will be used for determining pixel depth.
-		 * @param[in]	output		Texture to output the results to.
-		 * @param[in]	view		View through which the depth of field effect is viewed.
-		 * @param[in]	settings	Settings used to control depth of field rendering. 
-		 */
-		void execute(const SPtr<Texture>& sceneColor, const SPtr<Texture>& sceneDepth, const SPtr<RenderTarget>& output, 
-			const RendererView& view, const DepthOfFieldSettings& settings);
-
-		/** Checks does the depth of field effect need to execute. */
-		static bool requiresDOF(const DepthOfFieldSettings& settings);
-	private:
-		GaussianDOFSeparateMat<true, true> mSeparateNF;
-		GaussianDOFSeparateMat<false, true> mSeparateF;
-		GaussianDOFSeparateMat<true, false> mSeparateN;
-
-		GaussianDOFCombineMat<true, true> mCombineNF;
-		GaussianDOFCombineMat<false, true> mCombineF;
-		GaussianDOFCombineMat<true, false> mCombineN;
 
 
-		GaussianBlurMat mBlur;
+		static ShaderVariation VAR_Near_Far;
+		static ShaderVariation VAR_NoNear_Far;
+		static ShaderVariation VAR_Near_NoFar;
 	};
 	};
 
 
 	/** Shader that calculates a single level of the hierarchical Z mipmap chain. */
 	/** Shader that calculates a single level of the hierarchical Z mipmap chain. */
@@ -534,27 +419,6 @@ namespace bs { namespace ct
 		GpuParamTexture mInputTexture;
 		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);
-
-	private:
-		BuildHiZMat mHiZMat;
-	};
-
 	BS_PARAM_BLOCK_BEGIN(FXAAParamDef)
 	BS_PARAM_BLOCK_BEGIN(FXAAParamDef)
 		BS_PARAM_BLOCK_ENTRY(Vector2, gInvTexSize)
 		BS_PARAM_BLOCK_ENTRY(Vector2, gInvTexSize)
 	BS_PARAM_BLOCK_END
 	BS_PARAM_BLOCK_END
@@ -616,18 +480,8 @@ namespace bs { namespace ct
 		SPtr<Texture> randomRotations;
 		SPtr<Texture> randomRotations;
 	};
 	};
 
 
-	/** 
-	 * Shader that computes ambient occlusion using screen based methods.
-	 *
-	 * @tparam	UPSAMPLE	If true the shader will blend the calculated AO with AO data from the previous pass.
-	 * @tparam	FINAL_PASS	If true the shader will use the full screen normal/depth information and perform
-	 *						intensity scaling, as well as distance fade. Otherwise the shader will use the
-	 *						downsampled AO setup information, with no scaling/fade.
-	 * @tparam	QUALITY		Integer in range [0, 4] that controls the quality of SSAO sampling. Higher numbers yield
-	 *						better quality at the cost of performance. 
-	 */
-	template<bool UPSAMPLE, bool FINAL_PASS, int QUALITY>
-	class SSAOMat : public RendererMaterial<SSAOMat<UPSAMPLE, FINAL_PASS, QUALITY>>
+	/** Shader that computes ambient occlusion using screen based methods. */
+	class SSAOMat : public RendererMaterial<SSAOMat>
 	{
 	{
 		RMAT_DEF("PPSSAO.bsl");
 		RMAT_DEF("PPSSAO.bsl");
 
 
@@ -646,6 +500,18 @@ namespace bs { namespace ct
 		void execute(const RendererView& view, const SSAOTextureInputs& textures, const SPtr<RenderTexture>& destination, 
 		void execute(const RendererView& view, const SSAOTextureInputs& textures, const SPtr<RenderTexture>& destination, 
 			const AmbientOcclusionSettings& settings);
 			const AmbientOcclusionSettings& settings);
 
 
+		/** 
+		 * Returns the material variation matching the provided parameters.
+		 *
+		 * @param	upsample	If true the shader will blend the calculated AO with AO data from the previous pass.
+		 * @param	finalPass	If true the shader will use the full screen normal/depth information and perform
+		 *						intensity scaling, as well as distance fade. Otherwise the shader will use the
+		 *						downsampled AO setup information, with no scaling/fade.
+		 * @param	quality		Integer in range [0, 4] that controls the quality of SSAO sampling. Higher numbers yield
+		 *						better quality at the cost of performance. 
+		 */
+		static SSAOMat* getVariation(bool upsample, bool finalPass, int quality);
+
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		GpuParamTexture mDepthTexture;
 		GpuParamTexture mDepthTexture;
@@ -653,6 +519,20 @@ namespace bs { namespace ct
 		GpuParamTexture mDownsampledAOTexture;
 		GpuParamTexture mDownsampledAOTexture;
 		GpuParamTexture mSetupAOTexture;
 		GpuParamTexture mSetupAOTexture;
 		GpuParamTexture mRandomTexture;
 		GpuParamTexture mRandomTexture;
+
+#define VARIATION(QUALITY) \
+		static ShaderVariation VAR_Upsample_Final_Quality##QUALITY;		\
+		static ShaderVariation VAR_Upsample_NoFinal_Quality##QUALITY;		\
+		static ShaderVariation VAR_NoUpsample_Final_Quality##QUALITY;		\
+		static ShaderVariation VAR_NoUpsample_NoFinal_Quality##QUALITY;		\
+
+		VARIATION(0)
+		VARIATION(1)
+		VARIATION(2)
+		VARIATION(3)
+		VARIATION(4)
+
+#undef VARIATION
 	};
 	};
 
 
 	BS_PARAM_BLOCK_BEGIN(SSAODownsampleParamDef)
 	BS_PARAM_BLOCK_BEGIN(SSAODownsampleParamDef)
@@ -702,8 +582,7 @@ namespace bs { namespace ct
 	/** 
 	/** 
 	 * Shaders that blurs the ambient occlusion output, in order to hide the noise caused by the randomization texture.
 	 * Shaders that blurs the ambient occlusion output, in order to hide the noise caused by the randomization texture.
 	 */
 	 */
-	template<bool HORIZONTAL>
-	class SSAOBlurMat : public RendererMaterial<SSAOBlurMat<HORIZONTAL>>
+	class SSAOBlurMat : public RendererMaterial<SSAOBlurMat>
 	{
 	{
 		RMAT_DEF("PPSSAOBlur.bsl");
 		RMAT_DEF("PPSSAOBlur.bsl");
 
 
@@ -722,58 +601,16 @@ namespace bs { namespace ct
 		void execute(const RendererView& view, const SPtr<Texture>& ao, const SPtr<Texture>& sceneDepth,
 		void execute(const RendererView& view, const SPtr<Texture>& ao, const SPtr<Texture>& sceneDepth,
 			const SPtr<RenderTexture>& destination, float depthRange);
 			const SPtr<RenderTexture>& destination, float depthRange);
 
 
+		/** Returns the material variation matching the provided parameters. */
+		static SSAOBlurMat* getVariation(bool horizontal);
+
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		GpuParamTexture mAOTexture;
 		GpuParamTexture mAOTexture;
 		GpuParamTexture mDepthTexture;
 		GpuParamTexture mDepthTexture;
-	};
-
-	/** 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:
-		/** @copydoc SSAOMat::execute() */
-		void executeSSAOMat(bool upsample, bool final, int quality, const RendererView& view, 
-			const SSAOTextureInputs& textures, const SPtr<RenderTexture>& destination, 
-			const AmbientOcclusionSettings& settings);
-
-		SSAODownsampleMat mDownsample;
-		SSAOBlurMat<true> mBlurHorz;
-		SSAOBlurMat<false> mBlurVert;
-		SPtr<Texture> mSSAORandomizationTex;
 
 
-#define DEFINE_MATERIAL(QUALITY)							\
-		SSAOMat<false, false, QUALITY> mSSAO_FF_##QUALITY;	\
-		SSAOMat<true, false, QUALITY> mSSAO_TF_##QUALITY;	\
-		SSAOMat<false, true, QUALITY> mSSAO_FT_##QUALITY;	\
-		SSAOMat<true, true, QUALITY> mSSAO_TT_##QUALITY;	\
-
-		DEFINE_MATERIAL(0)
-		DEFINE_MATERIAL(1)
-		DEFINE_MATERIAL(2)
-		DEFINE_MATERIAL(3)
-		DEFINE_MATERIAL(4)
-
-#undef DEFINE_MATERIAL
+		static ShaderVariation VAR_Vertical;
+		static ShaderVariation VAR_Horizontal;
 	};
 	};
 
 
 	BS_PARAM_BLOCK_BEGIN(SSRStencilParamDef)
 	BS_PARAM_BLOCK_BEGIN(SSRStencilParamDef)
@@ -794,9 +631,10 @@ namespace bs { namespace ct
 		 * Renders the effect with the provided parameters, using the currently bound render target. 
 		 * 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]	view			Information about the view we're rendering from.
+		 * @param[in]	gbuffer			GBuffer textures.
 		 * @param[in]	settings		Parameters used for controling the SSR effect.
 		 * @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:
 	private:
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		GBufferParams mGBufferParams;
 		GBufferParams mGBufferParams;
@@ -825,10 +663,14 @@ namespace bs { namespace ct
 		 * Renders the effect with the provided parameters. 
 		 * Renders the effect with the provided parameters. 
 		 * 
 		 * 
 		 * @param[in]	view			Information about the view we're rendering from.
 		 * @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]	settings		Parameters used for controling the SSR effect.
 		 * @param[in]	destination		Render target to which to write the results to.
 		 * @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);
 			const SPtr<RenderTarget>& destination);
 
 
 		/**
 		/**
@@ -859,14 +701,8 @@ namespace bs { namespace ct
 
 
 	extern SSRResolveParamDef gSSRResolveParamDef;
 	extern SSRResolveParamDef gSSRResolveParamDef;
 
 
-	/** 
-	 * Shader used for combining SSR information from the previous frame, in order to yield better quality. 
-	 * 
-	 * @tparam	EyeAdaptation	When true the shader will expect a texture containing an exposure value calculated by
-	 *							the eye adaptation shader. Otherwise the manually provided exposure value is used instead.
-	 */
-	template<bool EyeAdaptation>
-	class SSRResolveMat : public RendererMaterial<SSRResolveMat<EyeAdaptation>>
+	/** Shader used for combining SSR information from the previous frame, in order to yield better quality. */
+	class SSRResolveMat : public RendererMaterial<SSRResolveMat>
 	{
 	{
 		RMAT_DEF("PPSSRResolve.bsl");
 		RMAT_DEF("PPSSRResolve.bsl");
 
 
@@ -885,6 +721,15 @@ namespace bs { namespace ct
 		void execute(const RendererView& view, const SPtr<Texture>& prevFrame, const SPtr<Texture>& curFrame, 
 		void execute(const RendererView& view, const SPtr<Texture>& prevFrame, const SPtr<Texture>& curFrame, 
 			const SPtr<Texture>& sceneDepth, const SPtr<RenderTarget>& destination);
 			const SPtr<Texture>& sceneDepth, const SPtr<RenderTarget>& destination);
 
 
+		/** 
+		 * Returns the material variation matching the provided parameters. 
+		 * 
+		 * @param	eyeAdaptation	When true the shader will expect a texture containing an exposure value calculated by
+		 *							the eye adaptation shader. Otherwise the manually provided exposure value is used
+		 *							instead.
+		 */
+		SSRResolveMat* getVariation(bool eyeAdaptation);
+
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mSSRParamBuffer;
 		SPtr<GpuParamBlockBuffer> mSSRParamBuffer;
 		SPtr<GpuParamBlockBuffer> mTemporalParamBuffer;
 		SPtr<GpuParamBlockBuffer> mTemporalParamBuffer;
@@ -893,39 +738,9 @@ namespace bs { namespace ct
 		GpuParamTexture mPrevColorTexture;
 		GpuParamTexture mPrevColorTexture;
 		GpuParamTexture mSceneDepthTexture;
 		GpuParamTexture mSceneDepthTexture;
 		GpuParamTexture mEyeAdaptationTexture;
 		GpuParamTexture mEyeAdaptationTexture;
-	};
 
 
-	/**
-	 * 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:
-		DownsampleMaterials mDownsample;
-		EyeAdaptHistogramMat mEyeAdaptHistogram;
-		EyeAdaptHistogramReduceMat mEyeAdaptHistogramReduce;
-		EyeAdaptationMat mEyeAdaptation;
-
-		CreateTonemapLUTMat mCreateLUT;
-		TonemappingMaterials mTonemapping;
-		GaussianDOF mGaussianDOF;
-		FXAAMat mFXAA;
-		SSAO mSSAO;
+		static ShaderVariation VAR_EyeAdaptation;
+		static ShaderVariation VAR_NoEyeAdaptation;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 7 - 37
Source/RenderBeast/Include/BsRenderBeast.h

@@ -5,8 +5,6 @@
 #include "BsRenderBeastPrerequisites.h"
 #include "BsRenderBeastPrerequisites.h"
 #include "BsRenderer.h"
 #include "BsRenderer.h"
 #include "BsRendererMaterial.h"
 #include "BsRendererMaterial.h"
-#include "BsLightRendering.h"
-#include "BsImageBasedLighting.h"
 #include "BsObjectRendering.h"
 #include "BsObjectRendering.h"
 #include "BsPostProcessing.h"
 #include "BsPostProcessing.h"
 #include "BsRendererView.h"
 #include "BsRendererView.h"
@@ -71,9 +69,6 @@ namespace bs
 		/** @copydoc Renderer::destroy */
 		/** @copydoc Renderer::destroy */
 		void destroy() override;
 		void destroy() override;
 
 
-		/** @copydoc Renderer::createPostProcessSettings */
-		SPtr<PostProcessSettings> createPostProcessSettings() const override;
-
 		/** 
 		/** 
 		 * Captures the scene at the specified location into a cubemap. 
 		 * Captures the scene at the specified location into a cubemap. 
 		 * 
 		 * 
@@ -168,14 +163,14 @@ namespace bs
 		 *			
 		 *			
 		 * @note	Core thread only.
 		 * @note	Core thread only.
 		 */
 		 */
-		void renderView(RendererView* viewInfo, float frameDelta);
+		void renderView(const RendererViewGroup& viewGroup, RendererView& view, const FrameInfo& frameInfo);
 
 
 		/**
 		/**
 		 * Renders all overlay callbacks of the provided view.
 		 * Renders all overlay callbacks of the provided view.
 		 * 					
 		 * 					
 		 * @note	Core thread only.
 		 * @note	Core thread only.
 		 */
 		 */
-		void renderOverlay(RendererView* viewInfo);
+		void renderOverlay(RendererView& view);
 
 
 		/** 
 		/** 
 		 * Renders a single element of a renderable object. 
 		 * Renders a single element of a renderable object. 
@@ -195,48 +190,23 @@ namespace bs
 		void destroyCore();
 		void destroyCore();
 
 
 		/** Updates light probes, rendering & filtering ones that are dirty and updating the global probe cubemap array. */
 		/** Updates light probes, rendering & filtering ones that are dirty and updating the global probe cubemap array. */
-		void updateLightProbes(const FrameInfo& frameInfo);
+		void renderReflectionProbes(const FrameInfo& frameInfo);
+
+		/** Renders the skybox filtered reflections and irradiance cubemap, if they require updating. */
+		void updateSkybox();
 
 
 		// Core thread only fields
 		// Core thread only fields
 
 
 		// Scene data
 		// Scene data
 		SPtr<RendererScene> mScene;
 		SPtr<RendererScene> mScene;
 
 
-		//// Reflection probes
-		Vector<bool> mCubemapArrayUsedSlots;
-		SPtr<Texture> mReflCubemapArrayTex;
-
-		//// Sky light
-		Skybox* mSkybox = nullptr;
-		SPtr<Texture> mSkyboxTexture;
-		SPtr<Texture> mSkyboxFilteredReflections;
-		SPtr<Texture> mSkyboxIrradiance;
-
-		// Materials & GPU data
 		//// Base pass
 		//// Base pass
 		ObjectRenderer* mObjectRenderer = nullptr;
 		ObjectRenderer* mObjectRenderer = nullptr;
 
 
-		//// Lighting
-		TiledDeferredLightingMaterials* mTiledDeferredLightingMats = nullptr;
-		LightGrid* mLightGrid = nullptr;
-		VisibleLightData* mVisibleLightInfo = nullptr;
-
-		//// Image based lighting
-		TiledDeferredImageBasedLightingMaterials* mTileDeferredImageBasedLightingMats = nullptr;
-		VisibleReflProbeData* mVisibleReflProbeInfo = nullptr;
-		SPtr<Texture> mPreintegratedEnvBRDF;
-
-		//// Sky
-		SkyboxMat<false>* mSkyboxMat;
-		SkyboxMat<true>* mSkyboxSolidColorMat;
-
-		//// Other
-		FlatFramebufferToTextureMat* mFlatFramebufferToTextureMat = nullptr;
-
 		SPtr<RenderBeastOptions> mCoreOptions;
 		SPtr<RenderBeastOptions> mCoreOptions;
 
 
 		// Helpers to avoid memory allocations
 		// Helpers to avoid memory allocations
-		RendererViewGroup mMainViewGroup;
+		RendererViewGroup* mMainViewGroup = nullptr;
 
 
 		// Sim thread only fields
 		// Sim thread only fields
 		SPtr<RenderBeastOptions> mOptions;
 		SPtr<RenderBeastOptions> mOptions;

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

@@ -0,0 +1,567 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsRenderBeastPrerequisites.h"
+
+namespace bs 
+{ 
+	class RendererExtension;
+
+namespace ct
+{
+	struct SceneInfo;
+	class RendererViewGroup;
+	class RenderCompositorNode;
+	struct PooledStorageBuffer;
+	struct FrameInfo;
+
+	/** @addtogroup RenderBeast
+	 *  @{
+	 */
+	
+	/** Inputs provided to each node in the render compositor hierarchy */
+	struct RenderCompositorNodeInputs
+	{
+		RenderCompositorNodeInputs(const RendererViewGroup& viewGroup, const RendererView& view, const SceneInfo& scene, 
+			const RenderBeastOptions& options, const FrameInfo& frameInfo)
+			: viewGroup(viewGroup), view(view), scene(scene), options(options), frameInfo(frameInfo)
+		{ }
+
+		const RendererViewGroup& viewGroup;
+		const RendererView& view;
+		const SceneInfo& scene;
+		const RenderBeastOptions& options;
+		const FrameInfo& frameInfo;
+
+		// Callbacks to external systems can hook into the compositor
+		SmallVector<RendererExtension*, 4> extPreBasePass;
+		SmallVector<RendererExtension*, 4> extPostBasePass;
+		SmallVector<RendererExtension*, 4> extPostLighting;
+		SmallVector<RendererExtension*, 4> extOverlay;
+
+		SmallVector<RenderCompositorNode*, 4> inputNodes;
+	};
+
+	/** 
+	 * Node in the render compositor hierarchy. Nodes can be implemented to perform specific rendering tasks. Each node
+	 * can depend on other nodes in the hierarchy.
+	 * 
+	 * @note	Implementations must provide a getNodeId() and getDependencies() static method, which are expected to
+	 *			return a unique name for the implemented node, as well as a set of nodes it depends on.
+	 */
+	class RenderCompositorNode
+	{
+	public:
+		virtual ~RenderCompositorNode() { }
+
+	protected:
+		friend class RenderCompositor;
+
+		/** Executes the task implemented in the node. */
+		virtual void render(const RenderCompositorNodeInputs& inputs) = 0;
+
+		/** 
+		 * Cleans up any temporary resources allocated in a render() call. Any resources lasting longer than one frame
+		 * should be kept alive and released in some other manner.
+		 */
+		virtual void clear() = 0;
+	};
+
+	/**
+	 * Performs rendering by iterating over a hierarchy of render nodes. Each node in the hierarchy performs a specific
+	 * rendering tasks and passes its output to the dependant node. The system takes care of initializing, rendering and
+	 * cleaning up nodes automatically depending on their dependencies.
+	 */
+	class RenderCompositor
+	{
+		/** Contains internal information about a single render node. */
+		struct NodeInfo
+		{
+			RenderCompositorNode* node;
+			UINT32 lastUseIdx;
+			SmallVector<RenderCompositorNode*, 4> inputs;
+		};
+	public:
+		~RenderCompositor();
+
+		/**
+		 * Rebuilds the render node hierarchy. Call this whenever some setting that may influence the render node 
+		 * dependencies changes.
+		 * 
+		 * @param[in]	view		Parent view to which this compositor belongs to.
+		 * @param[in]	finalNode	Identifier of the final node in the node hierarchy. This node is expected to write
+		 *							to the views render target. All other nodes will be deduced from this node's
+		 *							dependencies.
+		 */
+		void build(const RendererView& view, const StringID& finalNode);
+
+		/** Performs rendering using the current render node hierarchy. This is expected to be called once per frame. */
+		void execute(RenderCompositorNodeInputs& inputs) const;
+
+	private:
+		/** Clears the render node hierarchy. */
+		void clear();
+
+		Vector<NodeInfo> mNodeInfos;
+		bool mIsValid = false;
+
+		/************************************************************************/
+		/* 							NODE TYPES	                     			*/
+		/************************************************************************/
+	public:
+		/** Contains information about a specific node type. */
+		struct NodeType
+		{
+			virtual ~NodeType() {};
+
+			/** Creates a new node of this type. */
+			virtual RenderCompositorNode* create() const = 0;
+
+			/** Returns identifier for all the dependencies of a node of this type. */
+			virtual SmallVector<StringID, 4> getDependencies(const RendererView& view) const = 0;
+
+			StringID id;
+		};
+		
+		/** Templated implementation of NodeType. */
+		template<class T>
+		struct TNodeType : NodeType
+		{
+			/** @copydoc NodeType::create() */
+			RenderCompositorNode* create() const override { return bs_new<T>(); }
+
+			/** @copydoc NodeType::getDependencies() */
+			SmallVector<StringID, 4> getDependencies(const RendererView& view) const override
+			{
+				return T::getDependencies(view);
+			}
+		};
+
+		/** 
+		 * Registers a new type of node with the system. Each node type must first be registered before it can be used
+		 * in the node hierarchy.
+		 */
+		template<class T>
+		static void registerNodeType()
+		{
+			auto findIter = mNodeTypes.find(T::getNodeId());
+			if (findIter != mNodeTypes.end())
+				LOGERR("Found two render compositor nodes with the same name \"" + String(T::getNodeId().cstr()) + "\".");
+
+			mNodeTypes[T::getNodeId()] = bs_new<TNodeType<T>>();
+		}
+
+		/** Releases any information about render node types. */
+		static void cleanUp()
+		{
+			for (auto& entry : mNodeTypes)
+				bs_delete(entry.second);
+
+			mNodeTypes.clear();
+		}
+
+	private:
+		static UnorderedMap<StringID, NodeType*> mNodeTypes;
+	};
+
+	/************************************************************************/
+	/* 							BASE PASS NODES	                     		*/
+	/************************************************************************/
+
+	/** Initializes the scene depth texture. Does not perform any rendering. */
+	class RCNodeSceneDepth : public RenderCompositorNode
+	{
+	public:
+		// Outputs
+		SPtr<PooledRenderTexture> depthTex;
+
+		static StringID getNodeId() { return "SceneDepth"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+	};
+
+	/** 
+	 * Initializes the GBuffer textures and renders the base pass into the GBuffer. The base pass includes all the opaque
+	 * objects visible to the view.
+	 */
+	class RCNodeGBuffer : public RenderCompositorNode
+	{
+	public:
+		// Outputs
+		SPtr<PooledRenderTexture> albedoTex;
+		SPtr<PooledRenderTexture> normalTex;
+		SPtr<PooledRenderTexture> roughMetalTex;
+
+		SPtr<RenderTexture> renderTarget;
+
+		static StringID getNodeId() { return "GBuffer"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+	};
+
+	/** Initializes the scene color texture and/or buffer. Does not perform any rendering. */
+	class RCNodeSceneColor : public RenderCompositorNode
+	{
+	public:
+		// Outputs
+		/** 
+		 * Contains scene color. If MSAA is used this texture will be null until the flattened data from the buffer is
+		 * first resolved into this texture.
+		 */
+		SPtr<PooledRenderTexture> sceneColorTex;
+
+		/** 
+		 * Flattened, buffer version of sceneColorTex. Only available when MSAA is used, since random writes to multisampled
+		 * textures aren't supported on all render backends.
+		 */
+		SPtr<PooledStorageBuffer> flattenedSceneColorBuffer;
+
+		SPtr<RenderTexture> renderTarget;
+
+		static StringID getNodeId() { return "SceneColor"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+	};
+
+	/************************************************************************/
+	/* 							LIGHTING NODES                     			*/
+	/************************************************************************/
+
+	/** Initializes the light accumulation texture and/or buffer. Does not perform any rendering. */
+	class RCNodeLightAccumulation : public RenderCompositorNode
+	{
+	public:
+		// Outputs
+		/** 
+		 * Contains lighting information accumulated from multiple lights. If MSAA is used this texture will be null until
+		 * the flattened data from the buffer is first resolved into this texture.
+		 */
+		SPtr<PooledRenderTexture> lightAccumulationTex;
+
+		/** 
+		 * Flattened, buffer version of lightAccumulationTex. Only available when MSAA is used, since random writes to
+		 * multisampled textures aren't supported on all render backends.
+		 */
+		SPtr<PooledStorageBuffer> flattenedLightAccumBuffer;
+
+		SPtr<RenderTexture> renderTarget;
+
+		static StringID getNodeId() { return "LightAccumulation"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+	};
+
+	/** 
+	 * Performs tiled deferred lighting, outputing any lighting information in the light accumulation buffer. 
+	 * By default only non-shadowed lights are rendered, as shadowed ones are handled using standard deferred.
+	 */
+	class RCNodeTiledDeferredLighting : public RenderCompositorNode
+	{
+	public:
+		// Outputs
+		RCNodeLightAccumulation* output;
+
+		static StringID getNodeId() { return "TiledDeferredLighting"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+	};
+
+	/**
+	 * Performs standard deferred lighting, outputting any lighting information in the light accumulation buffer.
+	 * Only renders shadowed lights.
+	 */
+	class RCNodeStandardDeferredLighting : public RenderCompositorNode
+	{
+	public:
+		// Outputs
+		RCNodeLightAccumulation* output;
+
+		static StringID getNodeId() { return "StandardDeferredLighting"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+
+		SPtr<PooledRenderTexture> mLightOcclusionTex;
+		SPtr<RenderTexture> mRenderTarget;
+	};
+
+	/**
+	 * In case light accumulation 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 light accumulation texture.
+	 */
+	class RCNodeUnflattenLightAccum : public RenderCompositorNode
+	{
+	public:
+		// Outputs
+		RCNodeLightAccumulation* output;
+
+		static StringID getNodeId() { return "UnflattenLightAccum"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+	};
+
+	/**
+	 * Perform tiled deferred image based lighting, combines it with direct lighting present in the light accumulation
+	 * buffer and outputs the results to the scene color texture or buffer.
+	 */
+	class RCNodeTiledDeferredIBL : public RenderCompositorNode
+	{
+	public:
+		// Outputs
+		RCNodeLightAccumulation* output;
+
+		static StringID getNodeId() { return "TiledDeferredIBL"; }
+		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 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.
+	 */
+	class RCNodeUnflattenSceneColor : public RenderCompositorNode
+	{
+	public:
+		// Outputs
+		RCNodeSceneColor* output;
+
+		static StringID getNodeId() { return "UnflattenSceneColor"; }
+		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 the skybox into the scene color texture. If skybox texture is not available, a solid color will be rendered
+	 * instead.
+	 */
+	class RCNodeSkybox : public RenderCompositorNode
+	{
+	public:
+		static StringID getNodeId() { return "Skybox"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+	};
+
+	/** Moves the contents of the scene color texture into the view's output target. */
+	class RCNodeFinalResolve : public RenderCompositorNode
+	{
+	public:
+		static StringID getNodeId() { return "FinalResolve"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+	};
+
+	/************************************************************************/
+	/* 							POST PROCESS NODES                			*/
+	/************************************************************************/
+
+	/** 
+	 * Helper node used for post-processing. Takes care of allocating and switching between textures used for post process
+	 * effects. 
+	 */
+	class RCNodePostProcess : public RenderCompositorNode
+	{
+	public:
+		RCNodePostProcess();
+
+		/** 
+		 * Returns a texture that can be used for rendering a post-process effect, and the result of the previous 
+		 * output. Switches these textures so the next call they are returned in the opposite parameters. 
+		 */
+		void getAndSwitch(const RendererView& view, SPtr<RenderTexture>& output, SPtr<Texture>& lastFrame) const;
+
+		/** Returns a texture that contains the last rendererd post process output. */
+		SPtr<Texture> getLastOutput() const;
+
+		static StringID getNodeId() { return "PostProcess"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+
+		mutable SPtr<PooledRenderTexture> mOutput[2];
+		mutable bool mAllocated[2];
+		mutable UINT32 mCurrentIdx = 0;
+	};
+
+	/**
+	 * Performs tone mapping on the contents of the scene color texture. At the same time resolves MSAA into a non-MSAA
+	 * scene color texture.
+	 */
+	class RCNodeTonemapping : public RenderCompositorNode
+	{
+	public:
+		SPtr<PooledRenderTexture> eyeAdaptation;
+		SPtr<PooledRenderTexture> prevEyeAdaptation;
+
+		~RCNodeTonemapping();
+
+		static StringID getNodeId() { return "Tonemapping"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		void clear() override;
+
+		SPtr<PooledRenderTexture> mTonemapLUT;
+		UINT64 mTonemapLastUpdateHash = -1;
+	};
+
+	/** Renders the depth of field effect using Gaussian blurring. */
+	class RCNodeGaussianDOF : public RenderCompositorNode
+	{
+	public:
+		static StringID getNodeId() { return "GaussianDOF"; }
+		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 FXAA. */
+	class RCNodeFXAA : public RenderCompositorNode
+	{
+	public:
+		static StringID getNodeId() { return "FXAA"; }
+		static SmallVector<StringID, 4> getDependencies(const RendererView& view);
+	protected:
+		/** @copydoc RenderCompositorNode::render */
+		void render(const RenderCompositorNodeInputs& inputs) override;
+
+		/** @copydoc RenderCompositorNode::clear */
+		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 - 190
Source/RenderBeast/Include/BsRenderTargets.h

@@ -1,190 +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;
-
-		// Note: Only a single instance of this is needed, move it to a Module eventually
-		BuildHiZ mBuildHiZ;
-	};
-
-	/** @} */
-}}

+ 30 - 1
Source/RenderBeast/Include/BsRendererScene.h

@@ -21,6 +21,19 @@ namespace bs
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
+	// Limited by max number of array elements in texture for DX11 hardware
+	constexpr UINT32 MaxReflectionCubemaps = 2048 / 6;
+
+	/** Contains information about the skybox in the current scene. */
+	struct SkyInfo
+	{
+		Skybox* skybox = nullptr;
+
+		SPtr<Texture> radiance;
+		SPtr<Texture> filteredReflections;
+		SPtr<Texture> irradiance;
+	};
+
 	/** Contains most scene objects relevant to the renderer. */
 	/** Contains most scene objects relevant to the renderer. */
 	struct SceneInfo
 	struct SceneInfo
 	{
 	{
@@ -43,6 +56,11 @@ namespace bs
 		// Reflection probes
 		// Reflection probes
 		Vector<RendererReflectionProbe> reflProbes;
 		Vector<RendererReflectionProbe> reflProbes;
 		Vector<Sphere> reflProbeWorldBounds;
 		Vector<Sphere> reflProbeWorldBounds;
+		Vector<bool> reflProbeCubemapArrayUsedSlots;
+		SPtr<Texture> reflProbeCubemapsTex;
+
+		// Sky
+		SkyInfo sky;
 
 
 		// Buffers for various transient data that gets rebuilt every frame
 		// Buffers for various transient data that gets rebuilt every frame
 		//// Rebuilt every frame
 		//// Rebuilt every frame
@@ -98,6 +116,15 @@ namespace bs
 		/** Updates the index at which the reflection probe's texture is stored at, in the global array. */
 		/** Updates the index at which the reflection probe's texture is stored at, in the global array. */
 		void setReflectionProbeArrayIndex(UINT32 probeIdx, UINT32 arrayIdx, bool markAsClean);
 		void setReflectionProbeArrayIndex(UINT32 probeIdx, UINT32 arrayIdx, bool markAsClean);
 
 
+		/** Registers a new sky texture in the scene. */
+		void registerSkybox(Skybox* skybox);
+
+		/** Updates information about the previously registered skybox. */
+		void updateSkybox(Skybox* skybox);
+
+		/** Removes a skybox from the scene. */
+		void unregisterSkybox(Skybox* skybox);
+
 		/** Returns a container with all relevant scene objects. */
 		/** Returns a container with all relevant scene objects. */
 		const SceneInfo& getSceneInfo() const { return mInfo; }
 		const SceneInfo& getSceneInfo() const { return mInfo; }
 
 
@@ -121,6 +148,9 @@ namespace bs
 		 * @param[in]	frameInfo	Global information describing the current frame.
 		 * @param[in]	frameInfo	Global information describing the current frame.
 		 */
 		 */
 		void prepareRenderable(UINT32 idx, const FrameInfo& frameInfo);
 		void prepareRenderable(UINT32 idx, const FrameInfo& frameInfo);
+
+		/** Returns a modifiable version of SceneInfo. Only to be used by friends who know what they are doing. */
+		SceneInfo& _getSceneInfo() { return mInfo; }
 	private:
 	private:
 		/** Creates a renderer view descriptor for the particular camera. */
 		/** Creates a renderer view descriptor for the particular camera. */
 		RENDERER_VIEW_DESC createViewDesc(Camera* camera) const;
 		RENDERER_VIEW_DESC createViewDesc(Camera* camera) const;
@@ -134,7 +164,6 @@ namespace bs
 		SceneInfo mInfo;
 		SceneInfo mInfo;
 		UnorderedMap<SamplerOverrideKey, MaterialSamplerOverrides*> mSamplerOverrides;
 		UnorderedMap<SamplerOverrideKey, MaterialSamplerOverrides*> mSamplerOverrides;
 
 
-		DefaultMaterial* mDefaultMaterial = nullptr;
 		SPtr<RenderBeastOptions> mOptions;
 		SPtr<RenderBeastOptions> mOptions;
 	};
 	};
 
 

+ 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;
+	};
+
+	/** @} */
+}}

+ 71 - 30
Source/RenderBeast/Include/BsRendererView.h

@@ -10,6 +10,9 @@
 #include "BsBounds.h"
 #include "BsBounds.h"
 #include "BsConvexVolume.h"
 #include "BsConvexVolume.h"
 #include "BsLight.h"
 #include "BsLight.h"
+#include "BsLightGrid.h"
+#include "BsShadowRendering.h"
+#include "BsRenderCompositor.h"
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
@@ -48,8 +51,7 @@ namespace bs { namespace ct
 	extern SkyboxParamDef gSkyboxParamDef;
 	extern SkyboxParamDef gSkyboxParamDef;
 
 
 	/** Shader that renders a skybox using a cubemap or a solid color. */
 	/** Shader that renders a skybox using a cubemap or a solid color. */
-	template<bool SOLID_COLOR>
-	class SkyboxMat : public RendererMaterial<SkyboxMat<SOLID_COLOR>>
+	class SkyboxMat : public RendererMaterial<SkyboxMat>
 	{
 	{
 		RMAT_DEF("Skybox.bsl");
 		RMAT_DEF("Skybox.bsl");
 
 
@@ -61,9 +63,20 @@ namespace bs { namespace ct
 
 
 		/** Updates the skybox texture & solid color used by the material. */
 		/** Updates the skybox texture & solid color used by the material. */
 		void setParams(const SPtr<Texture>& texture, const Color& solidColor);
 		void setParams(const SPtr<Texture>& texture, const Color& solidColor);
+
+		/** 
+		 * Returns the material variation matching the provided parameters.
+		 * 
+		 * @param[in]	color	When true the material will use a solid color to render a skybox. When false a user
+		 *						provided texture will be used instead.
+		 */
+		static SkyboxMat* getVariation(bool color);
 	private:
 	private:
 		GpuParamTexture mSkyTextureParam;
 		GpuParamTexture mSkyTextureParam;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
+
+		static ShaderVariation VAR_Texture;
+		static ShaderVariation VAR_Color;
 	};
 	};
 
 
 	/** Data shared between RENDERER_VIEW_DESC and RendererViewProperties */
 	/** Data shared between RENDERER_VIEW_DESC and RendererViewProperties */
@@ -78,10 +91,6 @@ namespace bs { namespace ct
 		float farPlane;
 		float farPlane;
 		ProjectionType projType;
 		ProjectionType projType;
 
 
-		bool isOverlay : 1;
-		bool isHDR : 1;
-		bool noLighting : 1;
-		bool noShadows : 1;
 		bool triggerCallbacks : 1;
 		bool triggerCallbacks : 1;
 		bool runPostProcessing : 1;
 		bool runPostProcessing : 1;
 		bool renderingReflections : 1;
 		bool renderingReflections : 1;
@@ -177,8 +186,8 @@ namespace bs { namespace ct
 		/** Sets state reduction mode that determines how do render queues group & sort renderables. */
 		/** Sets state reduction mode that determines how do render queues group & sort renderables. */
 		void setStateReductionMode(StateReduction reductionMode);
 		void setStateReductionMode(StateReduction reductionMode);
 
 
-		/** Updates the internal camera post-processing data. */
-		void setPostProcessSettings(const SPtr<PostProcessSettings>& ppSettings);
+		/** Updates the internal camera render settings. */
+		void setRenderSettings(const SPtr<RenderSettings>& settings);
 
 
 		/** Updates the internal information with a new view transform. */
 		/** Updates the internal information with a new view transform. */
 		void setTransform(const Vector3& origin, const Vector3& direction, const Matrix4& view,
 		void setTransform(const Vector3& origin, const Vector3& direction, const Matrix4& view,
@@ -193,20 +202,12 @@ namespace bs { namespace ct
 		/** Returns the scene camera this object is based of. This can be null for manually constructed renderer cameras. */
 		/** Returns the scene camera this object is based of. This can be null for manually constructed renderer cameras. */
 		Camera* getSceneCamera() const { return mCamera; }
 		Camera* getSceneCamera() const { return mCamera; }
 
 
-		/** 
-		 * Prepares render targets for rendering. When done call endFrame().
-		 *
-		 * @param[in]	useGBuffer			Set to true if you will be rendering to internal render targets containing the
-		 *									GBuffer (retrieved via getRenderTargets()).
-		 */
-		void beginFrame(bool useGBuffer);
+		/** Prepares render targets for rendering. When done call endFrame(). */
+		void beginFrame();
 
 
 		/** Ends rendering and frees any acquired resources. */
 		/** Ends rendering and frees any acquired resources. */
 		void endFrame();
 		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 
 		 * 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.
 		 * or object transforms changed since the last time it was called.
@@ -219,6 +220,9 @@ namespace bs { namespace ct
 		 */
 		 */
 		const SPtr<RenderQueue>& getTransparentQueue() const { return mTransparentQueue; }
 		const SPtr<RenderQueue>& getTransparentQueue() const { return mTransparentQueue; }
 
 
+		/** Returns the compositor in charge of rendering for this view. */
+		const RenderCompositor& getCompositor() const { return mCompositor; }
+
 		/**
 		/**
 		 * Populates view render queues by determining visible renderable objects. 
 		 * Populates view render queues by determining visible renderable objects. 
 		 *
 		 *
@@ -275,14 +279,14 @@ namespace bs { namespace ct
 		/** Returns the visibility mask calculated with the last call to determineVisible(). */
 		/** Returns the visibility mask calculated with the last call to determineVisible(). */
 		const VisibilityInfo& getVisibilityMasks() const { return mVisibility; }
 		const VisibilityInfo& getVisibilityMasks() const { return mVisibility; }
 
 
-		/** 
-		 * Returns a structure containing information about post-processing effects. This structure will be modified and
-		 * maintained by the post-processing system.
-		 */
-		PostProcessInfo& getPPInfo() { return mPostProcessInfo; }
+		/** Returns per-view settings that control rendering. */
+		const RenderSettings& getRenderSettings() const { return *mRenderSettings; }
 
 
-		/** @copydoc getPPInfo() */
-		const PostProcessInfo& getPPInfo() const { return mPostProcessInfo; }
+		/**
+		 * Retrieves a hash value that is updated whenever render settings change. This can be used by external systems
+		 * to detect when they need to update.
+		 */
+		UINT64 getRenderSettingsHash() const { return mRenderSettingsHash; }
 
 
 		/** Updates the GPU buffer containing per-view information, with the latest internal data. */
 		/** Updates the GPU buffer containing per-view information, with the latest internal data. */
 		void updatePerViewBuffer();
 		void updatePerViewBuffer();
@@ -290,6 +294,15 @@ namespace bs { namespace ct
 		/** Returns a buffer that stores per-view parameters. */
 		/** Returns a buffer that stores per-view parameters. */
 		SPtr<GpuParamBlockBuffer> getPerViewBuffer() const { return mParamBuffer; }
 		SPtr<GpuParamBlockBuffer> getPerViewBuffer() const { return mParamBuffer; }
 
 
+		/** 
+		 * Returns information about visible lights, in the form of a light grid, used for forward rendering. Only valid
+		 * after a call to updateLightGrid().
+		 */
+		const LightGrid& getLightGrid() const { return mLightGrid; }
+
+		/** Updates the light grid used for forward rendering. */
+		void updateLightGrid(const VisibleLightData& visibleLightData, const VisibleReflProbeData& visibleReflProbeData);
+
 		/**
 		/**
 		 * Extracts the necessary values from the projection matrix that allow you to transform device Z value (range [0, 1]
 		 * Extracts the necessary values from the projection matrix that allow you to transform device Z value (range [0, 1]
 		 * into view Z value.
 		 * into view Z value.
@@ -323,20 +336,21 @@ namespace bs { namespace ct
 		SPtr<RenderQueue> mOpaqueQueue;
 		SPtr<RenderQueue> mOpaqueQueue;
 		SPtr<RenderQueue> mTransparentQueue;
 		SPtr<RenderQueue> mTransparentQueue;
 
 
-		SPtr<RenderTargets> mRenderTargets;
-		PostProcessInfo mPostProcessInfo;
-		bool mUsingGBuffer;
+		RenderCompositor mCompositor;
+		SPtr<RenderSettings> mRenderSettings;
+		UINT32 mRenderSettingsHash;
 
 
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		VisibilityInfo mVisibility;
 		VisibilityInfo mVisibility;
+		LightGrid mLightGrid;
 	};
 	};
 
 
 	/** Contains one or multiple RendererView%s that are in some way related. */
 	/** Contains one or multiple RendererView%s that are in some way related. */
 	class RendererViewGroup
 	class RendererViewGroup
 	{
 	{
 	public:
 	public:
-		RendererViewGroup() {}
-		RendererViewGroup(RendererView** views, UINT32 numViews);
+		RendererViewGroup();
+		RendererViewGroup(RendererView** views, UINT32 numViews, UINT32 shadowMapSize);
 
 
 		/** 
 		/** 
 		 * Updates the internal list of views. This is more efficient than always constructing a new instance of this class
 		 * Updates the internal list of views. This is more efficient than always constructing a new instance of this class
@@ -357,6 +371,24 @@ namespace bs { namespace ct
 		 */
 		 */
 		const VisibilityInfo& getVisibilityInfo() const { return mVisibility; }
 		const VisibilityInfo& getVisibilityInfo() const { return mVisibility; }
 
 
+		/**
+		 * Returns information about lights visible from this group of views. Only valid after a call to 
+		 * determineVisibility().
+		 */
+		const VisibleLightData& getVisibleLightData() const { return mVisibleLightData; }
+
+		/**
+		 * Returns information about refl. probes visible from this group of views. Only valid after a call to 
+		 * determineVisibility().
+		 */
+		const VisibleReflProbeData& getVisibleReflProbeData() const { return mVisibleReflProbeData; }
+
+		/** Returns the object responsible for rendering shadows for this view group. */
+		ShadowRendering& getShadowRenderer() { return mShadowRenderer; }
+
+		/** Returns the object responsible for rendering shadows for this view group. */
+		const ShadowRendering& getShadowRenderer() const { return mShadowRenderer; }
+
 		/** 
 		/** 
 		 * Updates visibility information for the provided scene objects, from the perspective of all views in this group,
 		 * Updates visibility information for the provided scene objects, from the perspective of all views in this group,
 		 * and updates the render queues of each individual view. Use getVisibilityInfo() to retrieve the calculated
 		 * and updates the render queues of each individual view. Use getVisibilityInfo() to retrieve the calculated
@@ -367,6 +399,15 @@ namespace bs { namespace ct
 	private:
 	private:
 		Vector<RendererView*> mViews;
 		Vector<RendererView*> mViews;
 		VisibilityInfo mVisibility;
 		VisibilityInfo mVisibility;
+
+		VisibleLightData mVisibleLightData;
+		VisibleReflProbeData mVisibleReflProbeData;
+
+		// Note: Ideally we would want to keep this global, so all views share it. This way each view group renders its
+		// own set of shadows, but there might be shadows that are shared, and therefore we could avoid rendering them
+		// multiple times. Since non-primary view groups are used for pre-processing tasks exclusively (at the moment) 
+		// this isn't an issue right now.
+		ShadowRendering mShadowRenderer;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 57 - 93
Source/RenderBeast/Include/BsShadowRendering.h

@@ -100,8 +100,7 @@ namespace bs { namespace ct
 	extern ShadowProjectVertParamsDef gShadowProjectVertParamsDef;
 	extern ShadowProjectVertParamsDef gShadowProjectVertParamsDef;
 
 
 	/** Material used for populating the stencil buffer when projecting non-omnidirectional shadows. */
 	/** Material used for populating the stencil buffer when projecting non-omnidirectional shadows. */
-	template<bool Directional, bool ZFailStencil>
-	class ShadowProjectStencilMat : public RendererMaterial<ShadowProjectStencilMat<Directional, ZFailStencil>>
+	class ShadowProjectStencilMat : public RendererMaterial<ShadowProjectStencilMat>
 	{
 	{
 		RMAT_DEF("ShadowProjectStencil.bsl");
 		RMAT_DEF("ShadowProjectStencil.bsl");
 
 
@@ -111,29 +110,22 @@ namespace bs { namespace ct
 		/** Binds the material and its parameters to the pipeline. */
 		/** Binds the material and its parameters to the pipeline. */
 		void bind(const SPtr<GpuParamBlockBuffer>& perCamera);
 		void bind(const SPtr<GpuParamBlockBuffer>& perCamera);
 
 
-	private:
-		SPtr<GpuParamBlockBuffer> mVertParams;
-	};
-
-	/** Contains all variations of the ShadowProjectStencilMat material. */
-	class ShadowProjectStencilMaterials
-	{
-	public:
-		/** 
-		 * Binds a shader that can be used for populating the stencil buffer during non-omnidirectional shadow rendering. 
+		/** Returns the material variation matching the provided parameters.
 		 *
 		 *
 		 * @param[in]	directional		Set to true if shadows from a directional light are being rendered.
 		 * @param[in]	directional		Set to true if shadows from a directional light are being rendered.
 		 * @param[in]	useZFailStencil	If true the material will use z-fail operation to modify the stencil buffer. If 
 		 * @param[in]	useZFailStencil	If true the material will use z-fail operation to modify the stencil buffer. If 
 		 *								false z-pass will be used instead. Z-pass is a more performant alternative as it
 		 *								false z-pass will be used instead. Z-pass is a more performant alternative as it
 		 *								doesn't disable hi-z optimization, but it cannot handle the case when the viewer is
 		 *								doesn't disable hi-z optimization, but it cannot handle the case when the viewer is
 		 *								inside the drawn geometry.
 		 *								inside the drawn geometry.
-		 * @param[in]	perCamera		Buffer containing information about the current view.
 		 */
 		 */
-		void bind(bool directional, bool useZFailStencil, const SPtr<GpuParamBlockBuffer>& perCamera);
+		static ShadowProjectStencilMat* getVariation(bool directional, bool useZFailStencil);
 	private:
 	private:
-		ShadowProjectStencilMat<true, true> mTT;
-		ShadowProjectStencilMat<false, true> mFT;
-		ShadowProjectStencilMat<false, false> mFF;
+		SPtr<GpuParamBlockBuffer> mVertParams;
+
+		static ShaderVariation VAR_Dir_ZFailStencil;
+		static ShaderVariation VAR_Dir_NoZFailStencil;
+		static ShaderVariation VAR_NoDir_ZFailStencil;
+		static ShaderVariation VAR_NoDir_NoZFailStencil;
 	};
 	};
 
 
 	/** Common parameters used by the shadow projection materials. */
 	/** Common parameters used by the shadow projection materials. */
@@ -141,9 +133,9 @@ namespace bs { namespace ct
 	{
 	{
 		ShadowProjectParams(const Light& light, const SPtr<Texture>& shadowMap, UINT32 shadowMapFace,
 		ShadowProjectParams(const Light& light, const SPtr<Texture>& shadowMap, UINT32 shadowMapFace,
 			const SPtr<GpuParamBlockBuffer>& shadowParams, const SPtr<GpuParamBlockBuffer>& perCameraParams,
 			const SPtr<GpuParamBlockBuffer>& shadowParams, const SPtr<GpuParamBlockBuffer>& perCameraParams,
-			const RenderTargets& renderTargets)
+			GBufferInput gbuffer)
 			: light(light), shadowMap(shadowMap), shadowMapFace(shadowMapFace), shadowParams(shadowParams)
 			: light(light), shadowMap(shadowMap), shadowMapFace(shadowMapFace), shadowParams(shadowParams)
-			, perCamera(perCameraParams), renderTargets(renderTargets)
+			, perCamera(perCameraParams), gbuffer(gbuffer)
 		{ }
 		{ }
 
 
 		/** Light which is casting the shadow. */
 		/** Light which is casting the shadow. */
@@ -162,7 +154,7 @@ namespace bs { namespace ct
 		const SPtr<GpuParamBlockBuffer>& perCamera;
 		const SPtr<GpuParamBlockBuffer>& perCamera;
 
 
 		/** Contains the GBuffer textures. */
 		/** Contains the GBuffer textures. */
-		const RenderTargets& renderTargets;
+		GBufferInput gbuffer;
 	};
 	};
 
 
 	BS_PARAM_BLOCK_BEGIN(ShadowProjectParamsDef)
 	BS_PARAM_BLOCK_BEGIN(ShadowProjectParamsDef)
@@ -178,8 +170,7 @@ namespace bs { namespace ct
 	extern ShadowProjectParamsDef gShadowProjectParamsDef;
 	extern ShadowProjectParamsDef gShadowProjectParamsDef;
 
 
 	/** Material used for projecting depth into a shadow accumulation buffer for non-omnidirectional shadow maps. */
 	/** Material used for projecting depth into a shadow accumulation buffer for non-omnidirectional shadow maps. */
-	template<int ShadowQuality, bool Directional, bool MSAA>
-	class ShadowProjectMat : public RendererMaterial<ShadowProjectMat<ShadowQuality, Directional, MSAA>>
+	class ShadowProjectMat : public RendererMaterial<ShadowProjectMat>
 	{
 	{
 		RMAT_DEF("ShadowProject.bsl");
 		RMAT_DEF("ShadowProject.bsl");
 
 
@@ -189,6 +180,13 @@ namespace bs { namespace ct
 		/** Binds the material and its parameters to the pipeline. */
 		/** Binds the material and its parameters to the pipeline. */
 		void bind(const ShadowProjectParams& params);
 		void bind(const ShadowProjectParams& params);
 
 
+		/** Returns the material variation matching the provided parameters.
+		 *
+		 * @param[in]	quality			Quality of the shadow filtering to use. In range [1, 4].
+		 * @param[in]	directional		True if rendering a shadow from a directional light.
+		 * @param[in]	MSAA			True if the GBuffer contains per-sample data.
+		 */
+		static ShadowProjectMat* getVariation(UINT32 quality, bool directional, bool MSAA);
 	private:
 	private:
 		SPtr<SamplerState> mSamplerState;
 		SPtr<SamplerState> mSamplerState;
 		SPtr<GpuParamBlockBuffer> mVertParams;
 		SPtr<GpuParamBlockBuffer> mVertParams;
@@ -197,35 +195,19 @@ namespace bs { namespace ct
 
 
 		GpuParamTexture mShadowMapParam;
 		GpuParamTexture mShadowMapParam;
 		GpuParamSampState mShadowSamplerParam;
 		GpuParamSampState mShadowSamplerParam;
-	};
 
 
-	/** Contains all variations of the ShadowProjectMat material. */
-	class ShadowProjectMaterials
-	{
-	public:
-		/** 
-		 * Binds the appropriate variation of the ShadowProjectMat based on the provided parameters. 
-		 * 
-		 * @param[in]	quality			Quality of the shadow filtering to use. In range [1, 4].
-		 * @param[in]	directional		True if rendering a shadow from a directional light.
-		 * @param[in]	MSAA			True if the GBuffer contains per-sample data.
-		 * @param[in]	params			Parameters to be passed along to the material.
-		 */
-		void bind(UINT32 quality, bool directional, bool MSAA, const ShadowProjectParams& params);
-	private:
-#define MAT_MEMBERS(QUALITY)											\
-		ShadowProjectMat<QUALITY, true, true> mMat##QUALITY##TT;		\
-		ShadowProjectMat<QUALITY, true, false> mMat##QUALITY##TF;		\
-		ShadowProjectMat<QUALITY, false, true> mMat##QUALITY##FT;		\
-		ShadowProjectMat<QUALITY, false, false> mMat##QUALITY##FF;
+#define VARIATION(QUALITY)											\
+		static ShaderVariation VAR_Q##QUALITY##_Dir_MSAA;			\
+		static ShaderVariation VAR_Q##QUALITY##_Dir_NoMSAA;			\
+		static ShaderVariation VAR_Q##QUALITY##_NoDir_MSAA;			\
+		static ShaderVariation VAR_Q##QUALITY##_NoDir_NoMSAA;		\
 	
 	
-		MAT_MEMBERS(1)
-		MAT_MEMBERS(2)
-		MAT_MEMBERS(3)
-		MAT_MEMBERS(4)
-
-#undef MAT_MEMBERS
+		VARIATION(1)
+		VARIATION(2)
+		VARIATION(3)
+		VARIATION(4)
 
 
+#undef VARIATION 
 	};
 	};
 
 
 	BS_PARAM_BLOCK_BEGIN(ShadowProjectOmniParamsDef)
 	BS_PARAM_BLOCK_BEGIN(ShadowProjectOmniParamsDef)
@@ -239,8 +221,7 @@ namespace bs { namespace ct
 	extern ShadowProjectOmniParamsDef gShadowProjectOmniParamsDef;
 	extern ShadowProjectOmniParamsDef gShadowProjectOmniParamsDef;
 
 
 	/** Material used for projecting depth into a shadow accumulation buffer for omnidirectional shadow maps. */
 	/** Material used for projecting depth into a shadow accumulation buffer for omnidirectional shadow maps. */
-	template<int ShadowQuality, bool Inside, bool MSAA>
-	class ShadowProjectOmniMat : public RendererMaterial<ShadowProjectOmniMat<ShadowQuality, Inside, MSAA>>
+	class ShadowProjectOmniMat : public RendererMaterial<ShadowProjectOmniMat>
 	{
 	{
 		RMAT_DEF("ShadowProjectOmni.bsl");
 		RMAT_DEF("ShadowProjectOmni.bsl");
 
 
@@ -250,6 +231,13 @@ namespace bs { namespace ct
 		/** Binds the material and its parameters to the pipeline. */
 		/** Binds the material and its parameters to the pipeline. */
 		void bind(const ShadowProjectParams& params);
 		void bind(const ShadowProjectParams& params);
 
 
+		/** Returns the material variation matching the provided parameters.
+		 *
+		 * @param[in]	quality			Quality of the shadow filtering to use. In range [1, 4].
+		 * @param[in]	inside			True if the viewer is inside the light volume.
+		 * @param[in]	MSAA			True if the GBuffer contains per-sample data.
+		 */
+		static ShadowProjectOmniMat* getVariation(UINT32 quality, bool inside, bool MSAA);
 	private:
 	private:
 		SPtr<SamplerState> mSamplerState;
 		SPtr<SamplerState> mSamplerState;
 		SPtr<GpuParamBlockBuffer> mVertParams;
 		SPtr<GpuParamBlockBuffer> mVertParams;
@@ -258,35 +246,19 @@ namespace bs { namespace ct
 
 
 		GpuParamTexture mShadowMapParam;
 		GpuParamTexture mShadowMapParam;
 		GpuParamSampState mShadowSamplerParam;
 		GpuParamSampState mShadowSamplerParam;
-	};
 
 
-	/** Contains all variations of the ShadowProjectOmniMat material. */
-	class ShadowProjectOmniMaterials
-	{
-	public:
-		/** 
-		 * Binds the appropriate variation of the ShadowProjectOmniMat based on the provided parameters. 
-		 * 
-		 * @param[in]	quality			Quality of the shadow filtering to use. In range [1, 4].
-		 * @param[in]	inside			True if the viewer is inside the light volume.
-		 * @param[in]	MSAA			True if the GBuffer contains per-sample data.
-		 * @param[in]	params			Parameters to be passed along to the material.
-		 */
-		void bind(UINT32 quality, bool inside, bool MSAA, const ShadowProjectParams& params);
-	private:
-#define MAT_MEMBERS(QUALITY)												\
-		ShadowProjectOmniMat<QUALITY, true, true> mMat##QUALITY##TT;		\
-		ShadowProjectOmniMat<QUALITY, true, false> mMat##QUALITY##TF;		\
-		ShadowProjectOmniMat<QUALITY, false, true> mMat##QUALITY##FT;		\
-		ShadowProjectOmniMat<QUALITY, false, false> mMat##QUALITY##FF;
+#define VARIATION(QUALITY)											\
+		static ShaderVariation VAR_Q##QUALITY##_Inside_MSAA;		\
+		static ShaderVariation VAR_Q##QUALITY##_Inside_NoMSAA;		\
+		static ShaderVariation VAR_Q##QUALITY##_Outside_MSAA;		\
+		static ShaderVariation VAR_Q##QUALITY##_Outside_NoMSAA;		\
 	
 	
-		MAT_MEMBERS(1)
-		MAT_MEMBERS(2)
-		MAT_MEMBERS(3)
-		MAT_MEMBERS(4)
-
-#undef MAT_MEMBERS
+		VARIATION(1)
+		VARIATION(2)
+		VARIATION(3)
+		VARIATION(4)
 
 
+#undef VARIATION 
 	};
 	};
 
 
 	/** Pixel format used for rendering and storing shadow maps. */
 	/** Pixel format used for rendering and storing shadow maps. */
@@ -435,7 +407,7 @@ namespace bs { namespace ct
 	};
 	};
 
 
 	/** Provides functionality for rendering shadow maps. */
 	/** Provides functionality for rendering shadow maps. */
-	class ShadowRendering : public Module<ShadowRendering>
+	class ShadowRendering
 	{
 	{
 		/** Contains information required for generating a shadow map for a specific light. */
 		/** Contains information required for generating a shadow map for a specific light. */
 		struct ShadowMapOptions
 		struct ShadowMapOptions
@@ -461,8 +433,8 @@ namespace bs { namespace ct
 		 * Renders shadow occlusion values for the specified light, into the currently bound render target. 
 		 * Renders shadow occlusion values for the specified light, into the currently bound render target. 
 		 * The system uses shadow maps rendered by renderShadowMaps().
 		 * The system uses shadow maps rendered by renderShadowMaps().
 		 */
 		 */
-		void renderShadowOcclusion(const RendererScene& scene, UINT32 shadowQuality, const RendererLight& light,
-			UINT32 viewIdx);
+		void renderShadowOcclusion(const SceneInfo& sceneInfo, UINT32 shadowQuality, const RendererLight& light,
+			UINT32 viewIdx, GBufferInput gbuffer) const;
 
 
 		/** Changes the default shadow map size. Will cause all shadow maps to be rebuilt. */
 		/** Changes the default shadow map size. Will cause all shadow maps to be rebuilt. */
 		void setShadowMapSize(UINT32 size);
 		void setShadowMapSize(UINT32 size);
@@ -502,13 +474,13 @@ namespace bs { namespace ct
 		 * @param[in]	far			Location of the far plane, in NDC.
 		 * @param[in]	far			Location of the far plane, in NDC.
 		 * @param[in]	drawNear	If disabled, only the far plane will be drawn.
 		 * @param[in]	drawNear	If disabled, only the far plane will be drawn.
 		 */
 		 */
-		void drawNearFarPlanes(float near, float far, bool drawNear = true);
+		void drawNearFarPlanes(float near, float far, bool drawNear = true) const;
 
 
 		/** 
 		/** 
 		 * Draws a frustum mesh using the provided vertices as its corners. Corners should be in the order specified
 		 * Draws a frustum mesh using the provided vertices as its corners. Corners should be in the order specified
 		 * by AABox::Corner enum.
 		 * by AABox::Corner enum.
 		 */
 		 */
-		void drawFrustum(const std::array<Vector3, 8>& corners);
+		void drawFrustum(const std::array<Vector3, 8>& corners) const;
 
 
 		/**
 		/**
 		 * Calculates optimal shadow quality based on the quality set in the options and the actual shadow map resolution.
 		 * Calculates optimal shadow quality based on the quality set in the options and the actual shadow map resolution.
@@ -582,14 +554,6 @@ namespace bs { namespace ct
 		/** Percent of the length of a single cascade in a CSM, in which to fade out the cascade. */
 		/** Percent of the length of a single cascade in a CSM, in which to fade out the cascade. */
 		static const float CASCADE_FRACTION_FADE;
 		static const float CASCADE_FRACTION_FADE;
 
 
-		ShadowDepthNormalMat mDepthNormalMat;
-		ShadowDepthCubeMat mDepthCubeMat;
-		ShadowDepthDirectionalMat mDepthDirectionalMat;
-
-		ShadowProjectStencilMaterials mProjectStencilMaterials;
-		ShadowProjectMaterials mProjectMaterials;
-		ShadowProjectOmniMaterials mProjectOmniMaterials;
-
 		UINT32 mShadowMapSize;
 		UINT32 mShadowMapSize;
 
 
 		Vector<ShadowMapAtlas> mDynamicShadowMaps;
 		Vector<ShadowMapAtlas> mDynamicShadowMaps;
@@ -605,12 +569,12 @@ namespace bs { namespace ct
 		SPtr<VertexDeclaration> mPositionOnlyVD;
 		SPtr<VertexDeclaration> mPositionOnlyVD;
 
 
 		// Mesh information used for drawing near & far planes
 		// Mesh information used for drawing near & far planes
-		SPtr<IndexBuffer> mPlaneIB;
-		SPtr<VertexBuffer> mPlaneVB;
+		mutable SPtr<IndexBuffer> mPlaneIB;
+		mutable SPtr<VertexBuffer> mPlaneVB;
 
 
 		// Mesh information used for drawing a shadow frustum
 		// Mesh information used for drawing a shadow frustum
-		SPtr<IndexBuffer> mFrustumIB;
-		SPtr<VertexBuffer> mFrustumVB;
+		mutable SPtr<IndexBuffer> mFrustumIB;
+		mutable SPtr<VertexBuffer> mFrustumVB;
 
 
 		Vector<bool> mRenderableVisibility; // Transient
 		Vector<bool> mRenderableVisibility; // Transient
 		Vector<ShadowMapOptions> mSpotLightShadowOptions; // Transient
 		Vector<ShadowMapOptions> mSpotLightShadowOptions; // Transient

+ 21 - 14
Source/RenderBeast/Include/BsStandardDeferredLighting.h

@@ -23,8 +23,7 @@ namespace bs { namespace ct {
 	extern PerLightParamDef gPerLightParamDef;
 	extern PerLightParamDef gPerLightParamDef;
 
 
 	/** Shader that renders directional light sources during deferred rendering light pass. */
 	/** Shader that renders directional light sources during deferred rendering light pass. */
-	template<bool MSAA>
-	class DirectionalLightMat : public RendererMaterial<DirectionalLightMat<MSAA>>
+	class DirectionalLightMat : public RendererMaterial<DirectionalLightMat>
 	{
 	{
 		RMAT_DEF("DeferredDirectionalLight.bsl");
 		RMAT_DEF("DeferredDirectionalLight.bsl");
 
 
@@ -32,18 +31,24 @@ namespace bs { namespace ct {
 		DirectionalLightMat();
 		DirectionalLightMat();
 
 
 		/** Binds the material for rendering and sets up any global parameters. */
 		/** Binds the material for rendering and sets up any global parameters. */
-		void bind(const RenderTargets& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera);
+		void bind(const GBufferInput& gBufferInput, const SPtr<Texture>& lightOcclusion, 
+			const SPtr<GpuParamBlockBuffer>& perCamera);
 
 
 		/** Updates the per-light buffers used by the material. */
 		/** Updates the per-light buffers used by the material. */
 		void setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight);
 		void setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight);
+		
+		/** Returns the material variation matching the provided parameters. */
+		static DirectionalLightMat* getVariation(bool msaa);
 	private:
 	private:
 		GBufferParams mGBufferParams;
 		GBufferParams mGBufferParams;
 		GpuParamTexture mLightOcclusionTexParam;
 		GpuParamTexture mLightOcclusionTexParam;
+
+		static ShaderVariation VAR_MSAA;
+		static ShaderVariation VAR_NoMSAA;
 	};
 	};
 
 
 	/** Shader that renders point (radial & spot) light sources during deferred rendering light pass. */
 	/** Shader that renders point (radial & spot) light sources during deferred rendering light pass. */
-	template<bool MSAA, bool InsideGeometry>
-	class PointLightMat : public RendererMaterial<PointLightMat<MSAA, InsideGeometry>>
+	class PointLightMat : public RendererMaterial<PointLightMat>
 	{
 	{
 		RMAT_DEF("DeferredPointLight.bsl");
 		RMAT_DEF("DeferredPointLight.bsl");
 
 
@@ -51,13 +56,22 @@ namespace bs { namespace ct {
 		PointLightMat();
 		PointLightMat();
 
 
 		/** Binds the material for rendering and sets up any global parameters. */
 		/** Binds the material for rendering and sets up any global parameters. */
-		void bind(const RenderTargets& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera);
+		void bind(const GBufferInput& gBufferInput, const SPtr<Texture>& lightOcclusion, 
+			const SPtr<GpuParamBlockBuffer>& perCamera);
 
 
 		/** Updates the per-light buffers used by the material. */
 		/** Updates the per-light buffers used by the material. */
 		void setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight);
 		void setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight);
+
+		/** Returns the material variation matching the provided parameters. */
+		static PointLightMat* getVariation(bool msaa, bool inside);
 	private:
 	private:
 		GBufferParams mGBufferParams;
 		GBufferParams mGBufferParams;
 		GpuParamTexture mLightOcclusionTexParam;
 		GpuParamTexture mLightOcclusionTexParam;
+
+		static ShaderVariation VAR_MSAA_Inside;
+		static ShaderVariation VAR_MSAA_Outside;
+		static ShaderVariation VAR_NoMSAA_Inside;
+		static ShaderVariation VAR_NoMSAA_Outside;
 	};
 	};
 
 
 	/** Provides functionality for standard (non-tiled) deferred rendering. */
 	/** Provides functionality for standard (non-tiled) deferred rendering. */
@@ -68,16 +82,9 @@ namespace bs { namespace ct {
 
 
 		/** Calculates lighting for the specified light, using the standard deferred renderer. */
 		/** Calculates lighting for the specified light, using the standard deferred renderer. */
 		void renderLight(LightType type, const RendererLight& light, const RendererView& view, 
 		void renderLight(LightType type, const RendererLight& light, const RendererView& view, 
-			const RenderTargets& renderTargets);
+			const GBufferInput& gBufferInput, const SPtr<Texture>& lightOcclusion);
 
 
 	private:
 	private:
 		SPtr<GpuParamBlockBuffer> mPerLightBuffer;
 		SPtr<GpuParamBlockBuffer> mPerLightBuffer;
-
-		PointLightMat<true, true> mPointLightMat_TT;
-		PointLightMat<true, false> mPointLightMat_TF;
-		PointLightMat<false, true> mPointLightMat_FT;
-		PointLightMat<false, false> mPointLightMat_FF;
-		DirectionalLightMat<true> mDirLightMat_T;
-		DirectionalLightMat<false> mDirLightMat_F;
 	};
 	};
 }}
 }}

+ 103 - 286
Source/RenderBeast/Source/BsImageBasedLighting.cpp

@@ -8,9 +8,9 @@
 #include "BsReflectionProbe.h"
 #include "BsReflectionProbe.h"
 #include "BsLightProbeCache.h"
 #include "BsLightProbeCache.h"
 #include "BsGpuParamsSet.h"
 #include "BsGpuParamsSet.h"
-#include "BsRenderTargets.h"
 #include "BsRenderBeast.h"
 #include "BsRenderBeast.h"
 #include "BsRendererUtility.h"
 #include "BsRendererUtility.h"
+#include "BsSkybox.h"
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
@@ -116,12 +116,6 @@ namespace bs { namespace ct
 		if (!optional || params->hasTexture(programType, "gSkyReflectionTex"))
 		if (!optional || params->hasTexture(programType, "gSkyReflectionTex"))
 		{
 		{
 			params->getTextureParam(programType, "gSkyReflectionTex", skyReflectionsTexParam);
 			params->getTextureParam(programType, "gSkyReflectionTex", skyReflectionsTexParam);
-
-			if(params->hasSamplerState(programType, "gSkyReflectionSamp"))
-				params->getSamplerStateParam(programType, "gSkyReflectionSamp", skyReflectionsSampParam);
-			else
-				params->getSamplerStateParam(programType, "gSkyReflectionTex", skyReflectionsSampParam);
-
 			params->getTextureParam(programType, "gSkyIrradianceTex", skyIrradianceTexParam);
 			params->getTextureParam(programType, "gSkyIrradianceTex", skyIrradianceTexParam);
 		}
 		}
 
 
@@ -129,14 +123,7 @@ namespace bs { namespace ct
 		if (!optional || params->hasTexture(programType, "gReflProbeCubemaps"))
 		if (!optional || params->hasTexture(programType, "gReflProbeCubemaps"))
 		{
 		{
 			params->getTextureParam(programType, "gReflProbeCubemaps", reflectionProbeCubemapsTexParam);
 			params->getTextureParam(programType, "gReflProbeCubemaps", reflectionProbeCubemapsTexParam);
-
-			if(params->hasSamplerState(programType, "gReflProbeSamp"))
-				params->getSamplerStateParam(programType, "gReflProbeSamp", reflectionProbeCubemapsSampParam);
-			else
-				params->getSamplerStateParam(programType, "gReflProbeCubemaps", reflectionProbeCubemapsSampParam);
-
 			params->getBufferParam(programType, "gReflectionProbes", reflectionProbesParam);
 			params->getBufferParam(programType, "gReflectionProbes", reflectionProbesParam);
-
 			params->getTextureParam(programType, "gPreintegratedEnvBRDF", preintegratedEnvBRDFParam);
 			params->getTextureParam(programType, "gPreintegratedEnvBRDF", preintegratedEnvBRDFParam);
 		}
 		}
 
 
@@ -149,15 +136,68 @@ namespace bs { namespace ct
 		reflProbeParamsBindingIdx = paramsSet->getParamBlockBufferIndex("ReflProbeParams");
 		reflProbeParamsBindingIdx = paramsSet->getParamBlockBufferIndex("ReflProbeParams");
 	}
 	}
 
 
+	ReflProbeParamBuffer::ReflProbeParamBuffer()
+	{
+		buffer = gReflProbeParamsParamDef.createBuffer();
+	}
+
+	void ReflProbeParamBuffer::populate(const SkyInfo& sky, const VisibleReflProbeData& probeData, 
+		const SPtr<Texture>& reflectionCubemaps, bool capturingReflections)
+	{
+		UINT32 skyReflectionsAvailable = 0;
+		UINT32 numSkyMips = 0;
+		if (sky.filteredReflections != nullptr)
+		{
+			numSkyMips = sky.filteredReflections->getProperties().getNumMipmaps() + 1;
+			skyReflectionsAvailable = 1;
+		}
+
+		float brightness = 1.0f;
+		if (sky.skybox != nullptr)
+			brightness = sky.skybox->getBrightness();
+
+		gReflProbeParamsParamDef.gSkyCubemapNumMips.set(buffer, numSkyMips);
+		gReflProbeParamsParamDef.gSkyCubemapAvailable.set(buffer, skyReflectionsAvailable);
+		gReflProbeParamsParamDef.gSkyBrightness.set(buffer, brightness);
+		gReflProbeParamsParamDef.gNumProbes.set(buffer, probeData.getNumProbes());
+
+		UINT32 numReflProbeMips = 0;
+		if (reflectionCubemaps != nullptr)
+			numReflProbeMips = reflectionCubemaps->getProperties().getNumMipmaps() + 1;
+
+		gReflProbeParamsParamDef.gReflCubemapNumMips.set(buffer, numReflProbeMips);
+		gReflProbeParamsParamDef.gUseReflectionMaps.set(buffer, capturingReflections ? 0 : 1);
+	}
+
+	ShaderVariation TiledDeferredImageBasedLightingMat::VAR_1MSAA = ShaderVariation({
+		ShaderVariation::Param("TILE_SIZE", TILE_SIZE),
+		ShaderVariation::Param("MSAA_COUNT", 1)
+	});
+
+	ShaderVariation TiledDeferredImageBasedLightingMat::VAR_2MSAA = ShaderVariation({
+		ShaderVariation::Param("TILE_SIZE", TILE_SIZE),
+		ShaderVariation::Param("MSAA_COUNT", 2)
+	});
+
+	ShaderVariation TiledDeferredImageBasedLightingMat::VAR_4MSAA = ShaderVariation({
+		ShaderVariation::Param("TILE_SIZE", TILE_SIZE),
+		ShaderVariation::Param("MSAA_COUNT", 4)
+	});
+
+	ShaderVariation TiledDeferredImageBasedLightingMat::VAR_8MSAA = ShaderVariation({
+		ShaderVariation::Param("TILE_SIZE", TILE_SIZE),
+		ShaderVariation::Param("MSAA_COUNT", 8)
+	});
+
 	// Note: Using larger tiles than in tiled deferred lighting since we use AABB for intersections, which is more
 	// Note: Using larger tiles than in tiled deferred lighting since we use AABB for intersections, which is more
 	// expensive to compute than frustums. This way we amortize the cost even though other parts of the shader might suffer
 	// expensive to compute than frustums. This way we amortize the cost even though other parts of the shader might suffer
 	// due to increased thread group load.
 	// due to increased thread group load.
-	const UINT32 TiledDeferredImageBasedLighting::TILE_SIZE = 32;
+	const UINT32 TiledDeferredImageBasedLightingMat::TILE_SIZE = 32;
 
 
-	TiledDeferredImageBasedLighting::TiledDeferredImageBasedLighting(const SPtr<Material>& material, 
-		const SPtr<GpuParamsSet>& paramsSet, UINT32 sampleCount)
-		:mSampleCount(sampleCount), mMaterial(material), mParamsSet(paramsSet)
+	TiledDeferredImageBasedLightingMat::TiledDeferredImageBasedLightingMat()
 	{
 	{
+		mSampleCount = mVariation.getUInt("MSAA_COUNT");
+
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 
 
 		params->getTextureParam(GPT_COMPUTE_PROGRAM, "gGBufferATex", mGBufferA);
 		params->getTextureParam(GPT_COMPUTE_PROGRAM, "gGBufferATex", mGBufferA);
@@ -176,48 +216,53 @@ namespace bs { namespace ct
 
 
 		mImageBasedParams.populate(mParamsSet, GPT_COMPUTE_PROGRAM, false, false);
 		mImageBasedParams.populate(mParamsSet, GPT_COMPUTE_PROGRAM, false, false);
 
 
-		mReflectionsParamBuffer = gReflProbeParamsParamDef.createBuffer();
-		mParamsSet->setParamBlockBuffer("ReflProbeParams", mReflectionsParamBuffer);
-
-		SAMPLER_STATE_DESC reflSamplerDesc;
-		reflSamplerDesc.magFilter = FO_LINEAR;
-		reflSamplerDesc.minFilter = FO_LINEAR;
-		reflSamplerDesc.mipFilter = FO_LINEAR;
-
-		mReflectionSamplerState = SamplerState::create(reflSamplerDesc);
+		mParamsSet->setParamBlockBuffer("ReflProbeParams", mReflProbeParamBuffer.buffer);
+	}
 
 
-		mImageBasedParams.skyReflectionsSampParam.set(mReflectionSamplerState);
-		mImageBasedParams.reflectionProbeCubemapsSampParam.set(mReflectionSamplerState);
+	void TiledDeferredImageBasedLightingMat::_initVariations(ShaderVariations& variations)
+	{
+		variations.add(VAR_1MSAA);
+		variations.add(VAR_2MSAA);
+		variations.add(VAR_4MSAA);
+		variations.add(VAR_8MSAA);
 	}
 	}
 
 
-	void TiledDeferredImageBasedLighting::execute(const SPtr<RenderTargets>& renderTargets,
-		const SPtr<GpuParamBlockBuffer>& perCamera, const SPtr<Texture>& preintegratedGF)
+	void TiledDeferredImageBasedLightingMat::execute(const RendererView& view, const SceneInfo& sceneInfo, 
+		const VisibleReflProbeData& probeData, const Inputs& inputs)
 	{
 	{
+		const RendererViewProperties& viewProps = view.getProperties();
+		UINT32 width = viewProps.viewRect.width;
+		UINT32 height = viewProps.viewRect.height;
+
 		Vector2I framebufferSize;
 		Vector2I framebufferSize;
-		framebufferSize[0] = renderTargets->getWidth();
-		framebufferSize[1] = renderTargets->getHeight();
+		framebufferSize[0] = width;
+		framebufferSize[1] = height;
 		gTiledImageBasedLightingParamDef.gFramebufferSize.set(mParamBuffer, framebufferSize);
 		gTiledImageBasedLightingParamDef.gFramebufferSize.set(mParamBuffer, framebufferSize);
 
 
+		mReflProbeParamBuffer.populate(sceneInfo.sky, probeData, sceneInfo.reflProbeCubemapsTex, 
+			viewProps.renderingReflections);
+
 		mParamBuffer->flushToGPU();
 		mParamBuffer->flushToGPU();
-		mReflectionsParamBuffer->flushToGPU();
+		mReflProbeParamBuffer.buffer->flushToGPU();
 
 
-		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));
+		mGBufferA.set(inputs.gbuffer.albedo);
+		mGBufferB.set(inputs.gbuffer.normals);
+		mGBufferC.set(inputs.gbuffer.roughMetal);
+		mGBufferDepth.set(inputs.gbuffer.depth);
 
 
-		mImageBasedParams.preintegratedEnvBRDFParam.set(preintegratedGF);
+		mImageBasedParams.preintegratedEnvBRDFParam.set(inputs.preIntegratedGF);
+		mImageBasedParams.reflectionProbesParam.set(probeData.getProbeBuffer());
+		mImageBasedParams.reflectionProbeCubemapsTexParam.set(sceneInfo.reflProbeCubemapsTex);
+		mImageBasedParams.skyReflectionsTexParam.set(sceneInfo.sky.filteredReflections);
+		mImageBasedParams.skyIrradianceTexParam.set(sceneInfo.sky.irradiance);
 
 
-		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
+		mParamsSet->setParamBlockBuffer("PerCamera", view.getPerViewBuffer(), true);
 
 
-		mInColorTextureParam.set(renderTargets->get(RTT_LightAccumulation));
+		mInColorTextureParam.set(inputs.lightAccumulation);
 		if (mSampleCount > 1)
 		if (mSampleCount > 1)
-			mOutputBufferParam.set(renderTargets->getSceneColorBuffer());
+			mOutputBufferParam.set(inputs.sceneColorBuffer);
 		else
 		else
-			mOutputTextureParam.set(renderTargets->get(RTT_SceneColor));
-
-		UINT32 width = renderTargets->getWidth();
-		UINT32 height = renderTargets->getHeight();
+			mOutputTextureParam.set(inputs.sceneColorTex);
 
 
 		UINT32 numTilesX = (UINT32)Math::ceilToInt(width / (float)TILE_SIZE);
 		UINT32 numTilesX = (UINT32)Math::ceilToInt(width / (float)TILE_SIZE);
 		UINT32 numTilesY = (UINT32)Math::ceilToInt(height / (float)TILE_SIZE);
 		UINT32 numTilesY = (UINT32)Math::ceilToInt(height / (float)TILE_SIZE);
@@ -228,247 +273,19 @@ namespace bs { namespace ct
 		RenderAPI::instance().dispatchCompute(numTilesX, numTilesY);
 		RenderAPI::instance().dispatchCompute(numTilesX, numTilesY);
 	}
 	}
 
 
-	void TiledDeferredImageBasedLighting::setReflectionProbes(const VisibleReflProbeData& probeData,
-		const SPtr<Texture>& reflectionCubemaps, bool capturingReflections)
-	{
-		mImageBasedParams.reflectionProbesParam.set(probeData.getProbeBuffer());
-		mImageBasedParams.reflectionProbeCubemapsTexParam.set(reflectionCubemaps);
-
-		gReflProbeParamsParamDef.gNumProbes.set(mReflectionsParamBuffer, probeData.getNumProbes());
-
-		UINT32 numMips = 0;
-		if (reflectionCubemaps != nullptr)
-			numMips = reflectionCubemaps->getProperties().getNumMipmaps() + 1;
-
-		gReflProbeParamsParamDef.gReflCubemapNumMips.set(mReflectionsParamBuffer, numMips);
-		gReflProbeParamsParamDef.gUseReflectionMaps.set(mReflectionsParamBuffer, capturingReflections ? 0 : 1);
-	}
-
-	void TiledDeferredImageBasedLighting::setSky(const SPtr<Texture>& skyReflections, const SPtr<Texture>& skyIrradiance,
-		float brightness)
-	{
-		mImageBasedParams.skyReflectionsTexParam.set(skyReflections);
-		mImageBasedParams.skyIrradianceTexParam.set(skyIrradiance);
-
-		UINT32 skyReflectionsAvailable = 0;
-		UINT32 numMips = 0;
-		if (skyReflections != nullptr)
-		{
-			numMips = skyReflections->getProperties().getNumMipmaps() + 1;
-			skyReflectionsAvailable = 1;
-		}
-
-		gReflProbeParamsParamDef.gSkyCubemapNumMips.set(mReflectionsParamBuffer, numMips);
-		gReflProbeParamsParamDef.gSkyCubemapAvailable.set(mReflectionsParamBuffer, skyReflectionsAvailable);
-		gReflProbeParamsParamDef.gSkyBrightness.set(mReflectionsParamBuffer, brightness);
-	}
-
-	// 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)
+	TiledDeferredImageBasedLightingMat* TiledDeferredImageBasedLightingMat::getVariation(UINT32 msaaCount)
 	{
 	{
-		// 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> TiledDeferredImageBasedLighting::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++)
+		switch(msaaCount)
 		{
 		{
-			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);
-			}
+		case 1:
+			return get(VAR_1MSAA);
+		case 2:
+			return get(VAR_2MSAA);
+		case 4:
+			return get(VAR_4MSAA);
+		case 8:
+		default:
+			return get(VAR_8MSAA);
 		}
 		}
-
-		texture->unlock();
-
-		return texture;
-	}
-
-	template<int MSAA_COUNT>
-	TTiledDeferredImageBasedLightingMat<MSAA_COUNT>::TTiledDeferredImageBasedLightingMat()
-		:mInternal(mMaterial, mParamsSet, MSAA_COUNT)
-	{
-
-	}
-
-	template<int MSAA_COUNT>
-	void TTiledDeferredImageBasedLightingMat<MSAA_COUNT>::_initDefines(ShaderDefines& defines)
-	{
-		defines.set("TILE_SIZE", TiledDeferredImageBasedLighting::TILE_SIZE);
-		defines.set("MSAA_COUNT", MSAA_COUNT);
-	}
-
-	template<int MSAA_COUNT>
-	void TTiledDeferredImageBasedLightingMat<MSAA_COUNT>::execute(const SPtr<RenderTargets>& gbuffer,
-		const SPtr<GpuParamBlockBuffer>& perCamera, const SPtr<Texture>& preintegratedGF)
-	{
-		mInternal.execute(gbuffer, perCamera, preintegratedGF);
-	}
-
-	template<int MSAA_COUNT>
-	void TTiledDeferredImageBasedLightingMat<MSAA_COUNT>::setReflectionProbes(const VisibleReflProbeData& probeData, 
-		const SPtr<Texture>& reflectionCubemaps, bool capturingReflections)
-	{
-		mInternal.setReflectionProbes(probeData, reflectionCubemaps, capturingReflections);
-	}
-
-	template<int MSAA_COUNT>
-	void TTiledDeferredImageBasedLightingMat<MSAA_COUNT>::setSky(const SPtr<Texture>& skyReflections,
-		const SPtr<Texture>& skyIrradiance, float brightness)
-	{
-		mInternal.setSky(skyReflections, skyIrradiance, brightness);
-	}
-
-	template<int MSAA_COUNT>
-	SPtr<GpuParamBlockBuffer> TTiledDeferredImageBasedLightingMat<MSAA_COUNT>::getReflectionsParamBuffer() const
-	{
-		return mInternal.getReflectionsParamBuffer();
-	}
-
-	template<int MSAA_COUNT>
-	SPtr<SamplerState> TTiledDeferredImageBasedLightingMat<MSAA_COUNT>::getReflectionsSamplerState() const
-	{
-		return mInternal.getReflectionsSamplerState();
-	}
-
-	TiledDeferredImageBasedLightingMaterials::TiledDeferredImageBasedLightingMaterials()
-	{
-		mInstances[0] = bs_new<TTiledDeferredImageBasedLightingMat<1>>();
-		mInstances[1] = bs_new<TTiledDeferredImageBasedLightingMat<2>>();
-		mInstances[2] = bs_new<TTiledDeferredImageBasedLightingMat<4>>();
-		mInstances[3] = bs_new<TTiledDeferredImageBasedLightingMat<8>>();
-	}
-
-	TiledDeferredImageBasedLightingMaterials::~TiledDeferredImageBasedLightingMaterials()
-	{
-		for (UINT32 i = 0; i < 4; i++)
-			bs_delete(mInstances[i]);
-	}
-
-	ITiledDeferredImageBasedLightingMat* TiledDeferredImageBasedLightingMaterials::get(UINT32 msaa)
-	{
-		if (msaa == 1)
-			return mInstances[0];
-		else if (msaa == 2)
-			return mInstances[1];
-		else if (msaa == 4)
-			return mInstances[2];
-		else
-			return mInstances[3];
 	}
 	}
-}}
+}}

+ 25 - 13
Source/RenderBeast/Source/BsLightGrid.cpp

@@ -5,7 +5,6 @@
 #include "BsGpuParamsSet.h"
 #include "BsGpuParamsSet.h"
 #include "BsRendererUtility.h"
 #include "BsRendererUtility.h"
 #include "BsRendererView.h"
 #include "BsRendererView.h"
-#include "BsRenderTargets.h"
 #include "BsLightRendering.h"
 #include "BsLightRendering.h"
 #include "BsImageBasedLighting.h"
 #include "BsImageBasedLighting.h"
 
 
@@ -47,9 +46,13 @@ namespace bs { namespace ct
 		mProbesCounterParam.set(mProbesCounter);
 		mProbesCounterParam.set(mProbesCounter);
 	}
 	}
 
 
-	void LightGridLLCreationMat::_initDefines(ShaderDefines& defines)
+	void LightGridLLCreationMat::_initVariations(ShaderVariations& variations)
 	{
 	{
-		defines.set("THREADGROUP_SIZE", THREADGROUP_SIZE);
+		ShaderVariation variation({
+			ShaderVariation::Param("THREADGROUP_SIZE", THREADGROUP_SIZE)
+		});
+
+		variations.add(variation);
 	}
 	}
 
 
 	void LightGridLLCreationMat::setParams(const Vector3I& gridSize, const SPtr<GpuParamBlockBuffer>& gridParams,
 	void LightGridLLCreationMat::setParams(const Vector3I& gridSize, const SPtr<GpuParamBlockBuffer>& gridParams,
@@ -161,9 +164,13 @@ namespace bs { namespace ct
 		mGridDataCounterParam.set(mGridDataCounter);
 		mGridDataCounterParam.set(mGridDataCounter);
 	}
 	}
 
 
-	void LightGridLLReductionMat::_initDefines(ShaderDefines& defines)
+	void LightGridLLReductionMat::_initVariations(ShaderVariations& variations)
 	{
 	{
-		defines.set("THREADGROUP_SIZE", THREADGROUP_SIZE);
+		ShaderVariation variation({
+			ShaderVariation::Param("THREADGROUP_SIZE", THREADGROUP_SIZE)
+		});
+
+		variations.add(variation);
 	}
 	}
 
 
 	void LightGridLLReductionMat::setParams(const Vector3I& gridSize, const SPtr<GpuParamBlockBuffer>& gridParams,
 	void LightGridLLReductionMat::setParams(const Vector3I& gridSize, const SPtr<GpuParamBlockBuffer>& gridParams,
@@ -245,8 +252,10 @@ namespace bs { namespace ct
 	void LightGrid::updateGrid(const RendererView& view, const VisibleLightData& lightData, const VisibleReflProbeData& probeData,
 	void LightGrid::updateGrid(const RendererView& view, const VisibleLightData& lightData, const VisibleReflProbeData& probeData,
 		bool noLighting)
 		bool noLighting)
 	{
 	{
-		UINT32 width = view.getRenderTargets()->getWidth();
-		UINT32 height = view.getRenderTargets()->getHeight();
+		const RendererViewProperties& viewProps = view.getProperties();
+
+		UINT32 width = viewProps.viewRect.width;
+		UINT32 height = viewProps.viewRect.height;
 
 
 		Vector3I gridSize;
 		Vector3I gridSize;
 		gridSize[0] = (width + CELL_XY_SIZE - 1) / CELL_XY_SIZE;
 		gridSize[0] = (width + CELL_XY_SIZE - 1) / CELL_XY_SIZE;
@@ -286,24 +295,27 @@ namespace bs { namespace ct
 		gLightGridParamDefDef.gMaxNumLightsPerCell.set(mGridParamBuffer, MAX_LIGHTS_PER_CELL);
 		gLightGridParamDefDef.gMaxNumLightsPerCell.set(mGridParamBuffer, MAX_LIGHTS_PER_CELL);
 		gLightGridParamDefDef.gGridPixelSize.set(mGridParamBuffer, Vector2I(CELL_XY_SIZE, CELL_XY_SIZE));
 		gLightGridParamDefDef.gGridPixelSize.set(mGridParamBuffer, Vector2I(CELL_XY_SIZE, CELL_XY_SIZE));
 
 
-		mLLCreationMat.setParams(gridSize, mGridParamBuffer, lightData.getLightBuffer(), probeData.getProbeBuffer());
-		mLLCreationMat.execute(view);
+		LightGridLLCreationMat* creationMat = LightGridLLCreationMat::get();
+		creationMat->setParams(gridSize, mGridParamBuffer, lightData.getLightBuffer(), probeData.getProbeBuffer());
+		creationMat->execute(view);
 
 
 		SPtr<GpuBuffer> lightLLHeads;
 		SPtr<GpuBuffer> lightLLHeads;
 		SPtr<GpuBuffer> lightLL;
 		SPtr<GpuBuffer> lightLL;
 		SPtr<GpuBuffer> probeLLHeads;
 		SPtr<GpuBuffer> probeLLHeads;
 		SPtr<GpuBuffer> probeLL;
 		SPtr<GpuBuffer> probeLL;
-		mLLCreationMat.getOutputs(lightLLHeads, lightLL, probeLLHeads, probeLL);
+		creationMat->getOutputs(lightLLHeads, lightLL, probeLLHeads, probeLL);
 
 
-		mLLReductionMat.setParams(gridSize, mGridParamBuffer, lightLLHeads, lightLL, probeLLHeads, probeLL);
-		mLLReductionMat.execute(view);
+		LightGridLLReductionMat* reductionMat = LightGridLLReductionMat::get();
+		reductionMat->setParams(gridSize, mGridParamBuffer, lightLLHeads, lightLL, probeLLHeads, probeLL);
+		reductionMat->execute(view);
 	}
 	}
 
 
 	void LightGrid::getOutputs(SPtr<GpuBuffer>& gridLightOffsetsAndSize, SPtr<GpuBuffer>& gridLightIndices,
 	void LightGrid::getOutputs(SPtr<GpuBuffer>& gridLightOffsetsAndSize, SPtr<GpuBuffer>& gridLightIndices,
 		SPtr<GpuBuffer>& gridProbeOffsetsAndSize, SPtr<GpuBuffer>& gridProbeIndices, 
 		SPtr<GpuBuffer>& gridProbeOffsetsAndSize, SPtr<GpuBuffer>& gridProbeIndices, 
 		SPtr<GpuParamBlockBuffer>& gridParams) const
 		SPtr<GpuParamBlockBuffer>& gridParams) const
 	{
 	{
-		mLLReductionMat.getOutputs(gridLightOffsetsAndSize, gridLightIndices, gridProbeOffsetsAndSize, gridProbeIndices);
+		LightGridLLReductionMat* reductionMat = LightGridLLReductionMat::get();
+		reductionMat->getOutputs(gridLightOffsetsAndSize, gridLightIndices, gridProbeOffsetsAndSize, gridProbeIndices);
 		gridParams = mGridParamBuffer;
 		gridParams = mGridParamBuffer;
 	}
 	}
 }}
 }}

+ 90 - 101
Source/RenderBeast/Source/BsLightRendering.cpp

@@ -4,7 +4,6 @@
 #include "BsMaterial.h"
 #include "BsMaterial.h"
 #include "BsShader.h"
 #include "BsShader.h"
 #include "BsRenderBeast.h"
 #include "BsRenderBeast.h"
-#include "BsRenderTargets.h"
 #include "BsGpuParams.h"
 #include "BsGpuParams.h"
 #include "BsGpuParamsSet.h"
 #include "BsGpuParamsSet.h"
 #include "BsGpuBuffer.h"
 #include "BsGpuBuffer.h"
@@ -117,12 +116,12 @@ namespace bs { namespace ct
 		material->setSamplerState("gDepthBufferSamp", ss);
 		material->setSamplerState("gDepthBufferSamp", ss);
 	}
 	}
 
 
-	void GBufferParams::bind(const RenderTargets& renderTargets)
+	void GBufferParams::bind(const GBufferInput& gbuffer)
 	{
 	{
-		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));
+		mGBufferA.set(gbuffer.albedo);
+		mGBufferB.set(gbuffer.normals);
+		mGBufferC.set(gbuffer.roughMetal);
+		mGBufferDepth.set(gbuffer.depth);
 
 
 		mMaterial->updateParamsSet(mParamsSet);
 		mMaterial->updateParamsSet(mParamsSet);
 	}
 	}
@@ -230,12 +229,34 @@ namespace bs { namespace ct
 		mLightDataTemp.clear();
 		mLightDataTemp.clear();
 	}
 	}
 
 
-	const UINT32 TiledDeferredLighting::TILE_SIZE = 16;
+	const UINT32 TiledDeferredLightingMat::TILE_SIZE = 16;
 
 
-	TiledDeferredLighting::TiledDeferredLighting(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet,
-													UINT32 sampleCount)
-		: mSampleCount(sampleCount), mMaterial(material), mParamsSet(paramsSet), mGBufferParams(material, paramsSet)
+	ShaderVariation TiledDeferredLightingMat::VAR_1MSAA = ShaderVariation({
+		ShaderVariation::Param("TILE_SIZE", TILE_SIZE),
+		ShaderVariation::Param("MSAA_COUNT", 1)
+	});
+
+	ShaderVariation TiledDeferredLightingMat::VAR_2MSAA = ShaderVariation({
+		ShaderVariation::Param("TILE_SIZE", TILE_SIZE),
+		ShaderVariation::Param("MSAA_COUNT", 2)
+	});
+
+	ShaderVariation TiledDeferredLightingMat::VAR_4MSAA = ShaderVariation({
+		ShaderVariation::Param("TILE_SIZE", TILE_SIZE),
+		ShaderVariation::Param("MSAA_COUNT", 4)
+	});
+
+	ShaderVariation TiledDeferredLightingMat::VAR_8MSAA = ShaderVariation({
+		ShaderVariation::Param("TILE_SIZE", TILE_SIZE),
+		ShaderVariation::Param("MSAA_COUNT", 8)
+	});
+
+
+	TiledDeferredLightingMat::TiledDeferredLightingMat()
+		:mGBufferParams(mMaterial, mParamsSet)
 	{
 	{
+		mSampleCount = mVariation.getUInt("MSAA_COUNT");
+
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 
 
 		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLights", mLightBufferParam);
 		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLights", mLightBufferParam);
@@ -250,15 +271,31 @@ namespace bs { namespace ct
 		mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
 		mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
 	}
 	}
 
 
-	void TiledDeferredLighting::execute(const SPtr<RenderTargets>& renderTargets, 
-		const SPtr<GpuParamBlockBuffer>& perCamera, bool noLighting, bool noShadows)
+	void TiledDeferredLightingMat::_initVariations(ShaderVariations& variations)
+	{
+		variations.add(VAR_1MSAA);
+		variations.add(VAR_2MSAA);
+		variations.add(VAR_4MSAA);
+		variations.add(VAR_8MSAA);
+	}
+
+	void TiledDeferredLightingMat::execute(const RendererView& view, const VisibleLightData& lightData, 
+		const GBufferInput& gbuffer, const SPtr<Texture>& lightAccumTex, const SPtr<GpuBuffer>& lightAccumBuffer)
 	{
 	{
+		const RendererViewProperties& viewProps = view.getProperties();
+		const RenderSettings& settings = view.getRenderSettings();
+
+		mLightBufferParam.set(lightData.getLightBuffer());
+
+		UINT32 width = viewProps.viewRect.width;
+		UINT32 height = viewProps.viewRect.height;
+
 		Vector2I framebufferSize;
 		Vector2I framebufferSize;
-		framebufferSize[0] = renderTargets->getWidth();
-		framebufferSize[1] = renderTargets->getHeight();
+		framebufferSize[0] = width;
+		framebufferSize[1] = height;
 		gTiledLightingParamDef.gFramebufferSize.set(mParamBuffer, framebufferSize);
 		gTiledLightingParamDef.gFramebufferSize.set(mParamBuffer, framebufferSize);
 
 
-		if (noLighting)
+		if (!settings.enableLighting)
 		{
 		{
 			Vector4I lightCounts;
 			Vector4I lightCounts;
 			lightCounts[0] = 0;
 			lightCounts[0] = 0;
@@ -275,32 +312,39 @@ namespace bs { namespace ct
 		}
 		}
 		else
 		else
 		{
 		{
-			if(noShadows)
-				gTiledLightingParamDef.gLightCounts.set(mParamBuffer, mLightCounts);
+			Vector4I unshadowedLightCounts;
+			unshadowedLightCounts[0] = lightData.getNumUnshadowedLights(LightType::Directional);
+			unshadowedLightCounts[1] = lightData.getNumUnshadowedLights(LightType::Radial);
+			unshadowedLightCounts[2] = lightData.getNumUnshadowedLights(LightType::Spot);
+			unshadowedLightCounts[3] = unshadowedLightCounts[0] + unshadowedLightCounts[1] + unshadowedLightCounts[2];
+
+			Vector4I lightCounts;
+			lightCounts[0] = lightData.getNumLights(LightType::Directional);
+			lightCounts[1] = lightData.getNumLights(LightType::Radial);
+			lightCounts[2] = lightData.getNumLights(LightType::Spot);
+			lightCounts[3] = lightCounts[0] + lightCounts[1] + lightCounts[2];
+
+			Vector2I lightStrides;
+			lightStrides[0] = lightCounts[0];
+			lightStrides[1] = lightStrides[0] + lightCounts[1];
+
+			if(!settings.enableShadows)
+				gTiledLightingParamDef.gLightCounts.set(mParamBuffer, lightCounts);
 			else
 			else
-				gTiledLightingParamDef.gLightCounts.set(mParamBuffer, mUnshadowedLightCounts);
+				gTiledLightingParamDef.gLightCounts.set(mParamBuffer, unshadowedLightCounts);
 
 
-			gTiledLightingParamDef.gLightStrides.set(mParamBuffer, mLightStrides);
+			gTiledLightingParamDef.gLightStrides.set(mParamBuffer, lightStrides);
 		}
 		}
 
 
 		mParamBuffer->flushToGPU();
 		mParamBuffer->flushToGPU();
 
 
-		mGBufferParams.bind(*renderTargets);
-		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
+		mGBufferParams.bind(gbuffer);
+		mParamsSet->setParamBlockBuffer("PerCamera", view.getPerViewBuffer(), true);
 
 
 		if (mSampleCount > 1)
 		if (mSampleCount > 1)
-		{
-			SPtr<GpuBuffer> lightAccumulation = renderTargets->getLightAccumulationBuffer();
-			mOutputBufferParam.set(lightAccumulation);
-		}
+			mOutputBufferParam.set(lightAccumBuffer);
 		else
 		else
-		{
-			SPtr<Texture> lightAccumulation = renderTargets->get(RTT_LightAccumulation);
-			mOutputTextureParam.set(lightAccumulation);
-		}
-
-		UINT32 width = renderTargets->getWidth();
-		UINT32 height = renderTargets->getHeight();
+			mOutputTextureParam.set(lightAccumTex);
 
 
 		UINT32 numTilesX = (UINT32)Math::ceilToInt(width / (float)TILE_SIZE);
 		UINT32 numTilesX = (UINT32)Math::ceilToInt(width / (float)TILE_SIZE);
 		UINT32 numTilesY = (UINT32)Math::ceilToInt(height / (float)TILE_SIZE);
 		UINT32 numTilesY = (UINT32)Math::ceilToInt(height / (float)TILE_SIZE);
@@ -311,75 +355,20 @@ namespace bs { namespace ct
 		RenderAPI::instance().dispatchCompute(numTilesX, numTilesY);
 		RenderAPI::instance().dispatchCompute(numTilesX, numTilesY);
 	}
 	}
 
 
-	void TiledDeferredLighting::setLights(const VisibleLightData& lightData)
+	TiledDeferredLightingMat* TiledDeferredLightingMat::getVariation(UINT32 msaaCount)
 	{
 	{
-		mLightBufferParam.set(lightData.getLightBuffer());
-
-		mUnshadowedLightCounts[0] = lightData.getNumUnshadowedLights(LightType::Directional);
-		mUnshadowedLightCounts[1] = lightData.getNumUnshadowedLights(LightType::Radial);
-		mUnshadowedLightCounts[2] = lightData.getNumUnshadowedLights(LightType::Spot);
-		mUnshadowedLightCounts[3] = mUnshadowedLightCounts[0] + mUnshadowedLightCounts[1] + mUnshadowedLightCounts[2];
-
-		mLightCounts[0] = lightData.getNumLights(LightType::Directional);
-		mLightCounts[1] = lightData.getNumLights(LightType::Radial);
-		mLightCounts[2] = lightData.getNumLights(LightType::Spot);
-		mLightCounts[3] = mLightCounts[0] + mLightCounts[1] + mLightCounts[2];
-
-		mLightStrides[0] = mLightCounts[0];
-		mLightStrides[1] = mLightStrides[0] + mLightCounts[1];
-	}
-
-	template<int MSAA_COUNT>
-	TTiledDeferredLightingMat<MSAA_COUNT>::TTiledDeferredLightingMat()
-		:mInternal(mMaterial, mParamsSet, MSAA_COUNT)
-	{
-
-	}
-
-	template<int MSAA_COUNT>
-	void TTiledDeferredLightingMat<MSAA_COUNT>::_initDefines(ShaderDefines& defines)
-	{
-		defines.set("TILE_SIZE", TiledDeferredLighting::TILE_SIZE);
-		defines.set("MSAA_COUNT", MSAA_COUNT);
-	}
-
-	template<int MSAA_COUNT>
-	void TTiledDeferredLightingMat<MSAA_COUNT>::execute(const SPtr<RenderTargets>& gbuffer,
-		const SPtr<GpuParamBlockBuffer>& perCamera, bool noLighting, bool noShadows)
-	{
-		mInternal.execute(gbuffer, perCamera, noLighting, noShadows);
-	}
-
-	template<int MSAA_COUNT>
-	void TTiledDeferredLightingMat<MSAA_COUNT>::setLights(const VisibleLightData& lightData)
-	{
-		mInternal.setLights(lightData);
-	}
-
-	TiledDeferredLightingMaterials::TiledDeferredLightingMaterials()
-	{
-		mInstances[0] = bs_new<TTiledDeferredLightingMat<1>>();
-		mInstances[1] = bs_new<TTiledDeferredLightingMat<2>>();
-		mInstances[2] = bs_new<TTiledDeferredLightingMat<4>>();
-		mInstances[3] = bs_new<TTiledDeferredLightingMat<8>>();
-	}
-
-	TiledDeferredLightingMaterials::~TiledDeferredLightingMaterials()
-	{
-		for (UINT32 i = 0; i < 4; i++)
-			bs_delete(mInstances[i]);
-	}
-
-	ITiledDeferredLightingMat* TiledDeferredLightingMaterials::get(UINT32 msaa)
-	{
-		if (msaa == 1)
-			return mInstances[0];
-		else if (msaa == 2)
-			return mInstances[1];
-		else if (msaa == 4)
-			return mInstances[2];
-		else
-			return mInstances[3];
+		switch(msaaCount)
+		{
+		case 1:
+			return get(VAR_1MSAA);
+		case 2:
+			return get(VAR_2MSAA);
+		case 4:
+			return get(VAR_4MSAA);
+		case 8:
+		default:
+			return get(VAR_8MSAA);
+		}
 	}
 	}
 
 
 	FlatFramebufferToTextureParamDef gFlatFramebufferToTextureParamDef;
 	FlatFramebufferToTextureParamDef gFlatFramebufferToTextureParamDef;
@@ -393,7 +382,7 @@ namespace bs { namespace ct
 		mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
 		mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
 	}
 	}
 
 
-	void FlatFramebufferToTextureMat::_initDefines(ShaderDefines& defines)
+	void FlatFramebufferToTextureMat::_initVariations(ShaderVariations& variations)
 	{
 	{
 		// Do nothing
 		// Do nothing
 	}
 	}

+ 1 - 1
Source/RenderBeast/Source/BsObjectRendering.cpp

@@ -74,7 +74,7 @@ namespace bs { namespace ct
 		gPerFrameParamDef.gTime.set(mPerFrameParamBuffer, time);
 		gPerFrameParamDef.gTime.set(mPerFrameParamBuffer, time);
 	}
 	}
 
 
-	void DefaultMaterial::_initDefines(ShaderDefines& defines)
+	void DefaultMaterial::_initVariations(ShaderVariations& variations)
 	{
 	{
 		// Do nothing
 		// Do nothing
 	}
 	}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 279 - 388
Source/RenderBeast/Source/BsPostProcessing.cpp


+ 142 - 490
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -4,13 +4,10 @@
 #include "BsCCamera.h"
 #include "BsCCamera.h"
 #include "BsCRenderable.h"
 #include "BsCRenderable.h"
 #include "BsMaterial.h"
 #include "BsMaterial.h"
-#include "BsMesh.h"
 #include "BsPass.h"
 #include "BsPass.h"
-#include "BsSamplerState.h"
 #include "BsCoreApplication.h"
 #include "BsCoreApplication.h"
 #include "BsViewport.h"
 #include "BsViewport.h"
 #include "BsRenderTarget.h"
 #include "BsRenderTarget.h"
-#include "BsRenderQueue.h"
 #include "BsCoreThread.h"
 #include "BsCoreThread.h"
 #include "BsProfilerCPU.h"
 #include "BsProfilerCPU.h"
 #include "BsProfilerGPU.h"
 #include "BsProfilerGPU.h"
@@ -22,7 +19,6 @@
 #include "BsRenderBeastOptions.h"
 #include "BsRenderBeastOptions.h"
 #include "BsLight.h"
 #include "BsLight.h"
 #include "BsGpuResourcePool.h"
 #include "BsGpuResourcePool.h"
-#include "BsRenderTargets.h"
 #include "BsRendererUtility.h"
 #include "BsRendererUtility.h"
 #include "BsAnimationManager.h"
 #include "BsAnimationManager.h"
 #include "BsSkeleton.h"
 #include "BsSkeleton.h"
@@ -36,14 +32,14 @@
 #include "BsSkybox.h"
 #include "BsSkybox.h"
 #include "BsShadowRendering.h"
 #include "BsShadowRendering.h"
 #include "BsStandardDeferredLighting.h"
 #include "BsStandardDeferredLighting.h"
+#include "BsRenderCompositor.h"
+#include "BsMesh.h"
+#include "BsRendererTextures.h"
 
 
 using namespace std::placeholders;
 using namespace std::placeholders;
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
-	// Limited by max number of array elements in texture for DX11 hardware
-	constexpr UINT32 MaxReflectionCubemaps = 2048 / 6;
-
 	RenderBeast::RenderBeast()
 	RenderBeast::RenderBeast()
 	{
 	{
 		mOptions = bs_shared_ptr_new<RenderBeastOptions>();
 		mOptions = bs_shared_ptr_new<RenderBeastOptions>();
@@ -73,27 +69,36 @@ namespace bs { namespace ct
 	void RenderBeast::initializeCore()
 	void RenderBeast::initializeCore()
 	{
 	{
 		RendererUtility::startUp();
 		RendererUtility::startUp();
+		GpuResourcePool::startUp();
+		RendererTextures::startUp();
 
 
 		mCoreOptions = bs_shared_ptr_new<RenderBeastOptions>(); 
 		mCoreOptions = bs_shared_ptr_new<RenderBeastOptions>(); 
 		mScene = bs_shared_ptr_new<RendererScene>(mCoreOptions);
 		mScene = bs_shared_ptr_new<RendererScene>(mCoreOptions);
 		mObjectRenderer = bs_new<ObjectRenderer>();
 		mObjectRenderer = bs_new<ObjectRenderer>();
 
 
-		mSkyboxMat = bs_new<SkyboxMat<false>>();
-		mSkyboxSolidColorMat = bs_new<SkyboxMat<true>>();
-		mFlatFramebufferToTextureMat = bs_new<FlatFramebufferToTextureMat>();
+		mMainViewGroup = bs_new<RendererViewGroup>();
 
 
-		mTiledDeferredLightingMats = bs_new<TiledDeferredLightingMaterials>();
-		mTileDeferredImageBasedLightingMats = bs_new<TiledDeferredImageBasedLightingMaterials>();
-
-		mPreintegratedEnvBRDF = TiledDeferredImageBasedLighting::generatePreintegratedEnvBRDF();
-		mVisibleLightInfo = bs_new<VisibleLightData>();
-		mVisibleReflProbeInfo = bs_new<VisibleReflProbeData>();
-		mLightGrid = bs_new<LightGrid>();
-
-		GpuResourcePool::startUp();
-		PostProcessing::startUp();
-		ShadowRendering::startUp(mCoreOptions->shadowMapSize);
 		StandardDeferred::startUp();
 		StandardDeferred::startUp();
+
+		RenderCompositor::registerNodeType<RCNodeSceneDepth>();
+		RenderCompositor::registerNodeType<RCNodeGBuffer>();
+		RenderCompositor::registerNodeType<RCNodeLightAccumulation>();
+		RenderCompositor::registerNodeType<RCNodeSceneColor>();
+		RenderCompositor::registerNodeType<RCNodeStandardDeferredLighting>();
+		RenderCompositor::registerNodeType<RCNodeTiledDeferredLighting>();
+		RenderCompositor::registerNodeType<RCNodeTiledDeferredIBL>();
+		RenderCompositor::registerNodeType<RCNodeUnflattenLightAccum>();
+		RenderCompositor::registerNodeType<RCNodeFinalResolve>();
+		RenderCompositor::registerNodeType<RCNodeSkybox>();
+		RenderCompositor::registerNodeType<RCNodeUnflattenSceneColor>();
+		RenderCompositor::registerNodeType<RCNodePostProcess>();
+		RenderCompositor::registerNodeType<RCNodeTonemapping>();
+		RenderCompositor::registerNodeType<RCNodeGaussianDOF>();
+		RenderCompositor::registerNodeType<RCNodeFXAA>();
+		RenderCompositor::registerNodeType<RCNodeResolvedSceneDepth>();
+		RenderCompositor::registerNodeType<RCNodeHiZ>();
+		RenderCompositor::registerNodeType<RCNodeSSAO>();
+		RenderCompositor::registerNodeType<RCNodeClusteredForward>();
 	}
 	}
 
 
 	void RenderBeast::destroyCore()
 	void RenderBeast::destroyCore()
@@ -103,27 +108,14 @@ namespace bs { namespace ct
 
 
 		mScene = nullptr;
 		mScene = nullptr;
 
 
-		mReflCubemapArrayTex = nullptr;
-		mSkyboxTexture = nullptr;
-		mSkyboxFilteredReflections = nullptr;
-		mSkyboxIrradiance = nullptr;
+		RenderCompositor::cleanUp();
 
 
 		StandardDeferred::shutDown();
 		StandardDeferred::shutDown();
-		ShadowRendering::shutDown();
-		PostProcessing::shutDown();
-		GpuResourcePool::shutDown();
-
-		bs_delete(mSkyboxMat);
-		bs_delete(mSkyboxSolidColorMat);
-		bs_delete(mVisibleLightInfo);
-		bs_delete(mVisibleReflProbeInfo);
-		bs_delete(mLightGrid);
-		bs_delete(mFlatFramebufferToTextureMat);
-		bs_delete(mTiledDeferredLightingMats);
-		bs_delete(mTileDeferredImageBasedLightingMats);
 
 
-		mPreintegratedEnvBRDF = nullptr;
+		bs_delete(mMainViewGroup);
 
 
+		RendererTextures::shutDown();
+		GpuResourcePool::shutDown();
 		RendererUtility::shutDown();
 		RendererUtility::shutDown();
 	}
 	}
 
 
@@ -181,36 +173,6 @@ namespace bs { namespace ct
 	void RenderBeast::notifyReflectionProbeAdded(ReflectionProbe* probe)
 	void RenderBeast::notifyReflectionProbeAdded(ReflectionProbe* probe)
 	{
 	{
 		mScene->registerReflectionProbe(probe);
 		mScene->registerReflectionProbe(probe);
-
-		// Find a spot in cubemap array
-		const SceneInfo& sceneInfo = mScene->getSceneInfo();
-
-		UINT32 probeId = probe->getRendererId();
-		const RendererReflectionProbe* probeInfo = &sceneInfo.reflProbes[probeId];
-
-		UINT32 numArrayEntries = (UINT32)mCubemapArrayUsedSlots.size();
-		for(UINT32 i = 0; i < numArrayEntries; i++)
-		{
-			if(!mCubemapArrayUsedSlots[i])
-			{
-				mScene->setReflectionProbeArrayIndex(probeId, i, false);
-				mCubemapArrayUsedSlots[i] = true;
-				break;
-			}
-		}
-
-		// No empty slot was found
-		if (probeInfo->arrayIdx == -1)
-		{
-			mScene->setReflectionProbeArrayIndex(probeId, numArrayEntries, false);
-			mCubemapArrayUsedSlots.push_back(true);
-		}
-
-		if(probeInfo->arrayIdx > MaxReflectionCubemaps)
-		{
-			LOGERR("Reached the maximum number of allowed reflection probe cubemaps at once. "
-				"Ignoring reflection probe data.");
-		}
 	}
 	}
 
 
 	void RenderBeast::notifyReflectionProbeUpdated(ReflectionProbe* probe)
 	void RenderBeast::notifyReflectionProbeUpdated(ReflectionProbe* probe)
@@ -220,14 +182,6 @@ namespace bs { namespace ct
 
 
 	void RenderBeast::notifyReflectionProbeRemoved(ReflectionProbe* probe)
 	void RenderBeast::notifyReflectionProbeRemoved(ReflectionProbe* probe)
 	{
 	{
-		const SceneInfo& sceneInfo = mScene->getSceneInfo();
-
-		UINT32 probeId = probe->getRendererId();
-		UINT32 arrayIdx = sceneInfo.reflProbes[probeId].arrayIdx;
-
-		if (arrayIdx != -1)
-			mCubemapArrayUsedSlots[arrayIdx] = false;
-
 		mScene->unregisterReflectionProbe(probe);
 		mScene->unregisterReflectionProbe(probe);
 	}
 	}
 
 
@@ -248,39 +202,17 @@ namespace bs { namespace ct
 
 
 	void RenderBeast::notifySkyboxAdded(Skybox* skybox)
 	void RenderBeast::notifySkyboxAdded(Skybox* skybox)
 	{
 	{
-		mSkybox = skybox;
-
-		SPtr<Texture> skyTex = skybox->getTexture();
-		if (skyTex != nullptr && skyTex->getProperties().getTextureType() == TEX_TYPE_CUBE_MAP)
-			mSkyboxTexture = skyTex;
-
-		mSkyboxFilteredReflections = nullptr;
-		mSkyboxIrradiance = nullptr;
+		mScene->registerSkybox(skybox);
 	}
 	}
 
 
 	void RenderBeast::notifySkyboxTextureChanged(Skybox* skybox)
 	void RenderBeast::notifySkyboxTextureChanged(Skybox* skybox)
 	{
 	{
-		LightProbeCache::instance().notifyDirty(skybox->getUUID());
-
-		if (mSkybox == skybox)
-		{
-			mSkyboxTexture = skybox->getTexture();
-			mSkyboxFilteredReflections = nullptr;
-			mSkyboxIrradiance = nullptr;
-		}
+		mScene->updateSkybox(skybox);
 	}
 	}
 
 
 	void RenderBeast::notifySkyboxRemoved(Skybox* skybox)
 	void RenderBeast::notifySkyboxRemoved(Skybox* skybox)
 	{
 	{
-		LightProbeCache::instance().unloadCachedTexture(skybox->getUUID());
-
-		if (mSkybox == skybox)
-			mSkyboxTexture = nullptr;
-	}
-
-	SPtr<PostProcessSettings> RenderBeast::createPostProcessSettings() const
-	{
-		return bs_shared_ptr_new<StandardPostProcessSettings>();
+		mScene->unregisterSkybox(skybox);
 	}
 	}
 
 
 	void RenderBeast::setOptions(const SPtr<RendererOptions>& options)
 	void RenderBeast::setOptions(const SPtr<RendererOptions>& options)
@@ -306,7 +238,9 @@ namespace bs { namespace ct
 		*mCoreOptions = options;
 		*mCoreOptions = options;
 
 
 		mScene->setOptions(mCoreOptions);
 		mScene->setOptions(mCoreOptions);
-		ShadowRendering::instance().setShadowMapSize(mCoreOptions->shadowMapSize);
+
+		ShadowRendering& shadowRenderer = mMainViewGroup->getShadowRenderer();
+		shadowRenderer.setShadowMapSize(mCoreOptions->shadowMapSize);
 	}
 	}
 
 
 	void RenderBeast::renderAll() 
 	void RenderBeast::renderAll() 
@@ -365,17 +299,19 @@ namespace bs { namespace ct
 			}
 			}
 		}
 		}
 
 
-		mMainViewGroup.setViews(views.data(), (UINT32)views.size());
-		mMainViewGroup.determineVisibility(sceneInfo);
+		mMainViewGroup->setViews(views.data(), (UINT32)views.size());
+		mMainViewGroup->determineVisibility(sceneInfo);
 
 
 		// Render shadow maps
 		// Render shadow maps
-		ShadowRendering::instance().renderShadowMaps(*mScene, mMainViewGroup, frameInfo);
+		ShadowRendering& shadowRenderer = mMainViewGroup->getShadowRenderer();
+		shadowRenderer.renderShadowMaps(*mScene, *mMainViewGroup, frameInfo);
 
 
-		// Update reflection probes
-		updateLightProbes(frameInfo);
+		// Update reflection probe and skybox textures, if required
+		renderReflectionProbes(frameInfo);
+		updateSkybox();
 
 
 		// Render everything
 		// Render everything
-		renderViews(mMainViewGroup, frameInfo);
+		renderViews(*mMainViewGroup, frameInfo);
 
 
 		gProfilerGPU().endFrame();
 		gProfilerGPU().endFrame();
 
 
@@ -394,16 +330,6 @@ namespace bs { namespace ct
 		const SceneInfo& sceneInfo = mScene->getSceneInfo();
 		const SceneInfo& sceneInfo = mScene->getSceneInfo();
 		const VisibilityInfo& visibility = viewGroup.getVisibilityInfo();
 		const VisibilityInfo& visibility = viewGroup.getVisibilityInfo();
 
 
-		// Note: I'm determining light and refl. probe visibility for the entire group. It might be more performance
-		// efficient to do it per view. Additionally I'm using a single GPU buffer to hold their information, which is
-		// then updated when each view group is rendered. It might be better to keep one buffer reserved per-view.
-
-		// Update GPU light data
-		mVisibleLightInfo->update(sceneInfo, viewGroup);
-
-		// Update reflection probe data
-		mVisibleReflProbeInfo->update(sceneInfo, viewGroup);
-
 		// Update various buffers required by each renderable
 		// Update various buffers required by each renderable
 		UINT32 numRenderables = (UINT32)sceneInfo.renderables.size();
 		UINT32 numRenderables = (UINT32)sceneInfo.renderables.size();
 		for (UINT32 i = 0; i < numRenderables; i++)
 		for (UINT32 i = 0; i < numRenderables; i++)
@@ -418,355 +344,70 @@ namespace bs { namespace ct
 		for (UINT32 i = 0; i < numViews; i++)
 		for (UINT32 i = 0; i < numViews; i++)
 		{
 		{
 			RendererView* view = viewGroup.getView(i);
 			RendererView* view = viewGroup.getView(i);
+			const RenderSettings& settings = view->getRenderSettings();
 
 
-			if (view->getProperties().isOverlay)
-				renderOverlay(view);
+			if (settings.overlayOnly)
+				renderOverlay(*view);
 			else
 			else
-				renderView(view, frameInfo.timeDelta);
+				renderView(viewGroup, *view, frameInfo);
 		}
 		}
 	}
 	}
 
 
-	void RenderBeast::renderView(RendererView* viewInfo, float frameDelta)
+	void RenderBeast::renderView(const RendererViewGroup& viewGroup, RendererView& view, const FrameInfo& frameInfo)
 	{
 	{
 		gProfilerCPU().beginSample("Render");
 		gProfilerCPU().beginSample("Render");
 
 
 		const SceneInfo& sceneInfo = mScene->getSceneInfo();
 		const SceneInfo& sceneInfo = mScene->getSceneInfo();
-		auto& viewProps = viewInfo->getProperties();
-		const Camera* sceneCamera = viewInfo->getSceneCamera();
+		auto& viewProps = view.getProperties();
 
 
-		SPtr<GpuParamBlockBuffer> perCameraBuffer = viewInfo->getPerViewBuffer();
+		SPtr<GpuParamBlockBuffer> perCameraBuffer = view.getPerViewBuffer();
 		perCameraBuffer->flushToGPU();
 		perCameraBuffer->flushToGPU();
 
 
-		Matrix4 viewProj = viewProps.viewProjTransform;
-		UINT32 numSamples = viewProps.numSamples;
-
-		bool allowShadows = !viewProps.noShadows;
-		if(allowShadows)
-		{
-			if(sceneCamera == nullptr)
-			{
-				// Note: In order to support shadows on non-scene views I'd need to be aware of what those views are before
-				// rendering, in order to properly generate shadow maps. 
-				LOGWRN("Shadows are currently not supported on non-scene views. Disabling shadow rendering.");
-				allowShadows = false;
-			}
-		}
-
-		viewInfo->beginFrame(true);
+		view.beginFrame();
 
 
-		// Prepare light grid required for transparent object rendering
-		mLightGrid->updateGrid(*viewInfo, *mVisibleLightInfo, *mVisibleReflProbeInfo, viewProps.noLighting);
-
-		SPtr<GpuParamBlockBuffer> gridParams;
-		SPtr<GpuBuffer> gridLightOffsetsAndSize, gridLightIndices;
-		SPtr<GpuBuffer> gridProbeOffsetsAndSize, gridProbeIndices;
-		mLightGrid->getOutputs(gridLightOffsetsAndSize, gridLightIndices, gridProbeOffsetsAndSize, gridProbeIndices, 
-			gridParams);
-
-		// Prepare image based material and its param buffer
-		ITiledDeferredImageBasedLightingMat* imageBasedLightingMat =
-			mTileDeferredImageBasedLightingMats->get(numSamples);
-
-		imageBasedLightingMat->setReflectionProbes(*mVisibleReflProbeInfo, mReflCubemapArrayTex, viewProps.renderingReflections);
-
-		float skyBrightness = 1.0f;
-		if (mSkybox != nullptr)
-			skyBrightness = mSkybox->getBrightness();
-
-		imageBasedLightingMat->setSky(mSkyboxFilteredReflections, mSkyboxIrradiance, skyBrightness);
-
-		// Assign camera and per-call data to all relevant renderables
-		const VisibilityInfo& visibility = viewInfo->getVisibilityMasks();
-		UINT32 numRenderables = (UINT32)sceneInfo.renderables.size();
-		SPtr<GpuParamBlockBuffer> reflParamBuffer = imageBasedLightingMat->getReflectionsParamBuffer();
-		SPtr<SamplerState> reflSamplerState = imageBasedLightingMat->getReflectionsSamplerState();
-		for (UINT32 i = 0; i < numRenderables; i++)
-		{
-			if (!visibility.renderables[i])
-				continue;
-
-			RendererObject* rendererObject = sceneInfo.renderables[i];
-			rendererObject->updatePerCallBuffer(viewProj);
-
-			for (auto& element : sceneInfo.renderables[i]->elements)
-			{
-				if (element.perCameraBindingIdx != -1)
-					element.params->setParamBlockBuffer(element.perCameraBindingIdx, perCameraBuffer, true);
-
-				// Everything below is required only for forward rendering (ATM only used for transparent objects)
-				// Note: It would be nice to be able to set this once and keep it, only updating if the buffers actually
-				// change (e.g. when growing). Although technically the internal systems should be smart enough to
-				// avoid updates unless objects actually changed.
-				if (element.gridParamsBindingIdx != -1)
-					element.params->setParamBlockBuffer(element.gridParamsBindingIdx, gridParams, true);
-
-				element.gridLightOffsetsAndSizeParam.set(gridLightOffsetsAndSize);
-				element.gridLightIndicesParam.set(gridLightIndices);
-				element.lightsBufferParam.set(mVisibleLightInfo->getLightBuffer());
-
-				// Image based lighting params
-				ImageBasedLightingParams& iblParams = element.imageBasedParams;
-				if (iblParams.reflProbeParamsBindingIdx != -1)
-					element.params->setParamBlockBuffer(iblParams.reflProbeParamsBindingIdx, reflParamBuffer);
-
-				element.gridProbeOffsetsAndSizeParam.set(gridProbeOffsetsAndSize);
-
-				iblParams.reflectionProbeIndicesParam.set(gridProbeIndices);
-				iblParams.reflectionProbesParam.set(mVisibleReflProbeInfo->getProbeBuffer());
-
-				iblParams.skyReflectionsTexParam.set(mSkyboxFilteredReflections);
-				iblParams.skyIrradianceTexParam.set(mSkyboxIrradiance);
-
-				iblParams.reflectionProbeCubemapsTexParam.set(mReflCubemapArrayTex);
-				iblParams.preintegratedEnvBRDFParam.set(mPreintegratedEnvBRDF);
-
-				iblParams.reflectionProbeCubemapsSampParam.set(reflSamplerState);
-				iblParams.skyReflectionsSampParam.set(reflSamplerState);
-			}
-		}
-
-		SPtr<RenderTargets> renderTargets = viewInfo->getRenderTargets();
-		renderTargets->allocate(RTT_GBuffer);
-		renderTargets->bind(RTT_GBuffer);
-
-		// Trigger pre-base-pass callbacks
-		auto iterRenderCallback = mCallbacks.begin();
+		RenderCompositorNodeInputs inputs(viewGroup, view, sceneInfo, *mCoreOptions, frameInfo);
 
 
+		// Register callbacks
 		if (viewProps.triggerCallbacks)
 		if (viewProps.triggerCallbacks)
 		{
 		{
-			while (iterRenderCallback != mCallbacks.end())
+			for(auto& extension : mCallbacks)
 			{
 			{
-				RendererExtension* extension = *iterRenderCallback;
-				if (extension->getLocation() != RenderLocation::PreBasePass)
+				RenderLocation location = extension->getLocation();
+				switch(location)
+				{
+				case RenderLocation::PreBasePass: 
+					inputs.extPreBasePass.push_back(extension);
 					break;
 					break;
-
-				if (extension->check(*sceneCamera))
-					extension->render(*sceneCamera);
-
-				++iterRenderCallback;
-			}
-		}
-
-		// Render base pass
-		const Vector<RenderQueueElement>& opaqueElements = viewInfo->getOpaqueQueue()->getSortedElements();
-		for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
-		{
-			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
-			renderElement(*renderElem, iter->passIdx, iter->applyPass, viewProj);
-		}
-
-		// 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)
-		{
-			while (iterRenderCallback != mCallbacks.end())
-			{
-				RendererExtension* extension = *iterRenderCallback;
-				if (extension->getLocation() != RenderLocation::PostBasePass)
+				case RenderLocation::PostBasePass:
+					inputs.extPostBasePass.push_back(extension);
 					break;
 					break;
-
-				if (extension->check(*sceneCamera))
-					extension->render(*sceneCamera);
-
-				++iterRenderCallback;
-			}
-		}
-
-		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);
-		}
-
-		RenderAPI& rapi = RenderAPI::instance();
-		rapi.setRenderTarget(nullptr);
-
-		// Accumulate all direct lighting into the light accumulation texture
-		renderTargets->allocate(RTT_LightAccumulation);
-
-		// Render non-shadowed lights into light accumulation texture (or buffer if MSAA)
-		ITiledDeferredLightingMat* lightingMat = mTiledDeferredLightingMats->get(numSamples);
-		lightingMat->setLights(*mVisibleLightInfo);
-		lightingMat->execute(renderTargets, perCameraBuffer, viewProps.noLighting, !allowShadows);
-
-		// If we're using flattened accumulation buffer for MSAA we need to copy its contents to the MSAA texture before
-		// continuing
-		if(isMSAA)
-		{
-			renderTargets->bind(RTT_LightAccumulation);
-			mFlatFramebufferToTextureMat->execute(renderTargets->getLightAccumulationBuffer(), 
-				renderTargets->get(RTT_LightAccumulation));
-		}
-
-		// Render shadowed lights into light accumulation texture, using standard deferred
-		if (allowShadows)
-		{
-			renderTargets->allocate(RTT_LightOcclusion);
-
-			UINT32 viewIdx = sceneCamera->getRendererId();
-
-			for(UINT32 i = 0; i < (UINT32)LightType::Count; i++)
-			{
-				LightType lightType = (LightType)i;
-
-				auto& lights = mVisibleLightInfo->getLights(lightType);
-				UINT32 count = mVisibleLightInfo->getNumShadowedLights(lightType);
-				UINT32 offset = mVisibleLightInfo->getNumUnshadowedLights(lightType);
-
-				for (UINT32 j = 0; j < count; j++)
-				{
-					renderTargets->bind(RTT_LightOcclusion);
-
-					UINT32 lightIdx = offset + j;
-					const RendererLight& light = *lights[lightIdx];
-					ShadowRendering::instance().renderShadowOcclusion(*mScene, mCoreOptions->shadowFilteringQuality,
-						light, viewIdx);
-
-					renderTargets->bind(RTT_LightAccumulation);
-					StandardDeferred::instance().renderLight(lightType, light, *viewInfo, *renderTargets);
-				}
-			}
-
-			renderTargets->release(RTT_LightOcclusion);
-		}
-
-		// Make sure light accumulation buffer isn't bound and can be read from
-		rapi.setRenderTarget(nullptr);
-
-		// Render image based lighting, add it to light accumulation and output scene color
-		renderTargets->allocate(RTT_SceneColor);
-		imageBasedLightingMat->execute(renderTargets, perCameraBuffer, mPreintegratedEnvBRDF);
-
-		if (useSSAO)
-			renderTargets->release(RTT_AmbientOcclusion);
-
-		renderTargets->release(RTT_LightAccumulation);
-		renderTargets->release(RTT_GBuffer);
-
-		renderTargets->bind(RTT_SceneColor, true);
-
-		// If we're using flattened framebuffer for MSAA we need to copy its contents to the MSAA scene texture before
-		// continuing
-		if(isMSAA)
-			mFlatFramebufferToTextureMat->execute(renderTargets->getSceneColorBuffer(), renderTargets->get(RTT_SceneColor));
-
-		// Render skybox (if any)
-		if (mSkyboxTexture != nullptr)
-		{
-			mSkyboxMat->bind(perCameraBuffer);
-			mSkyboxMat->setParams(mSkyboxTexture, Color::White);
-		}
-		else
-		{
-			Color clearColor = viewProps.clearColor;
-
-			mSkyboxSolidColorMat->bind(perCameraBuffer);
-			mSkyboxSolidColorMat->setParams(nullptr, clearColor);
-		}
-
-		SPtr<Mesh> mesh = gRendererUtility().getSkyBoxMesh();
-		gRendererUtility().draw(mesh, mesh->getProperties().getSubMesh(0));
-
-		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)
-		{
-			while (iterRenderCallback != mCallbacks.end())
-			{
-				RendererExtension* extension = *iterRenderCallback;
-				if (extension->getLocation() != RenderLocation::PostLightPass)
+				case RenderLocation::PostLightPass:
+					inputs.extPostLighting.push_back(extension);
 					break;
 					break;
-
-				if (extension->check(*sceneCamera))
-					extension->render(*sceneCamera);
-
-				++iterRenderCallback;
-			}
-		}
-
-		// Post-processing and final resolve
-		Rect2 viewportArea = viewProps.nrmViewRect;
-
-		if (viewProps.runPostProcessing)
-		{
-			// Post-processing code also takes care of writting to the final output target
-			PostProcessing::instance().postProcess(viewInfo, renderTargets, frameDelta);
-		}
-		else
-		{
-			// Just copy from scene color to output if no post-processing
-			SPtr<RenderTarget> target = viewProps.target;
-
-			rapi.setRenderTarget(target);
-			rapi.setViewport(viewportArea);
-
-			SPtr<Texture> sceneColor = renderTargets->get(RTT_SceneColor);
-			gRendererUtility().blit(sceneColor, Rect2I::EMPTY, viewProps.flipView);
-		}
-
-		renderTargets->release(RTT_HiZ);
-		renderTargets->release(RTT_SceneColor);
-
-		if (isMSAA)
-			renderTargets->release(RTT_ResolvedDepth);
-
-		// Trigger overlay callbacks
-		if (viewProps.triggerCallbacks)
-		{
-			while (iterRenderCallback != mCallbacks.end())
-			{
-				RendererExtension* extension = *iterRenderCallback;
-				if (extension->getLocation() != RenderLocation::Overlay)
+				case RenderLocation::Overlay:
+					inputs.extOverlay.push_back(extension);
 					break;
 					break;
-
-				if (extension->check(*sceneCamera))
-					extension->render(*sceneCamera);
-
-				++iterRenderCallback;
+				}
 			}
 			}
 		}
 		}
 
 
-		viewInfo->endFrame();
+		const RenderCompositor& compositor = view.getCompositor();
+		compositor.execute(inputs);
+
+		view.endFrame();
 
 
 		gProfilerCPU().endSample("Render");
 		gProfilerCPU().endSample("Render");
 	}
 	}
 
 
-	void RenderBeast::renderOverlay(RendererView* viewInfo)
+	void RenderBeast::renderOverlay(RendererView& view)
 	{
 	{
 		gProfilerCPU().beginSample("RenderOverlay");
 		gProfilerCPU().beginSample("RenderOverlay");
 
 
-		viewInfo->getPerViewBuffer()->flushToGPU();
-		viewInfo->beginFrame(false);
+		view.getPerViewBuffer()->flushToGPU();
+		view.beginFrame();
 
 
-		auto& viewProps = viewInfo->getProperties();
-		const Camera* camera = viewInfo->getSceneCamera();
+		auto& viewProps = view.getProperties();
+		const Camera* camera = view.getSceneCamera();
 		SPtr<RenderTarget> target = viewProps.target;
 		SPtr<RenderTarget> target = viewProps.target;
 		SPtr<Viewport> viewport = camera->getViewport();
 		SPtr<Viewport> viewport = camera->getViewport();
 
 
@@ -808,7 +449,7 @@ namespace bs { namespace ct
 			++iterRenderCallback;
 			++iterRenderCallback;
 		}
 		}
 
 
-		viewInfo->endFrame();
+		view.endFrame();
 
 
 		gProfilerCPU().endSample("RenderOverlay");
 		gProfilerCPU().endSample("RenderOverlay");
 	}
 	}
@@ -830,20 +471,20 @@ namespace bs { namespace ct
 				element.morphVertexDeclaration);
 				element.morphVertexDeclaration);
 	}
 	}
 
 
-	void RenderBeast::updateLightProbes(const FrameInfo& frameInfo)
+	void RenderBeast::renderReflectionProbes(const FrameInfo& frameInfo)
 	{
 	{
-		const SceneInfo& sceneInfo = mScene->getSceneInfo();
+		SceneInfo& sceneInfo = mScene->_getSceneInfo();
 		UINT32 numProbes = (UINT32)sceneInfo.reflProbes.size();
 		UINT32 numProbes = (UINT32)sceneInfo.reflProbes.size();
 
 
 		bs_frame_mark();
 		bs_frame_mark();
 		{		
 		{		
 			UINT32 currentCubeArraySize = 0;
 			UINT32 currentCubeArraySize = 0;
 
 
-			if(mReflCubemapArrayTex != nullptr)
-				mReflCubemapArrayTex->getProperties().getNumArraySlices();
+			if(sceneInfo.reflProbeCubemapsTex != nullptr)
+				currentCubeArraySize = sceneInfo.reflProbeCubemapsTex->getProperties().getNumArraySlices();
 
 
 			bool forceArrayUpdate = false;
 			bool forceArrayUpdate = false;
-			if(mReflCubemapArrayTex == nullptr || (currentCubeArraySize < numProbes && currentCubeArraySize != MaxReflectionCubemaps))
+			if(sceneInfo.reflProbeCubemapsTex == nullptr || (currentCubeArraySize < numProbes && currentCubeArraySize != MaxReflectionCubemaps))
 			{
 			{
 				TEXTURE_DESC cubeMapDesc;
 				TEXTURE_DESC cubeMapDesc;
 				cubeMapDesc.type = TEX_TYPE_CUBE_MAP;
 				cubeMapDesc.type = TEX_TYPE_CUBE_MAP;
@@ -853,12 +494,12 @@ namespace bs { namespace ct
 				cubeMapDesc.numMips = PixelUtil::getMaxMipmaps(cubeMapDesc.width, cubeMapDesc.height, 1, cubeMapDesc.format);
 				cubeMapDesc.numMips = PixelUtil::getMaxMipmaps(cubeMapDesc.width, cubeMapDesc.height, 1, cubeMapDesc.format);
 				cubeMapDesc.numArraySlices = std::min(MaxReflectionCubemaps, numProbes + 4); // Keep a few empty entries
 				cubeMapDesc.numArraySlices = std::min(MaxReflectionCubemaps, numProbes + 4); // Keep a few empty entries
 
 
-				mReflCubemapArrayTex = Texture::create(cubeMapDesc);
+				sceneInfo.reflProbeCubemapsTex = Texture::create(cubeMapDesc);
 
 
 				forceArrayUpdate = true;
 				forceArrayUpdate = true;
 			}
 			}
 
 
-			auto& cubemapArrayProps = mReflCubemapArrayTex->getProperties();
+			auto& cubemapArrayProps = sceneInfo.reflProbeCubemapsTex->getProperties();
 
 
 			TEXTURE_DESC cubemapDesc;
 			TEXTURE_DESC cubemapDesc;
 			cubemapDesc.type = TEX_TYPE_CUBE_MAP;
 			cubemapDesc.type = TEX_TYPE_CUBE_MAP;
@@ -926,7 +567,7 @@ namespace bs { namespace ct
 					{
 					{
 						for(UINT32 face = 0; face < 6; face++)
 						for(UINT32 face = 0; face < 6; face++)
 							for(UINT32 mip = 0; mip <= srcProps.getNumMipmaps(); mip++)
 							for(UINT32 mip = 0; mip <= srcProps.getNumMipmaps(); mip++)
-								probeInfo.texture->copy(mReflCubemapArrayTex, face, mip, probeInfo.arrayIdx * 6 + face, mip);
+								probeInfo.texture->copy(sceneInfo.reflProbeCubemapsTex, face, mip, probeInfo.arrayIdx * 6 + face, mip);
 					}
 					}
 
 
 					mScene->setReflectionProbeArrayIndex(i, probeInfo.arrayIdx, true);
 					mScene->setReflectionProbeArrayIndex(i, probeInfo.arrayIdx, true);
@@ -934,54 +575,66 @@ namespace bs { namespace ct
 
 
 				// Note: Consider pruning the reflection cubemap array if empty slot count becomes too high
 				// Note: Consider pruning the reflection cubemap array if empty slot count becomes too high
 			}
 			}
+		}
+		bs_frame_clear();
+	}
+
+	void RenderBeast::updateSkybox()
+	{
+		SkyInfo& sky = mScene->_getSceneInfo().sky;
 
 
-			// Get skybox image-based lighting textures if needed/available
-			if (mSkybox != nullptr && mSkyboxTexture != nullptr)
+		// Get skybox image-based lighting textures if needed/available
+		if (sky.skybox != nullptr && sky.radiance != nullptr)
+		{
+			// If haven't assigned them already, do it now
+			if (sky.filteredReflections == nullptr)
 			{
 			{
-				// If haven't assigned them already, do it now
-				if (mSkyboxFilteredReflections == nullptr)
+				if (!LightProbeCache::instance().isRadianceDirty(sky.skybox->getUUID()))
+					sky.filteredReflections = LightProbeCache::instance().getCachedRadianceTexture(sky.skybox->getUUID());
+				else
 				{
 				{
-					if (!LightProbeCache::instance().isRadianceDirty(mSkybox->getUUID()))
-						mSkyboxFilteredReflections = LightProbeCache::instance().getCachedRadianceTexture(mSkybox->getUUID());
-					else
-					{
-						mSkyboxFilteredReflections = Texture::create(cubemapDesc);
-
-						IBLUtility::scaleCubemap(mSkyboxTexture, 0, mSkyboxFilteredReflections, 0);
-						IBLUtility::filterCubemapForSpecular(mSkyboxFilteredReflections, scratchCubemap);
-						LightProbeCache::instance().setCachedRadianceTexture(mSkybox->getUUID(), mSkyboxFilteredReflections);
-					}
+					TEXTURE_DESC cubemapDesc;
+					cubemapDesc.type = TEX_TYPE_CUBE_MAP;
+					cubemapDesc.format = PF_FLOAT_R11G11B10;
+					cubemapDesc.width = IBLUtility::REFLECTION_CUBEMAP_SIZE;
+					cubemapDesc.height = IBLUtility::REFLECTION_CUBEMAP_SIZE;
+					cubemapDesc.numMips = PixelUtil::getMaxMipmaps(cubemapDesc.width, cubemapDesc.height, 1, cubemapDesc.format);
+					cubemapDesc.usage = TU_STATIC | TU_RENDERTARGET;
+
+					sky.filteredReflections = Texture::create(cubemapDesc);
+
+					IBLUtility::scaleCubemap(sky.radiance, 0, sky.filteredReflections, 0);
+					IBLUtility::filterCubemapForSpecular(sky.filteredReflections, nullptr);
+					LightProbeCache::instance().setCachedRadianceTexture(sky.skybox->getUUID(), sky.filteredReflections);
 				}
 				}
+			}
 
 
-				if(mSkyboxIrradiance == nullptr)
+			if(sky.irradiance == nullptr)
+			{
+				if (!LightProbeCache::instance().isIrradianceDirty(sky.skybox->getUUID()))
+					sky.irradiance = LightProbeCache::instance().getCachedIrradianceTexture(sky.skybox->getUUID());
+				else
 				{
 				{
-					if (!LightProbeCache::instance().isIrradianceDirty(mSkybox->getUUID()))
-						mSkyboxIrradiance = LightProbeCache::instance().getCachedIrradianceTexture(mSkybox->getUUID());
-					else
-					{
-						TEXTURE_DESC irradianceCubemapDesc;
-						irradianceCubemapDesc.type = TEX_TYPE_CUBE_MAP;
-						irradianceCubemapDesc.format = PF_FLOAT_R11G11B10;
-						irradianceCubemapDesc.width = IBLUtility::IRRADIANCE_CUBEMAP_SIZE;
-						irradianceCubemapDesc.height = IBLUtility::IRRADIANCE_CUBEMAP_SIZE;
-						irradianceCubemapDesc.numMips = 0;
-						irradianceCubemapDesc.usage = TU_STATIC | TU_RENDERTARGET;
-
-						mSkyboxIrradiance = Texture::create(irradianceCubemapDesc);
-
-						IBLUtility::filterCubemapForIrradiance(mSkyboxFilteredReflections, mSkyboxIrradiance);
-						LightProbeCache::instance().setCachedIrradianceTexture(mSkybox->getUUID(), mSkyboxFilteredReflections);
-					}
+					TEXTURE_DESC irradianceCubemapDesc;
+					irradianceCubemapDesc.type = TEX_TYPE_CUBE_MAP;
+					irradianceCubemapDesc.format = PF_FLOAT_R11G11B10;
+					irradianceCubemapDesc.width = IBLUtility::IRRADIANCE_CUBEMAP_SIZE;
+					irradianceCubemapDesc.height = IBLUtility::IRRADIANCE_CUBEMAP_SIZE;
+					irradianceCubemapDesc.numMips = 0;
+					irradianceCubemapDesc.usage = TU_STATIC | TU_RENDERTARGET;
+
+					sky.irradiance = Texture::create(irradianceCubemapDesc);
+
+					IBLUtility::filterCubemapForIrradiance(sky.filteredReflections, sky.irradiance);
+					LightProbeCache::instance().setCachedIrradianceTexture(sky.skybox->getUUID(), sky.filteredReflections);
 				}
 				}
 			}
 			}
-			else
-			{
-				mSkyboxFilteredReflections = nullptr;
-				mSkyboxIrradiance = nullptr;
-			}
-
 		}
 		}
-		bs_frame_clear();
+		else
+		{
+			sky.filteredReflections = nullptr;
+			sky.irradiance = nullptr;
+		}
 	}
 	}
 
 
 	void RenderBeast::captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, bool hdr, const FrameInfo& frameInfo)
 	void RenderBeast::captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, bool hdr, const FrameInfo& frameInfo)
@@ -1005,10 +658,6 @@ namespace bs { namespace ct
 		viewDesc.target.targetHeight = texProps.getHeight();
 		viewDesc.target.targetHeight = texProps.getHeight();
 		viewDesc.target.numSamples = 1;
 		viewDesc.target.numSamples = 1;
 
 
-		viewDesc.isOverlay = false;
-		viewDesc.isHDR = hdr;
-		viewDesc.noLighting = false;
-		viewDesc.noShadows = true; // Note: If I ever change this I need to make sure that shadow map rendering is aware of this view (currently it is only aware of main camera views)
 		viewDesc.triggerCallbacks = false;
 		viewDesc.triggerCallbacks = false;
 		viewDesc.runPostProcessing = false;
 		viewDesc.runPostProcessing = false;
 		viewDesc.renderingReflections = true;
 		viewDesc.renderingReflections = true;
@@ -1025,6 +674,10 @@ namespace bs { namespace ct
 		viewDesc.stateReduction = mCoreOptions->stateReductionMode;
 		viewDesc.stateReduction = mCoreOptions->stateReductionMode;
 		viewDesc.sceneCamera = nullptr;
 		viewDesc.sceneCamera = nullptr;
 
 
+		SPtr<RenderSettings> settings = bs_shared_ptr_new<RenderSettings>();
+		settings->enableHDR = hdr;
+		settings->enableShadows = false; // Note: If I ever change this I need to make sure that shadow map rendering is aware of this view (currently it is only aware of main camera views)
+
 		Matrix4 viewOffsetMat = Matrix4::translation(-position);
 		Matrix4 viewOffsetMat = Matrix4::translation(-position);
 
 
 		RendererView views[6];
 		RendererView views[6];
@@ -1089,14 +742,13 @@ namespace bs { namespace ct
 			viewDesc.target.target = RenderTexture::create(cubeFaceRTDesc);
 			viewDesc.target.target = RenderTexture::create(cubeFaceRTDesc);
 
 
 			views[i].setView(viewDesc);
 			views[i].setView(viewDesc);
+			views[i].setRenderSettings(settings);
 			views[i].updatePerViewBuffer();
 			views[i].updatePerViewBuffer();
-
-			views[i].determineVisible(sceneInfo.renderables, sceneInfo.renderableCullInfos);
 		}
 		}
 
 
 		RendererView* viewPtrs[] = { &views[0], &views[1], &views[2], &views[3], &views[4], &views[5] };
 		RendererView* viewPtrs[] = { &views[0], &views[1], &views[2], &views[3], &views[4], &views[5] };
 
 
-		RendererViewGroup viewGroup(viewPtrs, 6);
+		RendererViewGroup viewGroup(viewPtrs, 6, mCoreOptions->shadowMapSize);
 		viewGroup.determineVisibility(sceneInfo);
 		viewGroup.determineVisibility(sceneInfo);
 
 
 		renderViews(viewGroup, frameInfo);
 		renderViews(viewGroup, frameInfo);

+ 1577 - 0
Source/RenderBeast/Source/BsRenderCompositor.cpp

@@ -0,0 +1,1577 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsRenderCompositor.h"
+#include "BsGpuResourcePool.h"
+#include "BsRendererView.h"
+#include "BsRendererUtility.h"
+#include "BsMesh.h"
+#include "BsGpuBuffer.h"
+#include "BsStandardDeferredLighting.h"
+#include "BsRenderBeastOptions.h"
+#include "BsCamera.h"
+#include "BsRendererScene.h"
+#include "BsIBLUtility.h"
+#include "BsRenderBeast.h"
+#include "BsBitwise.h"
+#include "BsRendererTextures.h"
+#include "BsObjectRendering.h"
+#include "BsGpuParamsSet.h"
+#include "BsRendererExtension.h"
+
+namespace bs { namespace ct
+{
+	UnorderedMap<StringID, RenderCompositor::NodeType*> RenderCompositor::mNodeTypes;
+
+	RenderCompositor::~RenderCompositor()
+	{
+		clear();
+	}
+
+	void RenderCompositor::build(const RendererView& view, const StringID& finalNode)
+	{
+		clear();
+
+		bs_frame_mark();
+		{
+			FrameUnorderedMap<StringID, UINT32> processedNodes;
+			mIsValid = true;
+
+			std::function<bool(const StringID&)> registerNode = [&](const StringID& nodeId)
+			{
+				// Find node type
+				auto iterFind = mNodeTypes.find(nodeId);
+				if (iterFind == mNodeTypes.end())
+				{
+					LOGERR("Cannot find render compositor node of type \"" + String(nodeId.cstr()) + "\".");
+					return false;
+				}
+
+				NodeType* nodeType = iterFind->second;
+
+				// Register current node
+				auto iterFind2 = processedNodes.find(nodeId);
+
+				// New node
+				if (iterFind2 == processedNodes.end())
+				{
+					// Mark it as invalid for now
+					processedNodes[nodeId] = -1;
+				}
+
+				// Register node dependencies
+				SmallVector<StringID, 4> depIds = nodeType->getDependencies(view);
+				for (auto& dep : depIds)
+				{
+					if (!registerNode(dep))
+						return false;
+				}
+
+				// Register current node
+				UINT32 curIdx;
+
+				// New node, properly populate its index
+				if (iterFind2 == processedNodes.end())
+				{
+					iterFind2 = processedNodes.find(nodeId);
+
+					curIdx = (UINT32)mNodeInfos.size();
+					mNodeInfos.push_back(NodeInfo());
+					processedNodes[nodeId] = curIdx;
+
+					NodeInfo& nodeInfo = mNodeInfos.back();
+					nodeInfo.node = nodeType->create();
+					nodeInfo.lastUseIdx = -1;
+
+					for (auto& depId : depIds)
+					{
+						iterFind2 = processedNodes.find(depId);
+
+						NodeInfo& depNodeInfo = mNodeInfos[iterFind2->second];
+						nodeInfo.inputs.push_back(depNodeInfo.node);
+					}
+				}
+				else // Existing node
+				{
+					curIdx = iterFind2->second;
+
+					// Check if invalid
+					if (curIdx == -1)
+					{
+						LOGERR("Render compositor nodes recursion detected. Node \"" + String(nodeId.cstr()) + "\" " +
+							"depends on node \"" + String(iterFind->first.cstr()) + "\" which is not available at " +
+							"this stage.");
+						return false;
+					}
+				}
+
+				// Update dependency last use counters
+				for (auto& dep : depIds)
+				{
+					iterFind2 = processedNodes.find(dep);
+
+					NodeInfo& depNodeInfo = mNodeInfos[iterFind2->second];
+					if (depNodeInfo.lastUseIdx == -1)
+						depNodeInfo.lastUseIdx = curIdx;
+					else
+						depNodeInfo.lastUseIdx = std::max(depNodeInfo.lastUseIdx, curIdx);
+				}
+
+				return true;
+			};
+
+			mIsValid = registerNode(finalNode);
+
+			if (!mIsValid)
+				clear();
+		}
+		bs_frame_clear();
+	}
+
+	void RenderCompositor::execute(RenderCompositorNodeInputs& inputs) const
+	{
+		if (!mIsValid)
+			return;
+
+		bs_frame_mark();
+		{
+			FrameVector<const NodeInfo*> activeNodes;
+
+			UINT32 idx = 0;
+			for (auto& entry : mNodeInfos)
+			{
+				inputs.inputNodes = entry.inputs;
+				entry.node->render(inputs);
+
+				activeNodes.push_back(&entry);
+
+				for (UINT32 i = 0; i < (UINT32)activeNodes.size(); ++i)
+				{
+					if (activeNodes[i] == nullptr)
+						continue;
+
+					if (activeNodes[i]->lastUseIdx <= idx)
+					{
+						activeNodes[i]->node->clear();
+						activeNodes[i] = nullptr;
+					}
+				}
+
+				idx++;
+			}
+		}
+		bs_frame_clear();
+
+		if (!mNodeInfos.empty())
+			mNodeInfos.back().node->clear();
+	}
+
+	void RenderCompositor::clear()
+	{
+		for (auto& entry : mNodeInfos)
+			bs_delete(entry.node);
+
+		mNodeInfos.clear();
+		mIsValid = false;
+	}
+
+	void RCNodeSceneDepth::render(const RenderCompositorNodeInputs& inputs)
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+
+		UINT32 width = viewProps.viewRect.width;
+		UINT32 height = viewProps.viewRect.height;
+		UINT32 numSamples = viewProps.numSamples;
+
+		depthTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_D32_S8X24, width, height, TU_DEPTHSTENCIL,
+			numSamples, false));
+	}
+
+	void RCNodeSceneDepth::clear()
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		resPool.release(depthTex);
+	}
+
+	SmallVector<StringID, 4> RCNodeSceneDepth::getDependencies(const RendererView& view)
+	{
+		return {};
+	}
+
+	void RCNodeGBuffer::render(const RenderCompositorNodeInputs& inputs)
+	{
+		// Allocate necessary textures & targets
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+
+		UINT32 width = viewProps.viewRect.width;
+		UINT32 height = viewProps.viewRect.height;
+		UINT32 numSamples = viewProps.numSamples;
+
+		// Note: Consider customizable formats. e.g. for testing if quality can be improved with higher precision normals.
+		albedoTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8G8B8A8, width, height, TU_RENDERTARGET,
+			numSamples, true));
+		normalTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_UNORM_R10G10B10A2, width, height, TU_RENDERTARGET,
+			numSamples, false));
+		roughMetalTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RG, width, height, TU_RENDERTARGET,
+			numSamples, false)); // Note: Metal doesn't need 16-bit float
+
+		RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[0]);
+		SPtr<PooledRenderTexture> sceneDepthTex = sceneDepthNode->depthTex;
+
+		bool rebuildRT = false;
+		if (renderTarget != nullptr)
+		{
+			rebuildRT |= renderTarget->getColorTexture(0) != albedoTex->texture;
+			rebuildRT |= renderTarget->getColorTexture(1) != normalTex->texture;
+			rebuildRT |= renderTarget->getColorTexture(2) != roughMetalTex->texture;
+			rebuildRT |= renderTarget->getDepthStencilTexture() != sceneDepthTex->texture;
+		}
+		else
+			rebuildRT = true;
+
+		if (renderTarget == nullptr || rebuildRT)
+		{
+			RENDER_TEXTURE_DESC gbufferDesc;
+			gbufferDesc.colorSurfaces[0].texture = albedoTex->texture;
+			gbufferDesc.colorSurfaces[0].face = 0;
+			gbufferDesc.colorSurfaces[0].numFaces = 1;
+			gbufferDesc.colorSurfaces[0].mipLevel = 0;
+
+			gbufferDesc.colorSurfaces[1].texture = normalTex->texture;
+			gbufferDesc.colorSurfaces[1].face = 0;
+			gbufferDesc.colorSurfaces[1].numFaces = 1;
+			gbufferDesc.colorSurfaces[1].mipLevel = 0;
+
+			gbufferDesc.colorSurfaces[2].texture = roughMetalTex->texture;
+			gbufferDesc.colorSurfaces[2].face = 0;
+			gbufferDesc.colorSurfaces[2].numFaces = 1;
+			gbufferDesc.colorSurfaces[2].mipLevel = 0;
+
+			gbufferDesc.depthStencilSurface.texture = sceneDepthTex->texture;
+			gbufferDesc.depthStencilSurface.face = 0;
+			gbufferDesc.depthStencilSurface.mipLevel = 0;
+
+			renderTarget = RenderTexture::create(gbufferDesc);
+		}
+
+		// Prepare all visible objects. Note that this also prepares non-opaque objects.
+		const VisibilityInfo& visibility = inputs.view.getVisibilityMasks();
+		UINT32 numRenderables = (UINT32)inputs.scene.renderables.size();
+		for (UINT32 i = 0; i < numRenderables; i++)
+		{
+			if (!visibility.renderables[i])
+				continue;
+
+			RendererObject* rendererObject = inputs.scene.renderables[i];
+			rendererObject->updatePerCallBuffer(viewProps.viewProjTransform);
+
+			for (auto& element : inputs.scene.renderables[i]->elements)
+			{
+				if (element.perCameraBindingIdx != -1)
+					element.params->setParamBlockBuffer(element.perCameraBindingIdx, inputs.view.getPerViewBuffer(), true);
+			}
+		}
+
+		Camera* sceneCamera = inputs.view.getSceneCamera();
+
+		// Trigger pre-base-pass callbacks
+		if (sceneCamera != nullptr)
+		{
+			for(auto& extension : inputs.extPreBasePass)
+			{
+				if (extension->check(*sceneCamera))
+					extension->render(*sceneCamera);
+			}
+		}
+
+		// Render base pass
+		RenderAPI& rapi = RenderAPI::instance();
+		rapi.setRenderTarget(renderTarget);
+
+		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 = viewProps.clearFlags & ~FBT_COLOR;
+		if (clearFlags != 0)
+		{
+			rapi.clearViewport(clearFlags, viewProps.clearColor, viewProps.clearDepthValue, 
+				viewProps.clearStencilValue, 0x01);
+		}
+
+		// Clear all non primary targets (Note: I could perhaps clear all but albedo, since it stores a per-pixel write mask)
+		rapi.clearViewport(FBT_COLOR, Color::ZERO, 1.0f, 0, 0xFF & ~0x01);
+
+		// Render all visible opaque elements
+		const Vector<RenderQueueElement>& opaqueElements = inputs.view.getOpaqueQueue()->getSortedElements();
+		for (auto iter = opaqueElements.begin(); iter != opaqueElements.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);
+		}
+
+		// Trigger post-base-pass callbacks
+		if (sceneCamera != nullptr)
+		{
+			for(auto& extension : inputs.extPostBasePass)
+			{
+				if (extension->check(*sceneCamera))
+					extension->render(*sceneCamera);
+			}
+		}
+	}
+
+	void RCNodeGBuffer::clear()
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+
+		resPool.release(albedoTex);
+		resPool.release(normalTex);
+		resPool.release(roughMetalTex);
+	}
+
+	SmallVector<StringID, 4> RCNodeGBuffer::getDependencies(const RendererView& view)
+	{
+		return { RCNodeSceneDepth::getNodeId() };
+	}
+
+	void RCNodeSceneColor::render(const RenderCompositorNodeInputs& inputs)
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+
+		UINT32 width = viewProps.viewRect.width;
+		UINT32 height = viewProps.viewRect.height;
+		UINT32 numSamples = viewProps.numSamples;
+
+		// Note: Consider customizable HDR format via options? e.g. smaller PF_FLOAT_R11G11B10 or larger 32-bit format
+		sceneColorTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RGBA, width, height, TU_RENDERTARGET | 
+			TU_LOADSTORE, numSamples, false));
+
+		RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[0]);
+		SPtr<PooledRenderTexture> sceneDepthTex = sceneDepthNode->depthTex;
+
+		if (viewProps.numSamples > 1)
+		{
+			UINT32 bufferNumElements = width * height * viewProps.numSamples;
+			flattenedSceneColorBuffer = resPool.get(POOLED_STORAGE_BUFFER_DESC::createStandard(BF_16X4F, bufferNumElements));
+		}
+		else
+			flattenedSceneColorBuffer = nullptr;
+
+		bool rebuildRT = false;
+		if (renderTarget != nullptr)
+		{
+			rebuildRT |= renderTarget->getColorTexture(0) != sceneColorTex->texture;
+			rebuildRT |= renderTarget->getDepthStencilTexture() != sceneDepthTex->texture;
+		}
+		else
+			rebuildRT = true;
+
+		if (rebuildRT)
+		{
+			RENDER_TEXTURE_DESC sceneColorDesc;
+			sceneColorDesc.colorSurfaces[0].texture = sceneColorTex->texture;
+			sceneColorDesc.colorSurfaces[0].face = 0;
+			sceneColorDesc.colorSurfaces[0].numFaces = 1;
+			sceneColorDesc.colorSurfaces[0].mipLevel = 0;
+
+			sceneColorDesc.depthStencilSurface.texture = sceneDepthTex->texture;
+			sceneColorDesc.depthStencilSurface.face = 0;
+			sceneColorDesc.depthStencilSurface.numFaces = 1;
+			sceneColorDesc.depthStencilSurface.mipLevel = 0;
+
+			renderTarget = RenderTexture::create(sceneColorDesc);
+		}
+	}
+
+	void RCNodeSceneColor::clear()
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		resPool.release(sceneColorTex);
+
+		if (flattenedSceneColorBuffer != nullptr)
+			resPool.release(flattenedSceneColorBuffer);
+	}
+
+	SmallVector<StringID, 4> RCNodeSceneColor::getDependencies(const RendererView& view)
+	{
+		return { RCNodeSceneDepth::getNodeId() };
+	}
+
+	void RCNodeLightAccumulation::render(const RenderCompositorNodeInputs& inputs)
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+
+		UINT32 width = viewProps.viewRect.width;
+		UINT32 height = viewProps.viewRect.height;
+		UINT32 numSamples = viewProps.numSamples;
+		
+		if (numSamples > 1)
+		{
+			UINT32 bufferNumElements = width * height * numSamples;
+			flattenedLightAccumBuffer =
+				resPool.get(POOLED_STORAGE_BUFFER_DESC::createStandard(BF_16X4F, bufferNumElements));
+
+			SPtr<GpuBuffer> buffer = flattenedLightAccumBuffer->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();
+		}
+		else
+			flattenedLightAccumBuffer = nullptr;
+
+		lightAccumulationTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RGBA, width,
+			height, TU_LOADSTORE | TU_RENDERTARGET, numSamples, false));
+
+		bool rebuildRT;
+		if (renderTarget != nullptr)
+			rebuildRT = renderTarget->getColorTexture(0) != lightAccumulationTex->texture;
+		else
+			rebuildRT = true;
+
+		if (rebuildRT)
+		{
+			RENDER_TEXTURE_DESC lightAccumulationRTDesc;
+			lightAccumulationRTDesc.colorSurfaces[0].texture = lightAccumulationTex->texture;
+			lightAccumulationRTDesc.colorSurfaces[0].face = 0;
+			lightAccumulationRTDesc.colorSurfaces[0].numFaces = 1;
+			lightAccumulationRTDesc.colorSurfaces[0].mipLevel = 0;
+
+			renderTarget = RenderTexture::create(lightAccumulationRTDesc);
+		}
+	}
+
+	void RCNodeLightAccumulation::clear()
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		resPool.release(lightAccumulationTex);
+
+		if (flattenedLightAccumBuffer)
+			resPool.release(flattenedLightAccumBuffer);
+	}
+
+	SmallVector<StringID, 4> RCNodeLightAccumulation::getDependencies(const RendererView& view)
+	{
+		return {};
+	}
+
+	void RCNodeTiledDeferredLighting::render(const RenderCompositorNodeInputs& inputs)
+	{
+		output = static_cast<RCNodeLightAccumulation*>(inputs.inputNodes[0]);
+
+		RCNodeGBuffer* gbufferNode = static_cast<RCNodeGBuffer*>(inputs.inputNodes[1]);
+		RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[2]);
+
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+		TiledDeferredLightingMat* tiledDeferredMat = TiledDeferredLightingMat::getVariation(viewProps.numSamples);
+
+		GBufferInput gbuffer;
+		gbuffer.albedo = gbufferNode->albedoTex->texture;
+		gbuffer.normals = gbufferNode->normalTex->texture;
+		gbuffer.roughMetal = gbufferNode->roughMetalTex->texture;
+		gbuffer.depth = sceneDepthNode->depthTex->texture;
+
+		RenderAPI& rapi = RenderAPI::instance();
+		rapi.setRenderTarget(output->renderTarget, FBT_DEPTH | FBT_STENCIL, RT_COLOR0 | RT_DEPTH_STENCIL);
+
+		const VisibleLightData& lightData = inputs.viewGroup.getVisibleLightData();
+		SPtr<GpuBuffer> flattenedLightAccumBuffer;
+		if (output->flattenedLightAccumBuffer)
+			flattenedLightAccumBuffer = output->flattenedLightAccumBuffer->buffer;
+
+		tiledDeferredMat->execute(inputs.view, lightData, gbuffer, output->lightAccumulationTex->texture, 
+			flattenedLightAccumBuffer);
+	}
+
+	void RCNodeTiledDeferredLighting::clear()
+	{
+		output = nullptr;
+	}
+
+	SmallVector<StringID, 4> RCNodeTiledDeferredLighting::getDependencies(const RendererView& view)
+	{
+		return { RCNodeLightAccumulation::getNodeId(), RCNodeGBuffer::getNodeId(), RCNodeSceneDepth::getNodeId() };
+	}
+
+	void RCNodeStandardDeferredLighting::render(const RenderCompositorNodeInputs& inputs)
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+
+		UINT32 width = viewProps.viewRect.width;
+		UINT32 height = viewProps.viewRect.height;
+		UINT32 numSamples = viewProps.numSamples;
+
+		RCNodeTiledDeferredLighting* tileDeferredNode = static_cast<RCNodeTiledDeferredLighting*>(inputs.inputNodes[0]);
+		output = tileDeferredNode->output;
+
+		RCNodeGBuffer* gbufferNode = static_cast<RCNodeGBuffer*>(inputs.inputNodes[1]);
+		RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[2]);
+
+		// Allocate light occlusion
+		mLightOcclusionTex = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, width,
+			height, TU_RENDERTARGET, numSamples, false));
+
+		bool rebuildRT = false;
+		if (mRenderTarget != nullptr)
+		{
+			rebuildRT |= mRenderTarget->getColorTexture(0) != mLightOcclusionTex->texture;
+			rebuildRT |= mRenderTarget->getDepthStencilTexture() != sceneDepthNode->depthTex->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 = sceneDepthNode->depthTex->texture;
+			lightOcclusionRTDesc.depthStencilSurface.face = 0;
+			lightOcclusionRTDesc.depthStencilSurface.numFaces = 1;
+			lightOcclusionRTDesc.depthStencilSurface.mipLevel = 0;
+
+			mRenderTarget = RenderTexture::create(lightOcclusionRTDesc);
+		}
+
+		GBufferInput gbuffer;
+		gbuffer.albedo = gbufferNode->albedoTex->texture;
+		gbuffer.normals = gbufferNode->normalTex->texture;
+		gbuffer.roughMetal = gbufferNode->roughMetalTex->texture;
+		gbuffer.depth = sceneDepthNode->depthTex->texture;
+
+		const VisibleLightData& lightData = inputs.viewGroup.getVisibleLightData();
+		const ShadowRendering& shadowRenderer = inputs.viewGroup.getShadowRenderer();
+
+		Camera* sceneCamera = inputs.view.getSceneCamera();
+
+		// Note: Currently skipping shadow rendering for any views that aren't part of the scene (like temporary ones)
+		if (sceneCamera != nullptr)
+		{
+			RenderAPI& rapi = RenderAPI::instance();
+			UINT32 viewIdx = sceneCamera->getRendererId();
+			for (UINT32 i = 0; i < (UINT32)LightType::Count; i++)
+			{
+				LightType lightType = (LightType)i;
+
+				auto& lights = lightData.getLights(lightType);
+				UINT32 count = lightData.getNumShadowedLights(lightType);
+				UINT32 offset = lightData.getNumUnshadowedLights(lightType);
+
+				for (UINT32 j = 0; j < count; j++)
+				{
+					rapi.setRenderTarget(mRenderTarget, FBT_DEPTH, RT_DEPTH_STENCIL);
+
+					Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
+					rapi.setViewport(area);
+
+					rapi.clearViewport(FBT_COLOR, Color::ZERO);
+
+					UINT32 lightIdx = offset + j;
+					const RendererLight& light = *lights[lightIdx];
+					shadowRenderer.renderShadowOcclusion(inputs.scene, inputs.options.shadowFilteringQuality,
+						light, viewIdx, gbuffer);
+
+					rapi.setRenderTarget(output->renderTarget, FBT_DEPTH | FBT_STENCIL, RT_COLOR0 | RT_DEPTH_STENCIL);
+					StandardDeferred::instance().renderLight(lightType, light, inputs.view, gbuffer,
+						mLightOcclusionTex->texture);
+				}
+			}
+
+			// Makes sure light accumulation can be read by following passes
+			rapi.setRenderTarget(nullptr);
+		}
+
+		resPool.release(mLightOcclusionTex);
+	}
+
+	void RCNodeStandardDeferredLighting::clear()
+	{
+		output = nullptr;
+	}
+
+	SmallVector<StringID, 4> RCNodeStandardDeferredLighting::getDependencies(const RendererView& view)
+	{
+		SmallVector<StringID, 4> deps;
+
+		deps.push_back(RCNodeTiledDeferredLighting::getNodeId());
+		deps.push_back(RCNodeGBuffer::getNodeId());
+		deps.push_back(RCNodeSceneDepth::getNodeId());
+
+		if (view.getProperties().numSamples > 1)
+			deps.push_back(RCNodeUnflattenLightAccum::getNodeId());
+
+		return deps;
+	}
+
+	void RCNodeUnflattenLightAccum::render(const RenderCompositorNodeInputs& inputs)
+	{
+		RCNodeLightAccumulation* lightAccumNode = static_cast<RCNodeLightAccumulation*>(inputs.inputNodes[0]);
+		FlatFramebufferToTextureMat* material = FlatFramebufferToTextureMat::get();
+
+		RenderAPI& rapi = RenderAPI::instance();
+		rapi.setRenderTarget(lightAccumNode->renderTarget, FBT_DEPTH | FBT_STENCIL, RT_COLOR0 | RT_DEPTH_STENCIL);
+		material->execute(lightAccumNode->flattenedLightAccumBuffer->buffer, lightAccumNode->lightAccumulationTex->texture);
+	}
+
+	void RCNodeUnflattenLightAccum::clear()
+	{
+		output = nullptr;
+	}
+
+	SmallVector<StringID, 4> RCNodeUnflattenLightAccum::getDependencies(const RendererView& view)
+	{
+		return { RCNodeLightAccumulation::getNodeId() };
+	}
+
+	void RCNodeTiledDeferredIBL::render(const RenderCompositorNodeInputs& inputs)
+	{
+		RCNodeSceneColor* sceneColorNode = static_cast<RCNodeSceneColor*>(inputs.inputNodes[0]);
+		RCNodeGBuffer* gbufferNode = static_cast<RCNodeGBuffer*>(inputs.inputNodes[1]);
+		RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[2]);
+		RCNodeLightAccumulation* lightAccumNode = static_cast <RCNodeLightAccumulation*>(inputs.inputNodes[3]);
+
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+		TiledDeferredImageBasedLightingMat* material = TiledDeferredImageBasedLightingMat::getVariation(viewProps.numSamples);
+
+		TiledDeferredImageBasedLightingMat::Inputs iblInputs;
+		iblInputs.gbuffer.albedo = gbufferNode->albedoTex->texture;
+		iblInputs.gbuffer.normals = gbufferNode->normalTex->texture;
+		iblInputs.gbuffer.roughMetal = gbufferNode->roughMetalTex->texture;
+		iblInputs.gbuffer.depth = sceneDepthNode->depthTex->texture;
+		iblInputs.sceneColorTex = sceneColorNode->sceneColorTex->texture;
+		iblInputs.lightAccumulation = lightAccumNode->lightAccumulationTex->texture;
+		iblInputs.preIntegratedGF = RendererTextures::preintegratedEnvGF;
+
+		if(sceneColorNode->flattenedSceneColorBuffer)
+			iblInputs.sceneColorBuffer = sceneColorNode->flattenedSceneColorBuffer->buffer;
+
+		material->execute(inputs.view, inputs.scene, inputs.viewGroup.getVisibleReflProbeData(), iblInputs);
+	}
+
+	void RCNodeTiledDeferredIBL::clear()
+	{
+		output = nullptr;
+	}
+
+	SmallVector<StringID, 4> RCNodeTiledDeferredIBL::getDependencies(const RendererView& view)
+	{
+		SmallVector<StringID, 4> deps;
+
+		deps.push_back(RCNodeSceneColor::getNodeId());
+		deps.push_back(RCNodeGBuffer::getNodeId());
+		deps.push_back(RCNodeSceneDepth::getNodeId());
+		deps.push_back(RCNodeLightAccumulation::getNodeId());
+		deps.push_back(RCNodeStandardDeferredLighting::getNodeId());
+
+		return deps;
+	}
+
+	void RCNodeUnflattenSceneColor::render(const RenderCompositorNodeInputs& inputs)
+	{
+		RCNodeSceneColor* sceneColorNode = static_cast<RCNodeSceneColor*>(inputs.inputNodes[0]);
+		FlatFramebufferToTextureMat* material = FlatFramebufferToTextureMat::get();
+
+		int readOnlyFlags = FBT_DEPTH | FBT_STENCIL;
+
+		RenderAPI& rapi = RenderAPI::instance();
+		rapi.setRenderTarget(sceneColorNode->renderTarget, readOnlyFlags, RT_COLOR0 | RT_DEPTH_STENCIL);
+
+		Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
+		rapi.setViewport(area);
+
+		material->execute(sceneColorNode->flattenedSceneColorBuffer->buffer, sceneColorNode->sceneColorTex->texture);
+	}
+
+	void RCNodeUnflattenSceneColor::clear()
+	{
+		output = nullptr;
+	}
+
+	void RCNodeClusteredForward::render(const RenderCompositorNodeInputs& inputs)
+	{
+		const SceneInfo& sceneInfo = inputs.scene;
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+
+		const VisibleLightData& visibleLightData = inputs.viewGroup.getVisibleLightData();
+		const VisibleReflProbeData& visibleReflProbeData = inputs.viewGroup.getVisibleReflProbeData();
+
+		const LightGrid& lightGrid = inputs.view.getLightGrid();
+
+		SPtr<GpuParamBlockBuffer> gridParams;
+		SPtr<GpuBuffer> gridLightOffsetsAndSize, gridLightIndices;
+		SPtr<GpuBuffer> gridProbeOffsetsAndSize, gridProbeIndices;
+		lightGrid.getOutputs(gridLightOffsetsAndSize, gridLightIndices, gridProbeOffsetsAndSize, gridProbeIndices, 
+			gridParams);
+
+		// Prepare refl. probe param buffer
+		ReflProbeParamBuffer reflProbeParamBuffer;
+		reflProbeParamBuffer.populate(sceneInfo.sky, visibleReflProbeData, sceneInfo.reflProbeCubemapsTex, 
+			viewProps.renderingReflections);
+
+		// Prepare objects for rendering
+		const VisibilityInfo& visibility = inputs.view.getVisibilityMasks();
+		UINT32 numRenderables = (UINT32)sceneInfo.renderables.size();
+		for (UINT32 i = 0; i < numRenderables; i++)
+		{
+			if (!visibility.renderables[i])
+				continue;
+
+			for (auto& element : sceneInfo.renderables[i]->elements)
+			{
+				bool isTransparent = (element.material->getShader()->getFlags() & (UINT32)ShaderFlags::Transparent) != 0;
+				if (!isTransparent)
+					continue;
+
+				// Note: It would be nice to be able to set this once and keep it, only updating if the buffers actually
+				// change (e.g. when growing). Although technically the internal systems should be smart enough to
+				// avoid updates unless objects actually changed.
+				if (element.gridParamsBindingIdx != -1)
+					element.params->setParamBlockBuffer(element.gridParamsBindingIdx, gridParams, true);
+
+				element.gridLightOffsetsAndSizeParam.set(gridLightOffsetsAndSize);
+				element.gridLightIndicesParam.set(gridLightIndices);
+				element.lightsBufferParam.set(visibleLightData.getLightBuffer());
+
+				// Image based lighting params
+				ImageBasedLightingParams& iblParams = element.imageBasedParams;
+				if (iblParams.reflProbeParamsBindingIdx != -1)
+					element.params->setParamBlockBuffer(iblParams.reflProbeParamsBindingIdx, reflProbeParamBuffer.buffer);
+
+				element.gridProbeOffsetsAndSizeParam.set(gridProbeOffsetsAndSize);
+
+				iblParams.reflectionProbeIndicesParam.set(gridProbeIndices);
+				iblParams.reflectionProbesParam.set(visibleReflProbeData.getProbeBuffer());
+
+				iblParams.skyReflectionsTexParam.set(sceneInfo.sky.filteredReflections);
+				iblParams.skyIrradianceTexParam.set(sceneInfo.sky.irradiance);
+
+				iblParams.reflectionProbeCubemapsTexParam.set(sceneInfo.reflProbeCubemapsTex);
+				iblParams.preintegratedEnvBRDFParam.set(RendererTextures::preintegratedEnvGF);
+			}
+		}
+
+		// 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);
+		}
+
+		// Trigger post-lighting callbacks
+		Camera* sceneCamera = inputs.view.getSceneCamera();
+		if (sceneCamera != nullptr)
+		{
+			for(auto& extension : inputs.extPostLighting)
+			{
+				if (extension->check(*sceneCamera))
+					extension->render(*sceneCamera);
+			}
+		}
+	}
+
+	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() };
+	}
+
+	void RCNodeSkybox::render(const RenderCompositorNodeInputs& inputs)
+	{
+		const SkyInfo& sky = inputs.scene.sky;
+
+		if (sky.radiance != nullptr)
+		{
+			SkyboxMat* material = SkyboxMat::getVariation(false);
+			material->bind(inputs.view.getPerViewBuffer());
+			material->setParams(sky.radiance, Color::White);
+		}
+		else
+		{
+			Color clearColor = inputs.view.getProperties().clearColor;
+
+			SkyboxMat* material = SkyboxMat::getVariation(true);
+			material->bind(inputs.view.getPerViewBuffer());
+			material->setParams(nullptr, clearColor);
+		}
+
+		RCNodeSceneColor* sceneColorNode = static_cast<RCNodeSceneColor*>(inputs.inputNodes[1]);
+		int readOnlyFlags = FBT_DEPTH | FBT_STENCIL;
+
+		RenderAPI& rapi = RenderAPI::instance();
+		rapi.setRenderTarget(sceneColorNode->renderTarget, readOnlyFlags, RT_COLOR0 | RT_DEPTH_STENCIL);
+
+		Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
+		rapi.setViewport(area);
+
+		SPtr<Mesh> mesh = gRendererUtility().getSkyBoxMesh();
+		gRendererUtility().draw(mesh, mesh->getProperties().getSubMesh(0));
+	}
+
+	void RCNodeSkybox::clear()
+	{ }
+
+	SmallVector<StringID, 4> RCNodeSkybox::getDependencies(const RendererView& view)
+	{
+		SmallVector<StringID, 4> deps;
+
+		deps.push_back(RCNodeTiledDeferredIBL::getNodeId());
+		deps.push_back(RCNodeSceneColor::getNodeId());
+
+		if (view.getProperties().numSamples > 1)
+			deps.push_back(RCNodeUnflattenSceneColor::getNodeId());
+
+		return deps;
+	}
+
+	void RCNodeFinalResolve::render(const RenderCompositorNodeInputs& inputs)
+	{
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+
+		SPtr<Texture> input;
+		if(viewProps.runPostProcessing)
+		{
+			RCNodePostProcess* postProcessNode = static_cast<RCNodePostProcess*>(inputs.inputNodes[0]);
+
+			// Note: Ideally the last PP effect could write directly to the final target and we could avoid this copy
+			input = postProcessNode->getLastOutput();
+		}
+		else
+		{
+			RCNodeSceneColor* sceneColorNode = static_cast<RCNodeSceneColor*>(inputs.inputNodes[0]);
+			input = sceneColorNode->sceneColorTex->texture;
+		}
+
+		SPtr<RenderTarget> target = viewProps.target;
+
+		RenderAPI& rapi = RenderAPI::instance();
+		rapi.setRenderTarget(target);
+		rapi.setViewport(viewProps.nrmViewRect);
+
+		gRendererUtility().blit(input, Rect2I::EMPTY, viewProps.flipView);
+
+		// Trigger overlay callbacks
+		Camera* sceneCamera = inputs.view.getSceneCamera();
+		if (sceneCamera != nullptr)
+		{
+			for(auto& extension : inputs.extOverlay)
+			{
+				if (extension->check(*sceneCamera))
+					extension->render(*sceneCamera);
+			}
+		}
+	}
+
+	void RCNodeFinalResolve::clear()
+	{ }
+
+	SmallVector<StringID, 4> RCNodeFinalResolve::getDependencies(const RendererView& view)
+	{
+		const RendererViewProperties& viewProps = view.getProperties();
+
+		SmallVector<StringID, 4> deps;
+		if(viewProps.runPostProcessing)
+		{
+			deps.push_back(RCNodePostProcess::getNodeId());
+			deps.push_back(RCNodeFXAA::getNodeId());
+		}
+		else
+		{
+			deps.push_back(RCNodeSceneColor::getNodeId());
+			deps.push_back(RCNodeClusteredForward::getNodeId());
+			
+		}
+
+		return deps;
+	}
+
+	RCNodePostProcess::RCNodePostProcess()
+		:mOutput(), mAllocated()
+	{ }
+
+	void RCNodePostProcess::getAndSwitch(const RendererView& view, SPtr<RenderTexture>& output, SPtr<Texture>& lastFrame) const
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+
+		const RendererViewProperties& viewProps = view.getProperties();
+		UINT32 width = viewProps.viewRect.width;
+		UINT32 height = viewProps.viewRect.height;
+
+		if(!mAllocated[mCurrentIdx])
+		{
+			mOutput[mCurrentIdx] = resPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8G8B8A8, width, height,
+					TU_RENDERTARGET, 1, false));
+
+			mAllocated[mCurrentIdx] = true;
+		}
+
+		output = mOutput[mCurrentIdx]->renderTexture;
+
+		UINT32 otherIdx = (mCurrentIdx + 1) % 2;
+		if (mAllocated[otherIdx])
+			lastFrame = mOutput[otherIdx]->texture;
+
+		mCurrentIdx = otherIdx;
+	}
+
+	SPtr<Texture> RCNodePostProcess::getLastOutput() const
+	{
+		UINT32 otherIdx = (mCurrentIdx + 1) % 2;
+		if (mAllocated[otherIdx])
+			return mOutput[otherIdx]->texture;
+		
+		return nullptr;
+	}
+
+	void RCNodePostProcess::render(const RenderCompositorNodeInputs& inputs)
+	{
+		// Do nothing, this is just a helper node
+	}
+
+	void RCNodePostProcess::clear()
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+
+		if (mAllocated[0])
+			resPool.release(mOutput[0]);
+
+		if (mAllocated[1])
+			resPool.release(mOutput[1]);
+
+		mAllocated[0] = false;
+		mAllocated[1] = false;
+		mCurrentIdx = 0;
+	}
+
+	SmallVector<StringID, 4> RCNodePostProcess::getDependencies(const RendererView& view)
+	{
+		return {};
+	}
+
+	RCNodeTonemapping::~RCNodeTonemapping()
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+
+		if (mTonemapLUT)
+			resPool.release(mTonemapLUT);
+
+		if (prevEyeAdaptation)
+			resPool.release(prevEyeAdaptation);
+	}
+
+	void RCNodeTonemapping::render(const RenderCompositorNodeInputs& inputs)
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+
+		const RendererViewProperties& viewProps = inputs.view.getProperties();
+		const RenderSettings& settings = inputs.view.getRenderSettings();
+
+		RCNodeSceneColor* sceneColorNode = static_cast<RCNodeSceneColor*>(inputs.inputNodes[0]);
+		RCNodePostProcess* postProcessNode = static_cast<RCNodePostProcess*>(inputs.inputNodes[2]);
+		SPtr<Texture> sceneColor = sceneColorNode->sceneColorTex->texture;
+
+		bool hdr = settings.enableHDR;
+		bool msaa = viewProps.numSamples > 1;
+
+		if(hdr && settings.enableAutoExposure)
+		{
+			// Downsample scene
+			DownsampleMat* downsampleMat = DownsampleMat::getVariation(1, msaa);
+			SPtr<PooledRenderTexture> downsampledScene = resPool.get(DownsampleMat::getOutputDesc(sceneColor));
+
+			downsampleMat->execute(sceneColor, downsampledScene->renderTexture);
+
+			// Generate histogram
+			SPtr<PooledRenderTexture> eyeAdaptHistogram = resPool.get(
+				EyeAdaptHistogramMat::getOutputDesc(downsampledScene->texture));
+			EyeAdaptHistogramMat* eyeAdaptHistogramMat = EyeAdaptHistogramMat::get();
+			eyeAdaptHistogramMat->execute(downsampledScene->texture, eyeAdaptHistogram->texture, settings.autoExposure);
+
+			// Reduce histogram
+			SPtr<PooledRenderTexture> reducedHistogram = resPool.get(EyeAdaptHistogramReduceMat::getOutputDesc());
+
+			SPtr<Texture> prevFrameEyeAdaptation;
+			if (prevEyeAdaptation != nullptr)
+				prevFrameEyeAdaptation = prevEyeAdaptation->texture;
+
+			EyeAdaptHistogramReduceMat* eyeAdaptHistogramReduce = EyeAdaptHistogramReduceMat::get();
+			eyeAdaptHistogramReduce->execute(downsampledScene->texture, eyeAdaptHistogram->texture, 
+				prevFrameEyeAdaptation, reducedHistogram->renderTexture);
+
+			resPool.release(downsampledScene);
+			downsampledScene = nullptr;
+
+			resPool.release(eyeAdaptHistogram);
+			eyeAdaptHistogram = nullptr;
+
+			// Generate eye adaptation value
+			eyeAdaptation = resPool.get(EyeAdaptationMat::getOutputDesc());
+			EyeAdaptationMat* eyeAdaptationMat = EyeAdaptationMat::get();
+			eyeAdaptationMat->execute(reducedHistogram->texture, eyeAdaptation->renderTexture, inputs.frameInfo.timeDelta,
+				settings.autoExposure, settings.exposureScale);
+
+			resPool.release(reducedHistogram);
+			reducedHistogram = nullptr;
+		}
+		else
+		{
+			if(prevEyeAdaptation)
+				resPool.release(prevEyeAdaptation);
+
+			prevEyeAdaptation = nullptr;
+			eyeAdaptation = nullptr;
+		}
+
+		bool gammaOnly;
+		bool autoExposure;
+		if (hdr)
+		{
+			if (settings.enableTonemapping)
+			{
+				UINT64 latestHash = inputs.view.getRenderSettingsHash();
+				bool tonemapLUTDirty = mTonemapLastUpdateHash != latestHash;
+
+				if (tonemapLUTDirty) // Rebuild LUT if PP settings changed
+				{
+					if(mTonemapLUT == nullptr)
+						mTonemapLUT = resPool.get(CreateTonemapLUTMat::getOutputDesc());
+
+					CreateTonemapLUTMat* createLUT = CreateTonemapLUTMat::get();
+					createLUT->execute(mTonemapLUT->texture, settings);
+
+					mTonemapLastUpdateHash = latestHash;
+				}
+
+				gammaOnly = false;
+			}
+			else
+				gammaOnly = true;
+
+			autoExposure = settings.enableAutoExposure;
+		}
+		else
+		{
+			gammaOnly = true;
+			autoExposure = false;
+		}
+
+		if(gammaOnly)
+		{
+			if(mTonemapLUT)
+			{
+				resPool.release(mTonemapLUT);
+				mTonemapLUT = nullptr;
+			}
+		}
+
+		TonemappingMat* tonemapping = TonemappingMat::getVariation(gammaOnly, autoExposure, msaa);
+
+		SPtr<RenderTexture> ppOutput;
+		SPtr<Texture> ppLastFrame;
+		postProcessNode->getAndSwitch(inputs.view, ppOutput, ppLastFrame);
+
+		SPtr<Texture> eyeAdaptationTex;
+		if (eyeAdaptation)
+			eyeAdaptationTex = eyeAdaptation->texture;
+
+		SPtr<Texture> tonemapLUTTex;
+		if (mTonemapLUT)
+			tonemapLUTTex = mTonemapLUT->texture;
+
+		tonemapping->execute(sceneColor, eyeAdaptationTex, tonemapLUTTex, ppOutput, settings);
+	}
+
+	void RCNodeTonemapping::clear()
+	{
+		GpuResourcePool& resPool = GpuResourcePool::instance();
+
+		// Save eye adaptation for next frame
+		if(prevEyeAdaptation)
+			resPool.release(prevEyeAdaptation);
+
+		std::swap(eyeAdaptation, prevEyeAdaptation);
+	}
+
+	SmallVector<StringID, 4> RCNodeTonemapping::getDependencies(const RendererView& view)
+	{
+		return{ RCNodeSceneColor::getNodeId(), RCNodeClusteredForward::getNodeId(), RCNodePostProcess::getNodeId() };
+	}
+
+	void RCNodeGaussianDOF::render(const RenderCompositorNodeInputs& inputs)
+	{
+		RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[1]);
+		RCNodePostProcess* postProcessNode = static_cast<RCNodePostProcess*>(inputs.inputNodes[2]);
+
+		const DepthOfFieldSettings& settings = inputs.view.getRenderSettings().depthOfField;
+		bool near = settings.nearBlurAmount > 0.0f;
+		bool far = settings.farBlurAmount > 0.0f;
+
+		bool enabled = settings.enabled && (near || far);
+		if(!enabled)
+			return;
+
+		GaussianDOFSeparateMat* separateMat = GaussianDOFSeparateMat::getVariation(near, far);
+		GaussianDOFCombineMat* combineMat = GaussianDOFCombineMat::getVariation(near, far);
+		GaussianBlurMat* blurMat = GaussianBlurMat::get();
+
+		SPtr<RenderTexture> ppOutput;
+		SPtr<Texture> ppLastFrame;
+		postProcessNode->getAndSwitch(inputs.view, ppOutput, ppLastFrame);
+
+		separateMat->execute(ppLastFrame, sceneDepthNode->depthTex->texture, inputs.view, settings);
+
+		SPtr<PooledRenderTexture> nearTex, farTex;
+		if(near && far)
+		{
+			nearTex = separateMat->getOutput(0);
+			farTex = separateMat->getOutput(1);
+		}
+		else
+		{
+			if (near)
+				nearTex = separateMat->getOutput(0);
+			else
+				farTex = separateMat->getOutput(0);
+		}
+
+		// Blur the out of focus pixels
+		// Note: Perhaps set up stencil so I can avoid performing blur on unused parts of the textures?
+		const TextureProperties& texProps = nearTex ? nearTex->texture->getProperties() : farTex->texture->getProperties();
+		POOLED_RENDER_TEXTURE_DESC tempTexDesc = POOLED_RENDER_TEXTURE_DESC::create2D(texProps.getFormat(), 
+			texProps.getWidth(), texProps.getHeight(), TU_RENDERTARGET);
+		SPtr<PooledRenderTexture> tempTexture = GpuResourcePool::instance().get(tempTexDesc);
+
+		SPtr<Texture> blurredNearTex;
+		if(nearTex)
+		{
+			blurMat->execute(nearTex->texture, settings.nearBlurAmount, tempTexture->renderTexture);
+			blurredNearTex = tempTexture->texture;
+		}
+
+		SPtr<Texture> blurredFarTex;
+		if(farTex)
+		{
+			// If temporary texture is used up, re-use the original near texture for the blurred result
+			if(blurredNearTex)
+			{
+				blurMat->execute(farTex->texture, settings.farBlurAmount, nearTex->renderTexture);
+				blurredFarTex = nearTex->texture;
+			}
+			else // Otherwise just use the temporary
+			{
+				blurMat->execute(farTex->texture, settings.farBlurAmount, tempTexture->renderTexture);
+				blurredFarTex = tempTexture->texture;
+			}
+		}
+
+		combineMat->execute(ppLastFrame, blurredNearTex, blurredFarTex, 
+			sceneDepthNode->depthTex->texture, ppOutput, inputs.view, settings);
+
+		separateMat->release();
+		GpuResourcePool::instance().release(tempTexture);
+	}
+
+	void RCNodeGaussianDOF::clear()
+	{
+		// Do nothing
+	}
+
+	SmallVector<StringID, 4> RCNodeGaussianDOF::getDependencies(const RendererView& view)
+	{
+		return { RCNodeTonemapping::getNodeId(), RCNodeSceneDepth::getNodeId(), RCNodePostProcess::getNodeId() };
+	}
+
+	void RCNodeFXAA::render(const RenderCompositorNodeInputs& inputs)
+	{
+		const RenderSettings& settings = inputs.view.getRenderSettings();
+		if (!settings.enableFXAA)
+			return;
+
+		RCNodePostProcess* postProcessNode = static_cast<RCNodePostProcess*>(inputs.inputNodes[1]);
+
+		SPtr<RenderTexture> ppOutput;
+		SPtr<Texture> ppLastFrame;
+		postProcessNode->getAndSwitch(inputs.view, ppOutput, ppLastFrame);
+
+		// Note: I could skip executing FXAA over DOF and motion blurred pixels
+		FXAAMat* fxaa = FXAAMat::get();
+		fxaa->execute(ppLastFrame, ppOutput);
+	}
+
+	void RCNodeFXAA::clear()
+	{
+		// Do nothing
+	}
+
+	SmallVector<StringID, 4> RCNodeFXAA::getDependencies(const RendererView& view)
+	{
+		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.getRenderSettings().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;
-	}
-}}

+ 71 - 12
Source/RenderBeast/Source/BsRendererScene.cpp

@@ -11,13 +11,13 @@
 #include "BsGpuParamsSet.h"
 #include "BsGpuParamsSet.h"
 #include "BsRenderBeastOptions.h"
 #include "BsRenderBeastOptions.h"
 #include "BsRenderBeast.h"
 #include "BsRenderBeast.h"
+#include "BsSkybox.h"
 
 
 namespace bs {	namespace ct
 namespace bs {	namespace ct
 {
 {
 	RendererScene::RendererScene(const SPtr<RenderBeastOptions>& options)
 	RendererScene::RendererScene(const SPtr<RenderBeastOptions>& options)
 		:mOptions(options)
 		:mOptions(options)
 	{
 	{
-		mDefaultMaterial = bs_new<DefaultMaterial>();
 	}
 	}
 
 
 	RendererScene::~RendererScene()
 	RendererScene::~RendererScene()
@@ -29,8 +29,6 @@ namespace bs {	namespace ct
 			bs_delete(entry);
 			bs_delete(entry);
 
 
 		assert(mSamplerOverrides.empty());
 		assert(mSamplerOverrides.empty());
-
-		bs_delete(mDefaultMaterial);
 	}
 	}
 
 
 	void RendererScene::registerCamera(Camera* camera)
 	void RendererScene::registerCamera(Camera* camera)
@@ -38,7 +36,7 @@ namespace bs {	namespace ct
 		RENDERER_VIEW_DESC viewDesc = createViewDesc(camera);
 		RENDERER_VIEW_DESC viewDesc = createViewDesc(camera);
 
 
 		RendererView* view = bs_new<RendererView>(viewDesc);
 		RendererView* view = bs_new<RendererView>(viewDesc);
-		view->setPostProcessSettings(camera->getPostProcessSettings());
+		view->setRenderSettings(camera->getRenderSettings());
 		view->updatePerViewBuffer();
 		view->updatePerViewBuffer();
 
 
 		UINT32 viewIdx = (UINT32)mInfo.views.size();
 		UINT32 viewIdx = (UINT32)mInfo.views.size();
@@ -60,13 +58,13 @@ namespace bs {	namespace ct
 			RENDERER_VIEW_DESC viewDesc = createViewDesc(camera);
 			RENDERER_VIEW_DESC viewDesc = createViewDesc(camera);
 
 
 			view->setView(viewDesc);
 			view->setView(viewDesc);
-			view->setPostProcessSettings(camera->getPostProcessSettings());
+			view->setRenderSettings(camera->getRenderSettings());
 
 
 			updateCameraRenderTargets(camera);
 			updateCameraRenderTargets(camera);
 		}
 		}
-		else if((updateFlag & (UINT32)CameraDirtyFlag::PostProcess) != 0)
+		else if((updateFlag & (UINT32)CameraDirtyFlag::RenderSettings) != 0)
 		{
 		{
-			view->setPostProcessSettings(camera->getPostProcessSettings());
+			view->setRenderSettings(camera->getRenderSettings());
 		}
 		}
 		else // Transform
 		else // Transform
 		{
 		{
@@ -254,7 +252,7 @@ namespace bs {	namespace ct
 
 
 				// If no mInfo.aterial use the default mInfo.aterial
 				// If no mInfo.aterial use the default mInfo.aterial
 				if (renElement.material == nullptr)
 				if (renElement.material == nullptr)
-					renElement.material = mDefaultMaterial->getMaterial();
+					renElement.material = DefaultMaterial::get()->getMaterial();
 
 
 				// Determine which technique to use
 				// Determine which technique to use
 				static StringID techniqueIDLookup[4] = { StringID::NONE, RTag_Skinned, RTag_Morph, RTag_SkinnedMorph };
 				static StringID techniqueIDLookup[4] = { StringID::NONE, RTag_Skinned, RTag_Morph, RTag_SkinnedMorph };
@@ -399,6 +397,31 @@ namespace bs {	namespace ct
 		RendererReflectionProbe& probeInfo = mInfo.reflProbes.back();
 		RendererReflectionProbe& probeInfo = mInfo.reflProbes.back();
 
 
 		mInfo.reflProbeWorldBounds.push_back(probe->getBounds());
 		mInfo.reflProbeWorldBounds.push_back(probe->getBounds());
+
+		// Find a spot in cubemap array
+		UINT32 numArrayEntries = (UINT32)mInfo.reflProbeCubemapArrayUsedSlots.size();
+		for(UINT32 i = 0; i < numArrayEntries; i++)
+		{
+			if(!mInfo.reflProbeCubemapArrayUsedSlots[i])
+			{
+				setReflectionProbeArrayIndex(probeId, i, false);
+				mInfo.reflProbeCubemapArrayUsedSlots[i] = true;
+				break;
+			}
+		}
+
+		// No empty slot was found
+		if (probeInfo.arrayIdx == -1)
+		{
+			setReflectionProbeArrayIndex(probeId, numArrayEntries, false);
+			mInfo.reflProbeCubemapArrayUsedSlots.push_back(true);
+		}
+
+		if(probeInfo.arrayIdx > MaxReflectionCubemaps)
+		{
+			LOGERR("Reached the maximum number of allowed reflection probe cubemaps at once. "
+				"Ignoring reflection probe data.");
+		}
 	}
 	}
 
 
 	void RendererScene::updateReflectionProbe(ReflectionProbe* probe)
 	void RendererScene::updateReflectionProbe(ReflectionProbe* probe)
@@ -417,6 +440,10 @@ namespace bs {	namespace ct
 	void RendererScene::unregisterReflectionProbe(ReflectionProbe* probe)
 	void RendererScene::unregisterReflectionProbe(ReflectionProbe* probe)
 	{
 	{
 		UINT32 probeId = probe->getRendererId();
 		UINT32 probeId = probe->getRendererId();
+		UINT32 arrayIdx = mInfo.reflProbes[probeId].arrayIdx;
+
+		if (arrayIdx != -1)
+			mInfo.reflProbeCubemapArrayUsedSlots[arrayIdx] = false;
 
 
 		ReflectionProbe* lastProbe = mInfo.reflProbes.back().probe;
 		ReflectionProbe* lastProbe = mInfo.reflProbes.back().probe;
 		UINT32 lastProbeId = lastProbe->getRendererId();
 		UINT32 lastProbeId = lastProbe->getRendererId();
@@ -453,6 +480,42 @@ namespace bs {	namespace ct
 			probe->arrayDirty = false;
 			probe->arrayDirty = false;
 	}
 	}
 
 
+	void RendererScene::registerSkybox(Skybox* skybox)
+	{
+		mInfo.sky.skybox = skybox;
+
+		SPtr<Texture> skyTex = skybox->getTexture();
+		if (skyTex != nullptr && skyTex->getProperties().getTextureType() == TEX_TYPE_CUBE_MAP)
+			mInfo.sky.radiance = skyTex;
+
+		mInfo.sky.filteredReflections = nullptr;
+		mInfo.sky.irradiance = nullptr;
+	}
+
+	void RendererScene::updateSkybox(Skybox* skybox)
+	{
+		LightProbeCache::instance().notifyDirty(skybox->getUUID());
+
+		if (mInfo.sky.skybox == skybox)
+		{
+			mInfo.sky.radiance = skybox->getTexture();
+			mInfo.sky.filteredReflections = nullptr;
+			mInfo.sky.irradiance = nullptr;
+		}
+	}
+
+	void RendererScene::unregisterSkybox(Skybox* skybox)
+	{
+		LightProbeCache::instance().unloadCachedTexture(skybox->getUUID());
+
+		if (mInfo.sky.skybox == skybox)
+		{
+			mInfo.sky.radiance = nullptr;
+			mInfo.sky.filteredReflections = nullptr;
+			mInfo.sky.irradiance = nullptr;
+		}
+	}
+
 	void RendererScene::setOptions(const SPtr<RenderBeastOptions>& options)
 	void RendererScene::setOptions(const SPtr<RenderBeastOptions>& options)
 	{
 	{
 		mOptions = options;
 		mOptions = options;
@@ -501,10 +564,6 @@ namespace bs {	namespace ct
 
 
 		viewDesc.target.numSamples = camera->getMSAACount();
 		viewDesc.target.numSamples = camera->getMSAACount();
 
 
-		viewDesc.isOverlay = camera->getFlags().isSet(CameraFlag::Overlay);
-		viewDesc.isHDR = camera->getFlags().isSet(CameraFlag::HDR);
-		viewDesc.noLighting = camera->getFlags().isSet(CameraFlag::NoLighting);
-		viewDesc.noShadows = camera->getFlags().isSet(CameraFlag::NoShadows);
 		viewDesc.triggerCallbacks = true;
 		viewDesc.triggerCallbacks = true;
 		viewDesc.runPostProcessing = true;
 		viewDesc.runPostProcessing = true;
 		viewDesc.renderingReflections = false;
 		viewDesc.renderingReflections = false;

+ 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;
+		
+	}
+}}

+ 81 - 52
Source/RenderBeast/Source/BsRendererView.cpp

@@ -5,7 +5,6 @@
 #include "BsRenderable.h"
 #include "BsRenderable.h"
 #include "BsMaterial.h"
 #include "BsMaterial.h"
 #include "BsShader.h"
 #include "BsShader.h"
-#include "BsRenderTargets.h"
 #include "BsRendererUtility.h"
 #include "BsRendererUtility.h"
 #include "BsLightRendering.h"
 #include "BsLightRendering.h"
 #include "BsGpuParamsSet.h"
 #include "BsGpuParamsSet.h"
@@ -16,8 +15,15 @@ namespace bs { namespace ct
 	PerCameraParamDef gPerCameraParamDef;
 	PerCameraParamDef gPerCameraParamDef;
 	SkyboxParamDef gSkyboxParamDef;
 	SkyboxParamDef gSkyboxParamDef;
 
 
-	template<bool SOLID_COLOR>
-	SkyboxMat<SOLID_COLOR>::SkyboxMat()
+	ShaderVariation SkyboxMat::VAR_Texture = ShaderVariation({
+		ShaderVariation::Param("SOLID_COLOR", false)
+	});
+
+	ShaderVariation SkyboxMat::VAR_Color = ShaderVariation({
+		ShaderVariation::Param("SOLID_COLOR", true)
+	});
+
+	SkyboxMat::SkyboxMat()
 	{
 	{
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 
 
@@ -30,23 +36,20 @@ namespace bs { namespace ct
 			mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
 			mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
 	}
 	}
 
 
-	template<bool SOLID_COLOR>
-	void SkyboxMat<SOLID_COLOR>::_initDefines(ShaderDefines& defines)
+	void SkyboxMat::_initVariations(ShaderVariations& variations)
 	{
 	{
-		if (SOLID_COLOR)
-			defines.set("SOLID_COLOR", 1);
+		variations.add(VAR_Color);
+		variations.add(VAR_Texture);
 	}
 	}
 
 
-	template<bool SOLID_COLOR>
-	void SkyboxMat<SOLID_COLOR>::bind(const SPtr<GpuParamBlockBuffer>& perCamera)
+	void SkyboxMat::bind(const SPtr<GpuParamBlockBuffer>& perCamera)
 	{
 	{
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
 
 
 		gRendererUtility().setPass(mMaterial, 0);
 		gRendererUtility().setPass(mMaterial, 0);
 	}
 	}
 
 
-	template<bool SOLID_COLOR>
-	void SkyboxMat<SOLID_COLOR>::setParams(const SPtr<Texture>& texture, const Color& solidColor)
+	void SkyboxMat::setParams(const SPtr<Texture>& texture, const Color& solidColor)
 	{
 	{
 		mSkyTextureParam.set(texture, TextureSurface(1, 1, 0, 0));
 		mSkyTextureParam.set(texture, TextureSurface(1, 1, 0, 0));
 
 
@@ -56,6 +59,14 @@ namespace bs { namespace ct
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().setPassParams(mParamsSet);
 	}
 	}
 
 
+	SkyboxMat* SkyboxMat::getVariation(bool color)
+	{
+		if (color)
+			return get(VAR_Color);
+
+		return get(VAR_Texture);
+	}
+
 	RendererViewProperties::RendererViewProperties(const RENDERER_VIEW_DESC& src)
 	RendererViewProperties::RendererViewProperties(const RENDERER_VIEW_DESC& src)
 		:RendererViewData(src)
 		:RendererViewData(src)
 	{
 	{
@@ -73,13 +84,13 @@ namespace bs { namespace ct
 	}
 	}
 
 
 	RendererView::RendererView()
 	RendererView::RendererView()
-		: mUsingGBuffer(false)
+		:mRenderSettingsHash(0)
 	{
 	{
 		mParamBuffer = gPerCameraParamDef.createBuffer();
 		mParamBuffer = gPerCameraParamDef.createBuffer();
 	}
 	}
 
 
 	RendererView::RendererView(const RENDERER_VIEW_DESC& desc)
 	RendererView::RendererView(const RENDERER_VIEW_DESC& desc)
-		: mProperties(desc), mTargetDesc(desc.target), mCamera(desc.sceneCamera), mUsingGBuffer(false)
+		: mProperties(desc), mTargetDesc(desc.target), mCamera(desc.sceneCamera), mRenderSettingsHash(0)
 	{
 	{
 		mParamBuffer = gPerCameraParamDef.createBuffer();
 		mParamBuffer = gPerCameraParamDef.createBuffer();
 		mProperties.prevViewProjTransform = mProperties.viewProjTransform;
 		mProperties.prevViewProjTransform = mProperties.viewProjTransform;
@@ -98,18 +109,18 @@ namespace bs { namespace ct
 		mTransparentQueue = bs_shared_ptr_new<RenderQueue>(transparentStateReduction);
 		mTransparentQueue = bs_shared_ptr_new<RenderQueue>(transparentStateReduction);
 	}
 	}
 
 
-	void RendererView::setPostProcessSettings(const SPtr<PostProcessSettings>& ppSettings)
+	void RendererView::setRenderSettings(const SPtr<RenderSettings>& settings)
 	{
 	{
-		if (mPostProcessInfo.settings == nullptr)
-			mPostProcessInfo.settings = bs_shared_ptr_new<StandardPostProcessSettings>();
+		if (mRenderSettings == nullptr)
+			mRenderSettings = bs_shared_ptr_new<RenderSettings>();
 
 
-		SPtr<StandardPostProcessSettings> stdPPSettings = std::static_pointer_cast<StandardPostProcessSettings>(ppSettings);
-		if (stdPPSettings != nullptr)
-			*mPostProcessInfo.settings = *stdPPSettings;
-		else
-			*mPostProcessInfo.settings = StandardPostProcessSettings();
+		if (settings != nullptr)
+			*mRenderSettings = *settings;
+
+		mRenderSettingsHash++;
 
 
-		mPostProcessInfo.settingDirty = true;
+		// Update compositor hierarchy
+		mCompositor.build(*this, RCNodeFinalResolve::getNodeId());
 	}
 	}
 
 
 	void RendererView::setTransform(const Vector3& origin, const Vector3& direction, const Matrix4& view, 
 	void RendererView::setTransform(const Vector3& origin, const Vector3& direction, const Matrix4& view, 
@@ -125,10 +136,6 @@ namespace bs { namespace ct
 
 
 	void RendererView::setView(const RENDERER_VIEW_DESC& desc)
 	void RendererView::setView(const RENDERER_VIEW_DESC& desc)
 	{
 	{
-		if (mTargetDesc.targetWidth != desc.target.targetWidth ||
-			mTargetDesc.targetHeight != desc.target.targetHeight)
-			mRenderTargets = nullptr;
-
 		mCamera = desc.sceneCamera;
 		mCamera = desc.sceneCamera;
 		mProperties = desc;
 		mProperties = desc;
 		mTargetDesc = desc.target;
 		mTargetDesc = desc.target;
@@ -136,21 +143,8 @@ namespace bs { namespace ct
 		setStateReductionMode(desc.stateReduction);
 		setStateReductionMode(desc.stateReduction);
 	}
 	}
 
 
-	void RendererView::beginFrame(bool useGBuffer)
+	void RendererView::beginFrame()
 	{
 	{
-		if (useGBuffer)
-		{
-			// 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();
-			mUsingGBuffer = true;
-		}
 	}
 	}
 
 
 	void RendererView::endFrame()
 	void RendererView::endFrame()
@@ -160,12 +154,6 @@ namespace bs { namespace ct
 
 
 		mOpaqueQueue->clear();
 		mOpaqueQueue->clear();
 		mTransparentQueue->clear();
 		mTransparentQueue->clear();
-
-		if(mUsingGBuffer)
-		{
-			mRenderTargets->cleanup();
-			mUsingGBuffer = false;
-		}
 	}
 	}
 
 
 	void RendererView::determineVisible(const Vector<RendererObject*>& renderables, const Vector<CullInfo>& cullInfos,
 	void RendererView::determineVisible(const Vector<RendererObject*>& renderables, const Vector<CullInfo>& cullInfos,
@@ -174,7 +162,7 @@ namespace bs { namespace ct
 		mVisibility.renderables.clear();
 		mVisibility.renderables.clear();
 		mVisibility.renderables.resize(renderables.size(), false);
 		mVisibility.renderables.resize(renderables.size(), false);
 
 
-		if (mProperties.isOverlay)
+		if (mRenderSettings->overlayOnly)
 			return;
 			return;
 
 
 		calculateVisibility(cullInfos, mVisibility.renderables);
 		calculateVisibility(cullInfos, mVisibility.renderables);
@@ -243,7 +231,7 @@ namespace bs { namespace ct
 			perViewVisibility = &mVisibility.spotLights;
 			perViewVisibility = &mVisibility.spotLights;
 		}
 		}
 
 
-		if (mProperties.isOverlay)
+		if (mRenderSettings->overlayOnly)
 			return;
 			return;
 
 
 		calculateVisibility(bounds, *perViewVisibility);
 		calculateVisibility(bounds, *perViewVisibility);
@@ -468,16 +456,24 @@ namespace bs { namespace ct
 
 
 		gPerCameraParamDef.gClipToUVScaleOffset.set(mParamBuffer, clipToUVScaleOffset);
 		gPerCameraParamDef.gClipToUVScaleOffset.set(mParamBuffer, clipToUVScaleOffset);
 
 
-		if (mProperties.noLighting)
+		if (!mRenderSettings->enableLighting)
 			gPerCameraParamDef.gAmbientFactor.set(mParamBuffer, 100.0f);
 			gPerCameraParamDef.gAmbientFactor.set(mParamBuffer, 100.0f);
 		else
 		else
 			gPerCameraParamDef.gAmbientFactor.set(mParamBuffer, 0.0f);
 			gPerCameraParamDef.gAmbientFactor.set(mParamBuffer, 0.0f);
 	}
 	}
 
 
-	template class SkyboxMat<true>;
-	template class SkyboxMat<false>;
+	void RendererView::updateLightGrid(const VisibleLightData& visibleLightData, 
+		const VisibleReflProbeData& visibleReflProbeData)
+	{
+		mLightGrid.updateGrid(*this, visibleLightData, visibleReflProbeData, !mRenderSettings->enableLighting);
+	}
+
+	RendererViewGroup::RendererViewGroup()
+		:mShadowRenderer(1024)
+	{ }
 
 
-	RendererViewGroup::RendererViewGroup(RendererView** views, UINT32 numViews)
+	RendererViewGroup::RendererViewGroup(RendererView** views, UINT32 numViews, UINT32 shadowMapSize)
+		:mShadowRenderer(shadowMapSize)
 	{
 	{
 		setViews(views, numViews);
 		setViews(views, numViews);
 	}
 	}
@@ -494,6 +490,20 @@ namespace bs { namespace ct
 	{
 	{
 		UINT32 numViews = (UINT32)mViews.size();
 		UINT32 numViews = (UINT32)mViews.size();
 
 
+		// Early exit if no views render scene geometry
+		bool allViewsOverlay = false;
+		for (UINT32 i = 0; i < numViews; i++)
+		{
+			if (!mViews[i]->getRenderSettings().overlayOnly)
+			{
+				allViewsOverlay = false;
+				break;
+			}
+		}
+
+		if (allViewsOverlay)
+			return;
+
 		// Generate render queues per camera
 		// Generate render queues per camera
 		mVisibility.renderables.resize(sceneInfo.renderables.size(), false);
 		mVisibility.renderables.resize(sceneInfo.renderables.size(), false);
 		mVisibility.renderables.assign(sceneInfo.renderables.size(), false);
 		mVisibility.renderables.assign(sceneInfo.renderables.size(), false);
@@ -512,6 +522,9 @@ namespace bs { namespace ct
 
 
 		for (UINT32 i = 0; i < numViews; i++)
 		for (UINT32 i = 0; i < numViews; i++)
 		{
 		{
+			if (mViews[i]->getRenderSettings().overlayOnly)
+				continue;
+
 			mViews[i]->determineVisible(sceneInfo.radialLights, sceneInfo.radialLightWorldBounds, LightType::Radial,
 			mViews[i]->determineVisible(sceneInfo.radialLights, sceneInfo.radialLightWorldBounds, LightType::Radial,
 				&mVisibility.radialLights);
 				&mVisibility.radialLights);
 
 
@@ -535,5 +548,21 @@ namespace bs { namespace ct
 
 
 			mViews[i]->calculateVisibility(sceneInfo.reflProbeWorldBounds, mVisibility.reflProbes);
 			mViews[i]->calculateVisibility(sceneInfo.reflProbeWorldBounds, mVisibility.reflProbes);
 		}
 		}
+
+		// Organize light and refl. probe visibility infomation in a more GPU friendly manner
+
+		// Note: I'm determining light and refl. probe visibility for the entire group. It might be more performance
+		// efficient to do it per view. Additionally I'm using a single GPU buffer to hold their information, which is
+		// then updated when each view group is rendered. It might be better to keep one buffer reserved per-view.
+		mVisibleLightData.update(sceneInfo, *this);
+		mVisibleReflProbeData.update(sceneInfo, *this);
+
+		for (UINT32 i = 0; i < numViews; i++)
+		{
+			if (mViews[i]->getRenderSettings().overlayOnly)
+				continue;
+
+			mViews[i]->updateLightGrid(mVisibleLightData, mVisibleReflProbeData);
+		}
 	}
 	}
 }}
 }}

+ 178 - 120
Source/RenderBeast/Source/BsShadowRendering.cpp

@@ -18,7 +18,7 @@ namespace bs { namespace ct
 	ShadowDepthNormalMat::ShadowDepthNormalMat()
 	ShadowDepthNormalMat::ShadowDepthNormalMat()
 	{ }
 	{ }
 
 
-	void ShadowDepthNormalMat::_initDefines(ShaderDefines& defines)
+	void ShadowDepthNormalMat::_initVariations(ShaderVariations& variations)
 	{
 	{
 		// No defines
 		// No defines
 	}
 	}
@@ -39,7 +39,7 @@ namespace bs { namespace ct
 	ShadowDepthDirectionalMat::ShadowDepthDirectionalMat()
 	ShadowDepthDirectionalMat::ShadowDepthDirectionalMat()
 	{ }
 	{ }
 
 
-	void ShadowDepthDirectionalMat::_initDefines(ShaderDefines& defines)
+	void ShadowDepthDirectionalMat::_initVariations(ShaderVariations& variations)
 	{
 	{
 		// No defines
 		// No defines
 	}
 	}
@@ -63,7 +63,7 @@ namespace bs { namespace ct
 	ShadowDepthCubeMat::ShadowDepthCubeMat()
 	ShadowDepthCubeMat::ShadowDepthCubeMat()
 	{ }
 	{ }
 
 
-	void ShadowDepthCubeMat::_initDefines(ShaderDefines& defines)
+	void ShadowDepthCubeMat::_initVariations(ShaderVariations& variations)
 	{
 	{
 		// No defines
 		// No defines
 	}
 	}
@@ -89,8 +89,25 @@ namespace bs { namespace ct
 	ShadowProjectParamsDef gShadowProjectParamsDef;
 	ShadowProjectParamsDef gShadowProjectParamsDef;
 	ShadowProjectVertParamsDef gShadowProjectVertParamsDef;
 	ShadowProjectVertParamsDef gShadowProjectVertParamsDef;
 
 
-	template<bool Directional, bool ZFailStencil>
-	ShadowProjectStencilMat<Directional, ZFailStencil>::ShadowProjectStencilMat()
+	ShaderVariation ShadowProjectStencilMat::VAR_Dir_ZFailStencil = ShaderVariation({
+		ShaderVariation::Param("NEEDS_TRANSFORM", true),
+		ShaderVariation::Param("USE_ZFAIL_STENCIL", true)
+	});
+
+	ShaderVariation ShadowProjectStencilMat::VAR_Dir_NoZFailStencil = ShaderVariation({
+		ShaderVariation::Param("NEEDS_TRANSFORM", true)
+	});
+
+	ShaderVariation ShadowProjectStencilMat::VAR_NoDir_ZFailStencil = ShaderVariation({
+		ShaderVariation::Param("NEEDS_TRANSFORM", false),
+		ShaderVariation::Param("USE_ZFAIL_STENCIL", true)
+	});
+
+	ShaderVariation ShadowProjectStencilMat::VAR_NoDir_NoZFailStencil = ShaderVariation({
+		ShaderVariation::Param("NEEDS_TRANSFORM", false)
+	});
+	
+	ShadowProjectStencilMat::ShadowProjectStencilMat()
 	{
 	{
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 
 
@@ -99,17 +116,15 @@ namespace bs { namespace ct
 			params->setParamBlockBuffer(GPT_VERTEX_PROGRAM, "VertParams", mVertParams);
 			params->setParamBlockBuffer(GPT_VERTEX_PROGRAM, "VertParams", mVertParams);
 	}
 	}
 
 
-	template<bool Directional, bool ZFailStencil>
-	void ShadowProjectStencilMat<Directional, ZFailStencil>::_initDefines(ShaderDefines& defines)
+	void ShadowProjectStencilMat::_initVariations(ShaderVariations& variations)
 	{
 	{
-		defines.set("NEEDS_TRANSFORM", Directional ? 0 : 1);
-
-		if(ZFailStencil)
-			defines.set("USE_ZFAIL_STENCIL", 1);
+		variations.add(VAR_Dir_ZFailStencil);
+		variations.add(VAR_Dir_NoZFailStencil);
+		variations.add(VAR_NoDir_ZFailStencil);
+		variations.add(VAR_NoDir_NoZFailStencil);
 	}
 	}
 
 
-	template<bool Directional, bool ZFailStencil>
-	void ShadowProjectStencilMat<Directional, ZFailStencil>::bind(const SPtr<GpuParamBlockBuffer>& perCamera)
+	void ShadowProjectStencilMat::bind(const SPtr<GpuParamBlockBuffer>& perCamera)
 	{
 	{
 		Vector4 lightPosAndScale(0, 0, 0, 1);
 		Vector4 lightPosAndScale(0, 0, 0, 1);
 		gShadowProjectVertParamsDef.gPositionAndScale.set(mVertParams, lightPosAndScale);
 		gShadowProjectVertParamsDef.gPositionAndScale.set(mVertParams, lightPosAndScale);
@@ -120,25 +135,54 @@ namespace bs { namespace ct
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().setPassParams(mParamsSet);
 	}
 	}
 
 
-	void ShadowProjectStencilMaterials::bind(bool directional, bool useZFailStencil,
-		const SPtr<GpuParamBlockBuffer>& perCamera)
+	ShadowProjectStencilMat* ShadowProjectStencilMat::getVariation(bool directional, bool useZFailStencil)
 	{
 	{
 		if(directional)
 		if(directional)
 		{
 		{
 			// Always uses z-fail stencil
 			// Always uses z-fail stencil
-			mTT.bind(perCamera);
+			return get(VAR_Dir_ZFailStencil);
 		}
 		}
 		else
 		else
 		{
 		{
 			if (useZFailStencil)
 			if (useZFailStencil)
-				mFT.bind(perCamera);
+				return get(VAR_NoDir_ZFailStencil);
 			else
 			else
-				mFF.bind(perCamera);
+				return get(VAR_NoDir_NoZFailStencil);
 		}
 		}
 	}
 	}
 
 
-	template<int ShadowQuality, bool Directional, bool MSAA>
-	ShadowProjectMat<ShadowQuality, Directional, MSAA>::ShadowProjectMat()
+#define VARIATION(QUALITY)																	\
+		ShaderVariation ShadowProjectMat::VAR_Q##QUALITY##_Dir_MSAA = ShaderVariation({		\
+			ShaderVariation::Param("SHADOW_QUALITY", QUALITY),								\
+			ShaderVariation::Param("FADE_PLANE", true),										\
+			ShaderVariation::Param("NEEDS_TRANSFORM", false),								\
+			ShaderVariation::Param("MSAA_COUNT", 2)											\
+		});																					\
+		ShaderVariation ShadowProjectMat::VAR_Q##QUALITY##_Dir_NoMSAA = ShaderVariation({	\
+			ShaderVariation::Param("SHADOW_QUALITY", QUALITY),								\
+			ShaderVariation::Param("FADE_PLANE", true),										\
+			ShaderVariation::Param("NEEDS_TRANSFORM", false),								\
+			ShaderVariation::Param("MSAA_COUNT", 1)											\
+		});																					\
+		ShaderVariation ShadowProjectMat::VAR_Q##QUALITY##_NoDir_MSAA = ShaderVariation({	\
+			ShaderVariation::Param("SHADOW_QUALITY", QUALITY),								\
+			ShaderVariation::Param("NEEDS_TRANSFORM", true),								\
+			ShaderVariation::Param("MSAA_COUNT", 2)											\
+		});																					\
+		ShaderVariation ShadowProjectMat::VAR_Q##QUALITY##_NoDir_NoMSAA = ShaderVariation({	\
+			ShaderVariation::Param("SHADOW_QUALITY", QUALITY),								\
+			ShaderVariation::Param("NEEDS_TRANSFORM", true),								\
+			ShaderVariation::Param("MSAA_COUNT", 1)											\
+		});																					\
+	
+		VARIATION(1)
+		VARIATION(2)
+		VARIATION(3)
+		VARIATION(4)
+
+#undef VARIATION 
+
+	ShadowProjectMat::ShadowProjectMat()
 		: mGBufferParams(mMaterial, mParamsSet)
 		: mGBufferParams(mMaterial, mParamsSet)
 	{
 	{
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
@@ -164,35 +208,23 @@ namespace bs { namespace ct
 			params->setParamBlockBuffer(GPT_VERTEX_PROGRAM, "VertParams", mVertParams);
 			params->setParamBlockBuffer(GPT_VERTEX_PROGRAM, "VertParams", mVertParams);
 	}
 	}
 
 
-	template<int ShadowQuality, bool Directional, bool MSAA>
-	void ShadowProjectMat<ShadowQuality, Directional, MSAA>::_initDefines(ShaderDefines& defines)
+	void ShadowProjectMat::_initVariations(ShaderVariations& variations)
 	{
 	{
-		switch(ShadowQuality)
-		{
-		default:
-		case 1:
-			defines.set("SHADOW_QUALITY", 1);
-			break;
-		case 2:
-			defines.set("SHADOW_QUALITY", 2);
-			break;
-		case 3:
-			defines.set("SHADOW_QUALITY", 3);
-			break;
-		case 4:
-			defines.set("SHADOW_QUALITY", 4);
-			break;
-		}
-
-		if(Directional)
-			defines.set("FADE_PLANE", 1);
+#define VARIATION(QUALITY)									\
+		variations.add(VAR_Q##QUALITY##_Dir_MSAA);			\
+		variations.add(VAR_Q##QUALITY##_Dir_NoMSAA);		\
+		variations.add(VAR_Q##QUALITY##_NoDir_MSAA);		\
+		variations.add(VAR_Q##QUALITY##_NoDir_NoMSAA);		\
+	
+		VARIATION(1)
+		VARIATION(2)
+		VARIATION(3)
+		VARIATION(4)
 
 
-		defines.set("NEEDS_TRANSFORM", Directional ? 0 : 1);
-		defines.set("MSAA_COUNT", MSAA ? 2 : 1); // Actual count doesn't matter, as long as its >1 if enabled
+#undef VARIATION 
 	}
 	}
 
 
-	template <int ShadowQuality, bool Directional, bool MSAA>
-	void ShadowProjectMat<ShadowQuality, Directional, MSAA>::bind(const ShadowProjectParams& params)
+	void ShadowProjectMat::bind(const ShadowProjectParams& params)
 	{
 	{
 		Vector4 lightPosAndScale(Vector3(0.0f, 0.0f, 0.0f), 1.0f);
 		Vector4 lightPosAndScale(Vector3(0.0f, 0.0f, 0.0f), 1.0f);
 		gShadowProjectVertParamsDef.gPositionAndScale.set(mVertParams, lightPosAndScale);
 		gShadowProjectVertParamsDef.gPositionAndScale.set(mVertParams, lightPosAndScale);
@@ -200,7 +232,7 @@ namespace bs { namespace ct
 		TextureSurface surface;
 		TextureSurface surface;
 		surface.arraySlice = params.shadowMapFace;
 		surface.arraySlice = params.shadowMapFace;
 
 
-		mGBufferParams.bind(params.renderTargets);
+		mGBufferParams.bind(params.gbuffer);
 
 
 		mShadowMapParam.set(params.shadowMap, surface);
 		mShadowMapParam.set(params.shadowMap, surface);
 		mShadowSamplerParam.set(mSamplerState);
 		mShadowSamplerParam.set(mSamplerState);
@@ -212,20 +244,20 @@ namespace bs { namespace ct
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().setPassParams(mParamsSet);
 	}
 	}
 
 
-	void ShadowProjectMaterials::bind(UINT32 quality, bool directional, bool MSAA, const ShadowProjectParams& params)
+	ShadowProjectMat* ShadowProjectMat::getVariation(UINT32 quality, bool directional, bool MSAA)
 	{
 	{
-#define BIND_MAT(QUALITY)						\
-	{											\
-		if(directional)							\
-			if (MSAA)							\
-				mMat##QUALITY##TT.bind(params);	\
-			else								\
-				mMat##QUALITY##TF.bind(params);	\
-		else									\
-			if (MSAA)							\
-				mMat##QUALITY##FT.bind(params);	\
-			else								\
-				mMat##QUALITY##FF.bind(params);	\
+#define BIND_MAT(QUALITY)									\
+	{														\
+		if(directional)										\
+			if (MSAA)										\
+				return get(VAR_Q##QUALITY##_Dir_MSAA);		\
+			else											\
+				return get(VAR_Q##QUALITY##_Dir_NoMSAA);	\
+		else												\
+			if (MSAA)										\
+				return get(VAR_Q##QUALITY##_NoDir_MSAA);	\
+			else											\
+				return get(VAR_Q##QUALITY##_NoDir_NoMSAA);	\
 	}
 	}
 
 
 		if(quality <= 1)
 		if(quality <= 1)
@@ -242,8 +274,38 @@ namespace bs { namespace ct
 
 
 	ShadowProjectOmniParamsDef gShadowProjectOmniParamsDef;
 	ShadowProjectOmniParamsDef gShadowProjectOmniParamsDef;
 
 
-	template<int ShadowQuality, bool Inside, bool MSAA>
-	ShadowProjectOmniMat<ShadowQuality, Inside, MSAA>::ShadowProjectOmniMat()
+#define VARIATION(QUALITY)																			\
+		ShaderVariation ShadowProjectOmniMat::VAR_Q##QUALITY##_Inside_MSAA = ShaderVariation({		\
+			ShaderVariation::Param("SHADOW_QUALITY", QUALITY),										\
+			ShaderVariation::Param("VIEWER_INSIDE_VOLUME", true),									\
+			ShaderVariation::Param("NEEDS_TRANSFORM", true),										\
+			ShaderVariation::Param("MSAA_COUNT", 2)													\
+		});																							\
+		ShaderVariation ShadowProjectOmniMat::VAR_Q##QUALITY##_Inside_NoMSAA = ShaderVariation({	\
+			ShaderVariation::Param("SHADOW_QUALITY", QUALITY),										\
+			ShaderVariation::Param("VIEWER_INSIDE_VOLUME", true),									\
+			ShaderVariation::Param("NEEDS_TRANSFORM", true),										\
+			ShaderVariation::Param("MSAA_COUNT", 1)													\
+		});																							\
+		ShaderVariation ShadowProjectOmniMat::VAR_Q##QUALITY##_Outside_MSAA = ShaderVariation({		\
+			ShaderVariation::Param("SHADOW_QUALITY", QUALITY),										\
+			ShaderVariation::Param("NEEDS_TRANSFORM", true),										\
+			ShaderVariation::Param("MSAA_COUNT", 2)													\
+		});																							\
+		ShaderVariation ShadowProjectOmniMat::VAR_Q##QUALITY##_Outside_NoMSAA = ShaderVariation({	\
+			ShaderVariation::Param("SHADOW_QUALITY", QUALITY),										\
+			ShaderVariation::Param("NEEDS_TRANSFORM", true),										\
+			ShaderVariation::Param("MSAA_COUNT", 1)													\
+		});																							\
+	
+		VARIATION(1)
+		VARIATION(2)
+		VARIATION(3)
+		VARIATION(4)
+
+#undef VARIATION 
+
+	ShadowProjectOmniMat::ShadowProjectOmniMat()
 		: mGBufferParams(mMaterial, mParamsSet)
 		: mGBufferParams(mMaterial, mParamsSet)
 	{
 	{
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
@@ -271,40 +333,28 @@ namespace bs { namespace ct
 			params->setParamBlockBuffer(GPT_VERTEX_PROGRAM, "VertParams", mVertParams);
 			params->setParamBlockBuffer(GPT_VERTEX_PROGRAM, "VertParams", mVertParams);
 	}
 	}
 
 
-	template<int ShadowQuality, bool Inside, bool MSAA>
-	void ShadowProjectOmniMat<ShadowQuality, Inside, MSAA>::_initDefines(ShaderDefines& defines)
+	void ShadowProjectOmniMat::_initVariations(ShaderVariations& variations)
 	{
 	{
-		switch(ShadowQuality)
-		{
-		default:
-		case 1:
-			defines.set("SHADOW_QUALITY", 1);
-			break;
-		case 2:
-			defines.set("SHADOW_QUALITY", 2);
-			break;
-		case 3:
-			defines.set("SHADOW_QUALITY", 3);
-			break;
-		case 4:
-			defines.set("SHADOW_QUALITY", 4);
-			break;
-		}
+#define VARIATION(QUALITY)									\
+		variations.add(VAR_Q##QUALITY##_Inside_MSAA);		\
+		variations.add(VAR_Q##QUALITY##_Inside_NoMSAA);		\
+		variations.add(VAR_Q##QUALITY##_Outside_MSAA);		\
+		variations.add(VAR_Q##QUALITY##_Outside_NoMSAA);	\
+	
+		VARIATION(1)
+		VARIATION(2)
+		VARIATION(3)
+		VARIATION(4)
 
 
-		defines.set("NEEDS_TRANSFORM", 1);
-		defines.set("MSAA_COUNT", MSAA ? 2 : 1); // Actual count doesn't matter, as long as its >1 if enabled
-		
-		if (Inside)
-			defines.set("VIEWER_INSIDE_VOLUME", 1);
+#undef VARIATION 
 	}
 	}
 
 
-	template<int ShadowQuality, bool Inside, bool MSAA>
-	void ShadowProjectOmniMat<ShadowQuality, Inside, MSAA>::bind(const ShadowProjectParams& params)
+	void ShadowProjectOmniMat::bind(const ShadowProjectParams& params)
 	{
 	{
 		Vector4 lightPosAndScale(params.light.getPosition(), params.light.getAttenuationRadius());
 		Vector4 lightPosAndScale(params.light.getPosition(), params.light.getAttenuationRadius());
 		gShadowProjectVertParamsDef.gPositionAndScale.set(mVertParams, lightPosAndScale);
 		gShadowProjectVertParamsDef.gPositionAndScale.set(mVertParams, lightPosAndScale);
 
 
-		mGBufferParams.bind(params.renderTargets);
+		mGBufferParams.bind(params.gbuffer);
 
 
 		mShadowMapParam.set(params.shadowMap);
 		mShadowMapParam.set(params.shadowMap);
 		mShadowSamplerParam.set(mSamplerState);
 		mShadowSamplerParam.set(mSamplerState);
@@ -316,20 +366,20 @@ namespace bs { namespace ct
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().setPassParams(mParamsSet);
 	}
 	}
 
 
-	void ShadowProjectOmniMaterials::bind(UINT32 quality, bool insideVolume, bool MSAA, const ShadowProjectParams& params)
+	ShadowProjectOmniMat* ShadowProjectOmniMat::getVariation(UINT32 quality, bool inside, bool MSAA)
 	{
 	{
-#define BIND_MAT(QUALITY)						\
-	{											\
-		if(insideVolume)						\
-			if (MSAA)							\
-				mMat##QUALITY##TT.bind(params);	\
-			else								\
-				mMat##QUALITY##TF.bind(params);	\
-		else									\
-			if (MSAA)							\
-				mMat##QUALITY##FT.bind(params);	\
-			else								\
-				mMat##QUALITY##FF.bind(params);	\
+#define BIND_MAT(QUALITY)										\
+	{															\
+		if(inside)												\
+			if (MSAA)											\
+				return get(VAR_Q##QUALITY##_Inside_MSAA);		\
+			else												\
+				return get(VAR_Q##QUALITY##_Inside_NoMSAA);		\
+		else													\
+			if (MSAA)											\
+				return get(VAR_Q##QUALITY##_Outside_MSAA);		\
+			else												\
+				return get(VAR_Q##QUALITY##_Outside_NoMSAA);	\
 	}
 	}
 
 
 		if(quality <= 1)
 		if(quality <= 1)
@@ -756,13 +806,13 @@ namespace bs { namespace ct
 		return shadowMapTfrm * mixedToShadow;
 		return shadowMapTfrm * mixedToShadow;
 	}
 	}
 
 
-	void ShadowRendering::renderShadowOcclusion(const RendererScene& scene, UINT32 shadowQuality, 
-		const RendererLight& rendererLight, UINT32 viewIdx)
+	void ShadowRendering::renderShadowOcclusion(const SceneInfo& sceneInfo, UINT32 shadowQuality, 
+		const RendererLight& rendererLight, UINT32 viewIdx, GBufferInput gbuffer) const
 	{
 	{
 		const Light* light = rendererLight.internal;
 		const Light* light = rendererLight.internal;
 		UINT32 lightIdx = light->getRendererId();
 		UINT32 lightIdx = light->getRendererId();
 
 
-		RendererView* view = scene.getSceneInfo().views[viewIdx];
+		RendererView* view = sceneInfo.views[viewIdx];
 		auto viewProps = view->getProperties();
 		auto viewProps = view->getProperties();
 
 
 		const Matrix4& viewP = viewProps.projTransform;
 		const Matrix4& viewP = viewProps.projTransform;
@@ -810,10 +860,11 @@ namespace bs { namespace ct
 				bool viewerInsideVolume = (light->getPosition() - viewProps.viewOrigin).length() < lightRadius;
 				bool viewerInsideVolume = (light->getPosition() - viewProps.viewOrigin).length() < lightRadius;
 
 
 				SPtr<Texture> shadowMap = mShadowCubemaps[shadowInfo.textureIdx].getTexture();
 				SPtr<Texture> shadowMap = mShadowCubemaps[shadowInfo.textureIdx].getTexture();
-				SPtr<RenderTargets> renderTargets = view->getRenderTargets();
+				ShadowProjectParams shadowParams(*light, shadowMap, 0, shadowOmniParamBuffer, perViewBuffer, gbuffer);
 
 
-				ShadowProjectParams shadowParams(*light, shadowMap, 0, shadowOmniParamBuffer, perViewBuffer, *renderTargets);
-				mProjectOmniMaterials.bind(effectiveShadowQuality, viewerInsideVolume, viewProps.numSamples > 1, shadowParams);
+				ShadowProjectOmniMat* mat = ShadowProjectOmniMat::getVariation(effectiveShadowQuality, viewerInsideVolume, 
+					viewProps.numSamples > 1);
+				mat->bind(shadowParams);
 
 
 				gRendererUtility().draw(gRendererUtility().getRadialLightStencil());
 				gRendererUtility().draw(gRendererUtility().getRadialLightStencil());
 			}
 			}
@@ -840,7 +891,7 @@ namespace bs { namespace ct
 			else // Directional
 			else // Directional
 			{
 			{
 				UINT32 mapIdx = mDirectionalLightShadows[lightIdx];
 				UINT32 mapIdx = mDirectionalLightShadows[lightIdx];
-				ShadowCascadedMap& cascadedMap = mCascadedShadowMaps[mapIdx];
+				const ShadowCascadedMap& cascadedMap = mCascadedShadowMaps[mapIdx];
 
 
 				// Render cascades in far to near order.
 				// Render cascades in far to near order.
 				// Note: If rendering other non-cascade maps they should be rendered after cascades.
 				// Note: If rendering other non-cascade maps they should be rendered after cascades.
@@ -901,7 +952,8 @@ namespace bs { namespace ct
 					// for handling viewer outside the frustum will not properly render intersections with the near plane.
 					// for handling viewer outside the frustum will not properly render intersections with the near plane.
 					bool viewerInsideFrustum = shadowFrustum.contains(viewProps.viewOrigin, viewProps.nearPlane * 3.0f);
 					bool viewerInsideFrustum = shadowFrustum.contains(viewProps.viewOrigin, viewProps.nearPlane * 3.0f);
 
 
-					mProjectStencilMaterials.bind(false, viewerInsideFrustum, perViewBuffer);
+					ShadowProjectStencilMat* mat = ShadowProjectStencilMat::getVariation(false, viewerInsideFrustum);
+					mat->bind(perViewBuffer);
 					drawFrustum(frustumVertices);
 					drawFrustum(frustumVertices);
 
 
 					// Reduce shadow quality based on shadow map resolution for spot lights
 					// Reduce shadow quality based on shadow map resolution for spot lights
@@ -915,7 +967,9 @@ namespace bs { namespace ct
 					Vector3 near = viewProps.projTransform.multiply(Vector3(0, 0, -shadowInfo->depthNear));
 					Vector3 near = viewProps.projTransform.multiply(Vector3(0, 0, -shadowInfo->depthNear));
 					Vector3 far = viewProps.projTransform.multiply(Vector3(0, 0, -shadowInfo->depthFar));
 					Vector3 far = viewProps.projTransform.multiply(Vector3(0, 0, -shadowInfo->depthFar));
 
 
-					mProjectStencilMaterials.bind(true, true, perViewBuffer);
+					ShadowProjectStencilMat* mat = ShadowProjectStencilMat::getVariation(true, true);
+					mat->bind(perViewBuffer);
+
 					drawNearFarPlanes(near.z, far.z, shadowInfo->cascadeIdx != 0);
 					drawNearFarPlanes(near.z, far.z, shadowInfo->cascadeIdx != 0);
 				}
 				}
 
 
@@ -929,10 +983,11 @@ namespace bs { namespace ct
 					shadowMapFace = shadowInfo->cascadeIdx;
 					shadowMapFace = shadowInfo->cascadeIdx;
 				}
 				}
 
 
-				SPtr<RenderTargets> renderTargets = view->getRenderTargets();
 				ShadowProjectParams shadowParams(*light, shadowMap, shadowMapFace, shadowParamBuffer, perViewBuffer, 
 				ShadowProjectParams shadowParams(*light, shadowMap, shadowMapFace, shadowParamBuffer, perViewBuffer, 
-					*renderTargets);
-				mProjectMaterials.bind(effectiveShadowQuality, isCSM, viewProps.numSamples > 1, shadowParams);
+					gbuffer);
+
+				ShadowProjectMat* mat = ShadowProjectMat::getVariation(effectiveShadowQuality, isCSM, viewProps.numSamples > 1);
+				mat->bind(shadowParams);
 
 
 				if (!isCSM)
 				if (!isCSM)
 					drawFrustum(frustumVertices);
 					drawFrustum(frustumVertices);
@@ -1045,7 +1100,8 @@ namespace bs { namespace ct
 			rapi.setRenderTarget(shadowMap.getTarget(i));
 			rapi.setRenderTarget(shadowMap.getTarget(i));
 			rapi.clearRenderTarget(FBT_DEPTH);
 			rapi.clearRenderTarget(FBT_DEPTH);
 
 
-			mDepthDirectionalMat.bind(shadowParamsBuffer);
+			ShadowDepthDirectionalMat* depthDirMat = ShadowDepthDirectionalMat::get();
+			depthDirMat->bind(shadowParamsBuffer);
 
 
 			for (UINT32 j = 0; j < sceneInfo.renderables.size(); j++)
 			for (UINT32 j = 0; j < sceneInfo.renderables.size(); j++)
 			{
 			{
@@ -1055,7 +1111,7 @@ namespace bs { namespace ct
 				scene.prepareRenderable(j, frameInfo);
 				scene.prepareRenderable(j, frameInfo);
 
 
 				RendererObject* renderable = sceneInfo.renderables[j];
 				RendererObject* renderable = sceneInfo.renderables[j];
-				mDepthDirectionalMat.setPerObjectBuffer(renderable->perObjectParamBuffer);
+				depthDirMat->setPerObjectBuffer(renderable->perObjectParamBuffer);
 
 
 				for (auto& element : renderable->elements)
 				for (auto& element : renderable->elements)
 				{
 				{
@@ -1141,7 +1197,8 @@ namespace bs { namespace ct
 		gShadowParamsDef.gMatViewProj.set(shadowParamsBuffer, mapInfo.shadowVPTransform);
 		gShadowParamsDef.gMatViewProj.set(shadowParamsBuffer, mapInfo.shadowVPTransform);
 		gShadowParamsDef.gNDCZToDeviceZ.set(shadowParamsBuffer, RendererView::getNDCZToDeviceZ());
 		gShadowParamsDef.gNDCZToDeviceZ.set(shadowParamsBuffer, RendererView::getNDCZToDeviceZ());
 
 
-		mDepthNormalMat.bind(shadowParamsBuffer);
+		ShadowDepthNormalMat* depthNormalMat = ShadowDepthNormalMat::get();
+		depthNormalMat->bind(shadowParamsBuffer);
 
 
 		const Vector<Plane>& frustumPlanes = localFrustum.getPlanes();
 		const Vector<Plane>& frustumPlanes = localFrustum.getPlanes();
 		Matrix4 worldMatrix = view.transpose();
 		Matrix4 worldMatrix = view.transpose();
@@ -1163,7 +1220,7 @@ namespace bs { namespace ct
 			scene.prepareRenderable(i, frameInfo);
 			scene.prepareRenderable(i, frameInfo);
 
 
 			RendererObject* renderable = sceneInfo.renderables[i];
 			RendererObject* renderable = sceneInfo.renderables[i];
-			mDepthNormalMat.setPerObjectBuffer(renderable->perObjectParamBuffer);
+			depthNormalMat->setPerObjectBuffer(renderable->perObjectParamBuffer);
 
 
 			for (auto& element : renderable->elements)
 			for (auto& element : renderable->elements)
 			{
 			{
@@ -1324,7 +1381,8 @@ namespace bs { namespace ct
 		rapi.setRenderTarget(cubemap.getTarget());
 		rapi.setRenderTarget(cubemap.getTarget());
 		rapi.clearRenderTarget(FBT_DEPTH);
 		rapi.clearRenderTarget(FBT_DEPTH);
 
 
-		mDepthCubeMat.bind(shadowParamsBuffer, shadowCubeMatricesBuffer);
+		ShadowDepthCubeMat* depthCubeMat = ShadowDepthCubeMat::get();
+		depthCubeMat->bind(shadowParamsBuffer, shadowCubeMatricesBuffer);
 
 
 		// First cull against a global volume
 		// First cull against a global volume
 		ConvexVolume boundingVolume(boundingPlanes);
 		ConvexVolume boundingVolume(boundingPlanes);
@@ -1343,7 +1401,7 @@ namespace bs { namespace ct
 			}
 			}
 
 
 			RendererObject* renderable = sceneInfo.renderables[i];
 			RendererObject* renderable = sceneInfo.renderables[i];
-			mDepthCubeMat.setPerObjectBuffer(renderable->perObjectParamBuffer, shadowCubeMasksBuffer);
+			depthCubeMat->setPerObjectBuffer(renderable->perObjectParamBuffer, shadowCubeMasksBuffer);
 
 
 			for (auto& element : renderable->elements)
 			for (auto& element : renderable->elements)
 			{
 			{
@@ -1414,7 +1472,7 @@ namespace bs { namespace ct
 		size = std::max(effectiveMapSize - 2 * border, 1u);
 		size = std::max(effectiveMapSize - 2 * border, 1u);
 	}
 	}
 
 
-	void ShadowRendering::drawNearFarPlanes(float near, float far, bool drawNear)
+	void ShadowRendering::drawNearFarPlanes(float near, float far, bool drawNear) const
 	{
 	{
 		RenderAPI& rapi = RenderAPI::instance();
 		RenderAPI& rapi = RenderAPI::instance();
 		const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
 		const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
@@ -1448,7 +1506,7 @@ namespace bs { namespace ct
 		rapi.drawIndexed(0, drawNear ? 12 : 6, 0, drawNear ? 8 : 4);
 		rapi.drawIndexed(0, drawNear ? 12 : 6, 0, drawNear ? 8 : 4);
 	}
 	}
 
 
-	void ShadowRendering::drawFrustum(const std::array<Vector3, 8>& corners)
+	void ShadowRendering::drawFrustum(const std::array<Vector3, 8>& corners) const
 	{
 	{
 		RenderAPI& rapi = RenderAPI::instance();
 		RenderAPI& rapi = RenderAPI::instance();
 
 

+ 77 - 75
Source/RenderBeast/Source/BsStandardDeferredLighting.cpp

@@ -4,93 +4,124 @@
 #include "BsRendererUtility.h"
 #include "BsRendererUtility.h"
 #include "BsRendererView.h"
 #include "BsRendererView.h"
 #include "BsGpuParamsSet.h"
 #include "BsGpuParamsSet.h"
-#include "BsRenderTargets.h"
 #include "BsMesh.h"
 #include "BsMesh.h"
 
 
 namespace bs { namespace ct {
 namespace bs { namespace ct {
 	PerLightParamDef gPerLightParamDef;
 	PerLightParamDef gPerLightParamDef;
 
 
-	template<bool MSAA>
-	DirectionalLightMat<MSAA>::DirectionalLightMat()
+	ShaderVariation DirectionalLightMat::VAR_MSAA = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 2)
+	});
+
+	ShaderVariation DirectionalLightMat::VAR_NoMSAA = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 1)
+	});
+
+	DirectionalLightMat::DirectionalLightMat()
 		:mGBufferParams(mMaterial, mParamsSet)
 		:mGBufferParams(mMaterial, mParamsSet)
 	{
 	{
 		const GpuParams& gpuParams = *mParamsSet->getGpuParams();
 		const GpuParams& gpuParams = *mParamsSet->getGpuParams();
 		gpuParams.getTextureParam(GPT_FRAGMENT_PROGRAM, "gLightOcclusionTex", mLightOcclusionTexParam);
 		gpuParams.getTextureParam(GPT_FRAGMENT_PROGRAM, "gLightOcclusionTex", mLightOcclusionTexParam);
 	}
 	}
 
 
-	template<bool MSAA>
-	void DirectionalLightMat<MSAA>::_initDefines(ShaderDefines& defines)
+	void DirectionalLightMat::_initVariations(ShaderVariations& variations)
 	{
 	{
-		if (MSAA)
-			defines.set("MSAA_COUNT", 2); // Actual count doesn't matter, as long as it's greater than one
-		else
-			defines.set("MSAA_COUNT", 1);
+		variations.add(VAR_MSAA);
+		variations.add(VAR_NoMSAA);
 	}
 	}
 
 
-	template<bool MSAA>
-	void DirectionalLightMat<MSAA>::bind(const RenderTargets& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera)
+	void DirectionalLightMat::bind(const GBufferInput& gBufferInput, const SPtr<Texture>& lightOcclusion, 
+		const SPtr<GpuParamBlockBuffer>& perCamera)
 	{
 	{
 		RendererUtility::instance().setPass(mMaterial, 0);
 		RendererUtility::instance().setPass(mMaterial, 0);
 
 
-		mGBufferParams.bind(renderTargets);
-		mLightOcclusionTexParam.set(renderTargets.get(RTT_LightOcclusion));
+		mGBufferParams.bind(gBufferInput);
+		mLightOcclusionTexParam.set(lightOcclusion);
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
 	}
 	}
 
 
-	template<bool MSAA>
-	void DirectionalLightMat<MSAA>::setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight)
+	void DirectionalLightMat::setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight)
 	{
 	{
 		mParamsSet->setParamBlockBuffer("PerLight", perLight, true);
 		mParamsSet->setParamBlockBuffer("PerLight", perLight, true);
 		
 		
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().setPassParams(mParamsSet);
 	}
 	}
 
 
-	template class DirectionalLightMat<true>;
-	template class DirectionalLightMat<false>;
+	DirectionalLightMat* DirectionalLightMat::getVariation(bool msaa)
+	{
+		if (msaa)
+			return get(VAR_MSAA);
+
+		return get(VAR_NoMSAA);
+	}
 
 
-	template<bool MSAA, bool InsideGeometry>
-	PointLightMat<MSAA, InsideGeometry>::PointLightMat()
+	ShaderVariation PointLightMat::VAR_MSAA_Inside = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 2),
+		ShaderVariation::Param("INSIDE_GEOMETRY", true)
+	});
+
+	ShaderVariation PointLightMat::VAR_MSAA_Outside = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 2)
+	});
+
+	ShaderVariation PointLightMat::VAR_NoMSAA_Inside = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 1),
+		ShaderVariation::Param("INSIDE_GEOMETRY", true)
+	});
+
+	ShaderVariation PointLightMat::VAR_NoMSAA_Outside = ShaderVariation({
+		ShaderVariation::Param("MSAA_COUNT", 1)
+	});
+
+	PointLightMat::PointLightMat()
 		:mGBufferParams(mMaterial, mParamsSet)
 		:mGBufferParams(mMaterial, mParamsSet)
 	{
 	{
 		const GpuParams& gpuParams = *mParamsSet->getGpuParams();
 		const GpuParams& gpuParams = *mParamsSet->getGpuParams();
 		gpuParams.getTextureParam(GPT_FRAGMENT_PROGRAM, "gLightOcclusionTex", mLightOcclusionTexParam);
 		gpuParams.getTextureParam(GPT_FRAGMENT_PROGRAM, "gLightOcclusionTex", mLightOcclusionTexParam);
 	}
 	}
 
 
-	template<bool MSAA, bool InsideGeometry>
-	void PointLightMat<MSAA, InsideGeometry>::_initDefines(ShaderDefines& defines)
+	void PointLightMat::_initVariations(ShaderVariations& variations)
 	{
 	{
-		if (MSAA)
-			defines.set("MSAA_COUNT", 2); // Actual count doesn't matter, as long as it's greater than one
-		else
-			defines.set("MSAA_COUNT", 1);
-
-		if (InsideGeometry)
-			defines.set("INSIDE_GEOMETRY", 1);
+		variations.add(VAR_MSAA_Inside);
+		variations.add(VAR_MSAA_Outside);
+		variations.add(VAR_NoMSAA_Inside);
+		variations.add(VAR_NoMSAA_Outside);
 	}
 	}
 
 
-	template<bool MSAA, bool InsideGeometry>
-	void PointLightMat<MSAA, InsideGeometry>::bind(const RenderTargets& renderTargets, 
+	void PointLightMat::bind(const GBufferInput& gBufferInput, const SPtr<Texture>& lightOcclusion, 
 		const SPtr<GpuParamBlockBuffer>& perCamera)
 		const SPtr<GpuParamBlockBuffer>& perCamera)
 	{
 	{
 		RendererUtility::instance().setPass(mMaterial, 0);
 		RendererUtility::instance().setPass(mMaterial, 0);
 
 
-		mGBufferParams.bind(renderTargets);
-		mLightOcclusionTexParam.set(renderTargets.get(RTT_LightOcclusion));
+		mGBufferParams.bind(gBufferInput);
+		mLightOcclusionTexParam.set(lightOcclusion);
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
 	}
 	}
 
 
-	template<bool MSAA, bool InsideGeometry>
-	void PointLightMat<MSAA, InsideGeometry>::setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight)
+	void PointLightMat::setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight)
 	{
 	{
 		mParamsSet->setParamBlockBuffer("PerLight", perLight, true);
 		mParamsSet->setParamBlockBuffer("PerLight", perLight, true);
 		
 		
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().setPassParams(mParamsSet);
 	}
 	}
 
 
-	template class PointLightMat<false, false>;
-	template class PointLightMat<false, true>;
-	template class PointLightMat<true, false>;
-	template class PointLightMat<true, true>;
+	PointLightMat* PointLightMat::getVariation(bool msaa, bool inside)
+	{
+		if(msaa)
+		{
+			if (inside)
+				return get(VAR_MSAA_Inside);
+			else
+				return get(VAR_MSAA_Outside);
+		}
+		else
+		{
+			if (inside)
+				return get(VAR_NoMSAA_Inside);
+			else
+				return get(VAR_NoMSAA_Outside);
+		}
+	}
 
 
 	StandardDeferred::StandardDeferred()
 	StandardDeferred::StandardDeferred()
 	{
 	{
@@ -98,7 +129,7 @@ namespace bs { namespace ct {
 	}
 	}
 
 
 	void StandardDeferred::renderLight(LightType lightType, const RendererLight& light, const RendererView& view, 
 	void StandardDeferred::renderLight(LightType lightType, const RendererLight& light, const RendererView& view, 
-		const RenderTargets& renderTargets)
+		const GBufferInput& gBufferInput, const SPtr<Texture>& lightOcclusion)
 	{
 	{
 		const auto& viewProps = view.getProperties();
 		const auto& viewProps = view.getProperties();
 
 
@@ -109,16 +140,9 @@ namespace bs { namespace ct {
 
 
 		if (lightType == LightType::Directional)
 		if (lightType == LightType::Directional)
 		{
 		{
-			if(isMSAA)
-			{
-				mDirLightMat_T.bind(renderTargets, perViewBuffer);
-				mDirLightMat_T.setPerLightParams(mPerLightBuffer);
-			}
-			else
-			{
-				mDirLightMat_F.bind(renderTargets, perViewBuffer);
-				mDirLightMat_F.setPerLightParams(mPerLightBuffer);
-			}
+			DirectionalLightMat* material = DirectionalLightMat::getVariation(isMSAA);
+			material->bind(gBufferInput, lightOcclusion, perViewBuffer);
+			material->setPerLightParams(mPerLightBuffer);
 
 
 			gRendererUtility().drawScreenQuad();
 			gRendererUtility().drawScreenQuad();
 		}
 		}
@@ -133,32 +157,10 @@ namespace bs { namespace ct {
 			float boundRadius = light.internal->getBounds().getRadius() + viewProps.nearPlane * 3.0f;
 			float boundRadius = light.internal->getBounds().getRadius() + viewProps.nearPlane * 3.0f;
 
 
 			bool isInside = distSqrd < (boundRadius * boundRadius);
 			bool isInside = distSqrd < (boundRadius * boundRadius);
-			if(isMSAA)
-			{
-				if(isInside)
-				{
-					mPointLightMat_TT.bind(renderTargets, perViewBuffer);
-					mPointLightMat_TT.setPerLightParams(mPerLightBuffer);
-				}
-				else
-				{
-					mPointLightMat_TF.bind(renderTargets, perViewBuffer);
-					mPointLightMat_TF.setPerLightParams(mPerLightBuffer);
-				}
-			}
-			else
-			{
-				if(isInside)
-				{
-					mPointLightMat_FT.bind(renderTargets, perViewBuffer);
-					mPointLightMat_FT.setPerLightParams(mPerLightBuffer);
-				}
-				else
-				{
-					mPointLightMat_FF.bind(renderTargets, perViewBuffer);
-					mPointLightMat_TF.setPerLightParams(mPerLightBuffer);
-				}
-			}
+
+			PointLightMat* material = PointLightMat::getVariation(isMSAA, isInside);
+			material->bind(gBufferInput, lightOcclusion, perViewBuffer);
+			material->setPerLightParams(mPerLightBuffer);
 
 
 			SPtr<Mesh> stencilMesh;
 			SPtr<Mesh> stencilMesh;
 			if(lightType == LightType::Radial)
 			if(lightType == LightType::Radial)

+ 2 - 2
Source/SBansheeEngine/CMakeSources.cmake

@@ -125,7 +125,7 @@ set(BS_SBANSHEEENGINE_INC_WRAPPERS
 	"Include/BsScriptScene.h"
 	"Include/BsScriptScene.h"
 	"Include/BsScriptResources.h"
 	"Include/BsScriptResources.h"
 	"Include/BsScriptResourceRef.h"
 	"Include/BsScriptResourceRef.h"
-	"Include/BsScriptPostProcessSettings.h"
+	"Include/BsScriptRenderSettings.h"
 	"Include/BsScriptAudioClip.h"
 	"Include/BsScriptAudioClip.h"
 	"Include/BsScriptAudio.h"
 	"Include/BsScriptAudio.h"
 	"Include/BsScriptAudioSource.h"
 	"Include/BsScriptAudioSource.h"
@@ -250,7 +250,7 @@ set(BS_SBANSHEEENGINE_SRC_WRAPPERS
 	"Source/BsScriptRenderTexture.cpp"
 	"Source/BsScriptRenderTexture.cpp"
 	"Source/BsScriptRenderTarget.cpp"
 	"Source/BsScriptRenderTarget.cpp"
 	"Source/BsScriptRenderable.cpp"
 	"Source/BsScriptRenderable.cpp"
-	"Source/BsScriptPostProcessSettings.cpp"
+	"Source/BsScriptRenderSettings.cpp"
 	"Source/BsScriptAudioClip.cpp"
 	"Source/BsScriptAudioClip.cpp"
 	"Source/BsScriptAudio.cpp"
 	"Source/BsScriptAudio.cpp"
 	"Source/BsScriptAudioSource.cpp"
 	"Source/BsScriptAudioSource.cpp"

+ 3 - 9
Source/SBansheeEngine/Include/BsScriptCamera.h

@@ -12,7 +12,7 @@
 #include "BsMatrix4.h"
 #include "BsMatrix4.h"
 #include "BsRect2.h"
 #include "BsRect2.h"
 #include "BsColor.h"
 #include "BsColor.h"
-#include "BsPostProcessSettings.h"
+#include "BsRenderSettings.h"
 
 
 namespace bs
 namespace bs
 {
 {
@@ -87,14 +87,8 @@ namespace bs
 		static int internal_GetPriority(ScriptCamera* instance);
 		static int internal_GetPriority(ScriptCamera* instance);
 		static void internal_SetPriority(ScriptCamera* instance, int value);
 		static void internal_SetPriority(ScriptCamera* instance, int value);
 
 
-		static bool internal_GetHDR(ScriptCamera* instance);
-		static void internal_SetHDR(ScriptCamera* instance, bool value);
-
-		static bool internal_GetNoLighting(ScriptCamera* instance);
-		static void internal_SetNoLighting(ScriptCamera* instance, bool value);
-
-		static MonoObject* internal_GetPostProcessSettings(ScriptCamera* instance);
-		static void internal_SetPostProcessSettings(ScriptCamera* instance, MonoObject* value);
+		static MonoObject* internal_GetRenderSettings(ScriptCamera* instance);
+		static void internal_SetRenderSettings(ScriptCamera* instance, MonoObject* value);
 
 
 		static UINT64 internal_GetLayers(ScriptCamera* instance);
 		static UINT64 internal_GetLayers(ScriptCamera* instance);
 		static void internal_SetLayers(ScriptCamera* instance, UINT64 value);
 		static void internal_SetLayers(ScriptCamera* instance, UINT64 value);

+ 11 - 7
Source/SBansheeEngine/Include/BsScriptPostProcessSettings.h → Source/SBansheeEngine/Include/BsScriptRenderSettings.h

@@ -7,7 +7,7 @@
 
 
 namespace bs
 namespace bs
 {
 {
-	struct StandardPostProcessSettings;
+	struct RenderSettings;
 	struct AutoExposureSettings;
 	struct AutoExposureSettings;
 	struct TonemappingSettings;
 	struct TonemappingSettings;
 	struct WhiteBalanceSettings;
 	struct WhiteBalanceSettings;
@@ -118,20 +118,20 @@ namespace bs
 		static MonoField* sOffset;
 		static MonoField* sOffset;
 	};
 	};
 
 
-	/**	Interop class between C++ & CLR for PostProcessSettings. */
-	class BS_SCR_BE_EXPORT ScriptPostProcessSettings : public ScriptObject<ScriptPostProcessSettings>
+	/**	Interop class between C++ & CLR for RenderSettings. */
+	class BS_SCR_BE_EXPORT ScriptRenderSettings : public ScriptObject<ScriptRenderSettings>
 	{
 	{
 	public:
 	public:
-		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "PostProcessSettings")
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "RenderSettings")
 
 
 		/** Converts managed object its native counterpart. */
 		/** Converts managed object its native counterpart. */
-		static SPtr<StandardPostProcessSettings> toNative(MonoObject* object);
+		static SPtr<RenderSettings> toNative(MonoObject* object);
 
 
 		/** Converts native object to its managed counterpart. */
 		/** Converts native object to its managed counterpart. */
-		static MonoObject* toManaged(const SPtr<StandardPostProcessSettings>& value);
+		static MonoObject* toManaged(const SPtr<RenderSettings>& value);
 
 
 	private:
 	private:
-		ScriptPostProcessSettings(MonoObject* instance);
+		ScriptRenderSettings(MonoObject* instance);
 
 
 		/************************************************************************/
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
 		/* 								CLR HOOKS						   		*/
@@ -146,6 +146,10 @@ namespace bs
 		static MonoField* sColorGrading;
 		static MonoField* sColorGrading;
 		static MonoField* sExposureScale;
 		static MonoField* sExposureScale;
 		static MonoField* sGamma;
 		static MonoField* sGamma;
+		static MonoField* sEnableHDR;
+		static MonoField* sEnableLighting;
+		static MonoField* sEnableShadows;
+		static MonoField* sOverlayOnly;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 12 - 49
Source/SBansheeEngine/Source/BsScriptCamera.cpp

@@ -15,8 +15,8 @@
 #include "BsRenderWindow.h"
 #include "BsRenderWindow.h"
 #include "BsRenderTexture.h"
 #include "BsRenderTexture.h"
 #include "BsGUIManager.h"
 #include "BsGUIManager.h"
-#include "BsStandardPostProcessSettings.h"
-#include "BsScriptPostProcessSettings.h"
+#include "BsRenderSettings.h"
+#include "BsScriptRenderSettings.h"
 
 
 namespace bs
 namespace bs
 {
 {
@@ -73,14 +73,8 @@ namespace bs
 		metaData.scriptClass->addInternalCall("Internal_GetPriority", &ScriptCamera::internal_GetPriority);
 		metaData.scriptClass->addInternalCall("Internal_GetPriority", &ScriptCamera::internal_GetPriority);
 		metaData.scriptClass->addInternalCall("Internal_SetPriority", &ScriptCamera::internal_SetPriority);
 		metaData.scriptClass->addInternalCall("Internal_SetPriority", &ScriptCamera::internal_SetPriority);
 
 
-		metaData.scriptClass->addInternalCall("Internal_GetHDR", &ScriptCamera::internal_GetHDR);
-		metaData.scriptClass->addInternalCall("Internal_SetHDR", &ScriptCamera::internal_SetHDR);
-
-		metaData.scriptClass->addInternalCall("Internal_GetNoLighting", &ScriptCamera::internal_GetNoLighting);
-		metaData.scriptClass->addInternalCall("Internal_SetNoLighting", &ScriptCamera::internal_SetNoLighting);
-
-		metaData.scriptClass->addInternalCall("Internal_GetPostProcessSettings", &ScriptCamera::internal_GetPostProcessSettings);
-		metaData.scriptClass->addInternalCall("Internal_SetPostProcessSettings", &ScriptCamera::internal_SetPostProcessSettings);
+		metaData.scriptClass->addInternalCall("Internal_GetRenderSettings", &ScriptCamera::internal_GetRenderSettings);
+		metaData.scriptClass->addInternalCall("Internal_SetRenderSettings", &ScriptCamera::internal_SetRenderSettings);
 
 
 		metaData.scriptClass->addInternalCall("Internal_GetLayers", &ScriptCamera::internal_GetLayers);
 		metaData.scriptClass->addInternalCall("Internal_GetLayers", &ScriptCamera::internal_GetLayers);
 		metaData.scriptClass->addInternalCall("Internal_SetLayers", &ScriptCamera::internal_SetLayers);
 		metaData.scriptClass->addInternalCall("Internal_SetLayers", &ScriptCamera::internal_SetLayers);
@@ -294,49 +288,18 @@ namespace bs
 		instance->mCamera->setPriority(value);
 		instance->mCamera->setPriority(value);
 	}
 	}
 
 
-	bool ScriptCamera::internal_GetHDR(ScriptCamera* instance)
-	{
-		return instance->mCamera->getFlags().isSet(CameraFlag::HDR);
-	}
-
-	void ScriptCamera::internal_SetHDR(ScriptCamera* instance, bool value)
+	MonoObject* ScriptCamera::internal_GetRenderSettings(ScriptCamera* instance)
 	{
 	{
-		instance->mCamera->setFlag(CameraFlag::HDR, value);
-	}
-
-	bool ScriptCamera::internal_GetNoLighting(ScriptCamera* instance)
-	{
-		return instance->mCamera->getFlags().isSet(CameraFlag::NoLighting);
-	}
-
-	void ScriptCamera::internal_SetNoLighting(ScriptCamera* instance, bool value)
-	{
-		instance->mCamera->setFlag(CameraFlag::NoLighting, value);
-	}
-
-	MonoObject* ScriptCamera::internal_GetPostProcessSettings(ScriptCamera* instance)
-	{
-		SPtr<PostProcessSettings> ppSettings = instance->mCamera->getPostProcessSettings();
-		SPtr<StandardPostProcessSettings> standardPPSettings;
-		if(ppSettings != nullptr)
-		{
-			if (!rtti_is_of_type<StandardPostProcessSettings>(ppSettings))
-			{
-				assert(false && "Invalid post process settings type.");
-			}
-			else
-				standardPPSettings = std::static_pointer_cast<StandardPostProcessSettings>(ppSettings);
-		}
-
-		if (standardPPSettings == nullptr)
-			standardPPSettings = bs_shared_ptr_new<StandardPostProcessSettings>();
+		SPtr<RenderSettings> settings = instance->mCamera->getRenderSettings();
+		if (settings == nullptr)
+			settings = bs_shared_ptr_new<RenderSettings>();
 
 
-		return ScriptPostProcessSettings::toManaged(standardPPSettings);
+		return ScriptRenderSettings::toManaged(settings);
 	}
 	}
 
 
-	void ScriptCamera::internal_SetPostProcessSettings(ScriptCamera* instance, MonoObject* value)
+	void ScriptCamera::internal_SetRenderSettings(ScriptCamera* instance, MonoObject* value)
 	{
 	{
-		instance->mCamera->setPostProcessSettings(ScriptPostProcessSettings::toNative(value));
+		instance->mCamera->setRenderSettings(ScriptRenderSettings::toNative(value));
 	}
 	}
 
 
 	UINT64 ScriptCamera::internal_GetLayers(ScriptCamera* instance)
 	UINT64 ScriptCamera::internal_GetLayers(ScriptCamera* instance)
@@ -541,4 +504,4 @@ namespace bs
 
 
 		ScriptObject::_onManagedInstanceDeleted();
 		ScriptObject::_onManagedInstanceDeleted();
 	}
 	}
-}
+}

+ 35 - 19
Source/SBansheeEngine/Source/BsScriptPostProcessSettings.cpp → Source/SBansheeEngine/Source/BsScriptRenderSettings.cpp

@@ -1,12 +1,12 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsScriptPostProcessSettings.h"
+#include "BsScriptRenderSettings.h"
 #include "BsMonoManager.h"
 #include "BsMonoManager.h"
 #include "BsMonoAssembly.h"
 #include "BsMonoAssembly.h"
 #include "BsMonoClass.h"
 #include "BsMonoClass.h"
 #include "BsMonoUtil.h"
 #include "BsMonoUtil.h"
 #include "BsCoreThread.h"
 #include "BsCoreThread.h"
-#include "BsStandardPostProcessSettings.h"
+#include "BsRenderSettings.h"
 
 
 namespace bs
 namespace bs
 {
 {
@@ -194,22 +194,26 @@ namespace bs
 		return object;
 		return object;
 	}
 	}
 
 
-	MonoField* ScriptPostProcessSettings::sEnableAutoExposure = nullptr;
-	MonoField* ScriptPostProcessSettings::sAutoExposure = nullptr;
-	MonoField* ScriptPostProcessSettings::sEnableTonemapping = nullptr;
-	MonoField* ScriptPostProcessSettings::sTonemapping = nullptr;
-	MonoField* ScriptPostProcessSettings::sWhiteBalance = nullptr;
-	MonoField* ScriptPostProcessSettings::sColorGrading = nullptr;
-	MonoField* ScriptPostProcessSettings::sExposureScale = nullptr;
-	MonoField* ScriptPostProcessSettings::sGamma = nullptr;
-
-	ScriptPostProcessSettings::ScriptPostProcessSettings(MonoObject* instance)
+	MonoField* ScriptRenderSettings::sEnableAutoExposure = nullptr;
+	MonoField* ScriptRenderSettings::sAutoExposure = nullptr;
+	MonoField* ScriptRenderSettings::sEnableTonemapping = nullptr;
+	MonoField* ScriptRenderSettings::sTonemapping = nullptr;
+	MonoField* ScriptRenderSettings::sWhiteBalance = nullptr;
+	MonoField* ScriptRenderSettings::sColorGrading = nullptr;
+	MonoField* ScriptRenderSettings::sExposureScale = nullptr;
+	MonoField* ScriptRenderSettings::sGamma = nullptr;
+	MonoField* ScriptRenderSettings::sEnableHDR = nullptr;
+	MonoField* ScriptRenderSettings::sEnableLighting = nullptr;
+	MonoField* ScriptRenderSettings::sEnableShadows = nullptr;
+	MonoField* ScriptRenderSettings::sOverlayOnly = nullptr;
+
+	ScriptRenderSettings::ScriptRenderSettings(MonoObject* instance)
 		:ScriptObject(instance)
 		:ScriptObject(instance)
 	{ }
 	{ }
 
 
-	void ScriptPostProcessSettings::initRuntimeData()
+	void ScriptRenderSettings::initRuntimeData()
 	{
 	{
-		metaData.scriptClass->addInternalCall("Internal_CreateDefault", &ScriptPostProcessSettings::internal_CreateDefault);
+		metaData.scriptClass->addInternalCall("Internal_CreateDefault", &ScriptRenderSettings::internal_CreateDefault);
 
 
 		sEnableAutoExposure = metaData.scriptClass->getField("EnableAutoExposure");
 		sEnableAutoExposure = metaData.scriptClass->getField("EnableAutoExposure");
 		sAutoExposure = metaData.scriptClass->getField("AutoExposure");
 		sAutoExposure = metaData.scriptClass->getField("AutoExposure");
@@ -219,16 +223,24 @@ namespace bs
 		sColorGrading = metaData.scriptClass->getField("ColorGrading");
 		sColorGrading = metaData.scriptClass->getField("ColorGrading");
 		sExposureScale = metaData.scriptClass->getField("ExposureScale");
 		sExposureScale = metaData.scriptClass->getField("ExposureScale");
 		sGamma = metaData.scriptClass->getField("Gamma");
 		sGamma = metaData.scriptClass->getField("Gamma");
+		sEnableHDR = metaData.scriptClass->getField("EnableHDR");
+		sEnableLighting = metaData.scriptClass->getField("EnableLighting");
+		sEnableShadows = metaData.scriptClass->getField("EnableShadows");
+		sOverlayOnly = metaData.scriptClass->getField("OverlayOnly");
 	}
 	}
 
 
-	SPtr<StandardPostProcessSettings> ScriptPostProcessSettings::toNative(MonoObject* object)
+	SPtr<RenderSettings> ScriptRenderSettings::toNative(MonoObject* object)
 	{
 	{
-		SPtr<StandardPostProcessSettings> output = bs_shared_ptr_new<StandardPostProcessSettings>();
+		SPtr<RenderSettings> output = bs_shared_ptr_new<RenderSettings>();
 
 
 		sEnableAutoExposure->get(object, &output->enableAutoExposure);
 		sEnableAutoExposure->get(object, &output->enableAutoExposure);
 		sEnableTonemapping->get(object, &output->enableTonemapping);
 		sEnableTonemapping->get(object, &output->enableTonemapping);
 		sExposureScale->get(object, &output->exposureScale);
 		sExposureScale->get(object, &output->exposureScale);
 		sGamma->get(object, &output->gamma);
 		sGamma->get(object, &output->gamma);
+		sEnableHDR->get(object, &output->enableHDR);
+		sEnableLighting->get(object, &output->enableLighting);
+		sEnableShadows->get(object, &output->enableShadows);
+		sOverlayOnly->get(object, &output->overlayOnly);
 
 
 		MonoObject* autoExposureMono;
 		MonoObject* autoExposureMono;
 		sAutoExposure->get(object, &autoExposureMono);
 		sAutoExposure->get(object, &autoExposureMono);
@@ -249,7 +261,7 @@ namespace bs
 		return output;
 		return output;
 	}
 	}
 
 
-	MonoObject* ScriptPostProcessSettings::toManaged(const SPtr<StandardPostProcessSettings>& value)
+	MonoObject* ScriptRenderSettings::toManaged(const SPtr<RenderSettings>& value)
 	{
 	{
 		MonoObject* object = metaData.scriptClass->createInstance();
 		MonoObject* object = metaData.scriptClass->createInstance();
 
 
@@ -257,6 +269,10 @@ namespace bs
 		sEnableTonemapping->set(object, &value->enableTonemapping);
 		sEnableTonemapping->set(object, &value->enableTonemapping);
 		sExposureScale->set(object, &value->exposureScale);
 		sExposureScale->set(object, &value->exposureScale);
 		sGamma->set(object, &value->gamma);
 		sGamma->set(object, &value->gamma);
+		sEnableHDR->set(object, &value->enableHDR);
+		sEnableLighting->set(object, &value->enableLighting);
+		sEnableShadows->set(object, &value->enableShadows);
+		sOverlayOnly->set(object, &value->overlayOnly);
 
 
 		MonoObject* autoExposureMono = ScriptAutoExposureSettings::toManaged(value->autoExposure);
 		MonoObject* autoExposureMono = ScriptAutoExposureSettings::toManaged(value->autoExposure);
 		sAutoExposure->set(object, autoExposureMono);
 		sAutoExposure->set(object, autoExposureMono);
@@ -273,8 +289,8 @@ namespace bs
 		return object;
 		return object;
 	}
 	}
 
 
-	MonoObject* ScriptPostProcessSettings::internal_CreateDefault()
+	MonoObject* ScriptRenderSettings::internal_CreateDefault()
 	{
 	{
-		return toManaged(bs_shared_ptr_new<StandardPostProcessSettings>());
+		return toManaged(bs_shared_ptr_new<RenderSettings>());
 	}
 	}
 }
 }

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott