瀏覽代碼

Final big bulk of work for shadow mapping (Untested)

BearishSun 8 年之前
父節點
當前提交
4891a95151
共有 30 個文件被更改,包括 761 次插入299 次删除
  1. 16 0
      Data/Raw/Engine/Includes/DeferredLightCommon.bslinc
  2. 6 4
      Data/Raw/Engine/Includes/LightGridCommon.bslinc
  3. 8 1
      Data/Raw/Engine/Shaders/DeferredDirectionalLight.bsl
  4. 8 2
      Data/Raw/Engine/Shaders/DeferredPointLight.bsl
  5. 3 3
      Data/Raw/Engine/Shaders/LightGridLLCreation.bsl
  6. 1 1
      Data/Raw/Engine/Shaders/ShadowProject.bsl
  7. 1 1
      Data/Raw/Engine/Shaders/ShadowProjectOmni.bsl
  8. 2 8
      Data/Raw/Engine/Shaders/TiledDeferredImageBasedLighting.bsl
  9. 12 9
      Data/Raw/Engine/Shaders/TiledDeferredLighting.bsl
  10. 1 1
      Data/Raw/Engine/Shaders/Transparent.bsl
  11. 3 1
      Source/BansheeCore/Include/BsCamera.h
  12. 3 1
      Source/BansheeCore/Include/BsLight.h
  13. 2 0
      Source/RenderBeast/CMakeSources.cmake
  14. 0 1
      Source/RenderBeast/Include/BsImageBasedLighting.h
  15. 4 3
      Source/RenderBeast/Include/BsLightGrid.h
  16. 46 64
      Source/RenderBeast/Include/BsLightRendering.h
  17. 1 3
      Source/RenderBeast/Include/BsRenderBeast.h
  18. 20 3
      Source/RenderBeast/Include/BsRenderTargets.h
  19. 25 1
      Source/RenderBeast/Include/BsRendererView.h
  20. 7 4
      Source/RenderBeast/Include/BsShadowRendering.h
  21. 83 0
      Source/RenderBeast/Include/BsStandardDeferredLighting.h
  22. 2 12
      Source/RenderBeast/Source/BsImageBasedLighting.cpp
  23. 19 9
      Source/RenderBeast/Source/BsLightGrid.cpp
  24. 111 111
      Source/RenderBeast/Source/BsLightRendering.cpp
  25. 79 48
      Source/RenderBeast/Source/BsRenderBeast.cpp
  26. 74 2
      Source/RenderBeast/Source/BsRenderTargets.cpp
  27. 1 0
      Source/RenderBeast/Source/BsRendererScene.cpp
  28. 45 0
      Source/RenderBeast/Source/BsRendererView.cpp
  29. 6 6
      Source/RenderBeast/Source/BsShadowRendering.cpp
  30. 172 0
      Source/RenderBeast/Source/BsStandardDeferredLighting.cpp

+ 16 - 0
Data/Raw/Engine/Includes/DeferredLightCommon.bslinc

@@ -19,6 +19,16 @@ mixin DeferredLightCommon
 		#endif
 		#endif
 	};
 	};
 	
 	
+	blend
+	{
+		target
+		{
+			enabled = true;
+			color = { one, one, add };
+			writemask = RGB;			
+		};
+	};
+	
 	raster
 	raster
 	{
 	{
 		#ifdef INSIDE_GEOMETRY
 		#ifdef INSIDE_GEOMETRY
@@ -67,5 +77,11 @@ mixin DeferredLightCommon
 
 
 			return output;
 			return output;
 		}
 		}
+		
+		#if MSAA_COUNT > 1
+		Texture2DMS<float4> gLightOcclusionTex;
+		#else
+		Texture2D<float4> gLightOcclusionTex;
+		#endif
 	};
 	};
 };
 };

+ 6 - 4
Data/Raw/Engine/Includes/LightGridCommon.bslinc

@@ -4,10 +4,12 @@ mixin LightGridCommon
 	{
 	{
 		cbuffer GridParams : register(b4)
 		cbuffer GridParams : register(b4)
 		{
 		{
-			// Offsets at which specific light types begin in gLights buffer
-			// Assumed directional lights start at 0
-			// x - offset to point lights, y - offset to spot lights, z - total number of lights
-			uint3 gLightOffsets;
+			// Number of lights per type in the lights buffer
+			// x - directional lights, y - radial lights, z - spot lights, w - total number of lights
+			uint4 gLightCounts;
+			// Strides between different light types in the light buffer
+			// x - stride to radial lights, y - stride to spot lights. Directional lights are assumed to start at 0.
+			uint2 gLightStrides;			
 			uint gNumReflProbes;
 			uint gNumReflProbes;
 			uint gNumCells;
 			uint gNumCells;
 			uint3 gGridSize;
 			uint3 gGridSize;

+ 8 - 1
Data/Raw/Engine/Shaders/DeferredDirectionalLight.bsl

@@ -58,7 +58,14 @@ technique DeferredDirectionalLight
 				roughness2 *= roughness2;
 				roughness2 *= roughness2;
 				
 				
 				LightData lightData = getLightData();
 				LightData lightData = getLightData();
-				return float4(getLuminanceDirectional(lightData, worldPosition, V, R, surfaceData), 1.0f);
+				
+				#if MSAA_COUNT > 1
+				float occlusion = 1.0f - gLightOcclusionTex.Load(pixelPos, 0).r;
+				#else
+				float occlusion = 1.0f - gLightOcclusionTex.Load(int3(pixelPos, 0)).r;
+				#endif
+				
+				return float4(getLuminanceDirectional(lightData, worldPosition, V, R, surfaceData) * occlusion, 1.0f);
 			}
 			}
 			else
 			else
 				return float4(0.0f, 0.0f, 0.0f, 0.0f);
 				return float4(0.0f, 0.0f, 0.0f, 0.0f);

+ 8 - 2
Data/Raw/Engine/Shaders/DeferredPointLight.bsl

@@ -108,11 +108,17 @@ technique DeferredPointLight
 				
 				
 				LightData lightData = getLightData();
 				LightData lightData = getLightData();
 				
 				
+				#if MSAA_COUNT > 1
+				float occlusion = 1.0f - gLightOcclusionTex.Load(pixelPos, 0).r;
+				#else
+				float occlusion = 1.0f - gLightOcclusionTex.Load(int3(pixelPos, 0)).r;
+				#endif
+				
 				bool isSpot = gShiftedLightPositionAndType.w > 0.5f;
 				bool isSpot = gShiftedLightPositionAndType.w > 0.5f;
 				if(isSpot)
 				if(isSpot)
-					return float4(getLuminanceSpot(lightData, worldPosition, V, R, roughness2, surfaceData), 1.0f);
+					return float4(getLuminanceSpot(lightData, worldPosition, V, R, roughness2, surfaceData) * occlusion, 1.0f);
 				else // Radial
 				else // Radial
-					return float4(getLuminanceRadial(lightData, worldPosition, V, R, roughness2, surfaceData), 1.0f);
+					return float4(getLuminanceRadial(lightData, worldPosition, V, R, roughness2, surfaceData) * occlusion, 1.0f);
 			}
 			}
 			else
 			else
 				return float4(0.0f, 0.0f, 0.0f, 0.0f);
 				return float4(0.0f, 0.0f, 0.0f, 0.0f);

+ 3 - 3
Data/Raw/Engine/Shaders/LightGridLLCreation.bsl

@@ -105,9 +105,9 @@ technique LightGridLLCreation
 			
 			
 			for(uint type = 1; type < 3; ++type)
 			for(uint type = 1; type < 3; ++type)
 			{
 			{
-				uint lightOffset = gLightOffsets[type - 1];
-				uint lightEnd = gLightOffsets[type];
-				for(uint i = lightOffset; i < lightEnd; ++i)
+				uint lightsStart = gLightStrides[type - 1];
+				uint lightsEnd = lightsStart + gLightCounts[type];
+				for(uint i = lightsStart; i < lightsEnd; ++i)
 				{
 				{
 					float4 lightPosition = mul(gMatView, float4(gLights[i].position, 1.0f));
 					float4 lightPosition = mul(gMatView, float4(gLights[i].position, 1.0f));
 					float lightRadius = gLights[i].attRadius;
 					float lightRadius = gLights[i].attRadius;

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

@@ -39,7 +39,7 @@ technique ShadowProject
 		{
 		{
 			enabled = true;
 			enabled = true;
 			writemask = R;
 			writemask = R;
-			color = { one, one, min };
+			color = { one, one, max };
 		};
 		};
 	};	
 	};	
 	#endif
 	#endif

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

@@ -12,7 +12,7 @@ technique ShadowProjectOmni
 		{
 		{
 			enabled = true;
 			enabled = true;
 			writemask = R;
 			writemask = R;
-			color = { one, one, min };
+			color = { one, one, max };
 		};
 		};
 	};
 	};
 	
 	

+ 2 - 8
Data/Raw/Engine/Shaders/TiledDeferredImageBasedLighting.bsl

@@ -22,7 +22,7 @@ technique TiledDeferredImageBasedLighting
 		}
 		}
 	
 	
 		#if MSAA_COUNT > 1
 		#if MSAA_COUNT > 1
-		Buffer<float4> gInColor;
+		Texture2DMS<float4> gInColor;
 		RWBuffer<float4> gOutput;
 		RWBuffer<float4> gOutput;
 		
 		
 		uint getLinearAddress(uint2 coord, uint sampleIndex)
 		uint getLinearAddress(uint2 coord, uint sampleIndex)
@@ -35,12 +35,6 @@ technique TiledDeferredImageBasedLighting
 			uint idx = getLinearAddress(coord, sampleIndex);
 			uint idx = getLinearAddress(coord, sampleIndex);
 			gOutput[idx] = color;
 			gOutput[idx] = color;
 		}
 		}
-		
-		float4 readInColorSample(uint2 coord, uint sampleIndex)
-		{
-			uint idx = getLinearAddress(coord, sampleIndex);
-			return gInColor[idx];
-		}
 
 
 		#else
 		#else
 		Texture2D<float4> gInColor;
 		Texture2D<float4> gInColor;
@@ -165,7 +159,7 @@ technique TiledDeferredImageBasedLighting
 			
 			
 			float4 existingColor;
 			float4 existingColor;
 			#if MSAA_COUNT > 1
 			#if MSAA_COUNT > 1
-			existingColor = readInColorSample(pixelPos, sampleIdx);
+			existingColor = gInColor.Load(pixelPos.xy, sampleIdx);
 			#else
 			#else
 			existingColor = gInColor.Load(int3(pixelPos.xy, 0));
 			existingColor = gInColor.Load(int3(pixelPos.xy, 0));
 			#endif				
 			#endif				

+ 12 - 9
Data/Raw/Engine/Shaders/TiledDeferredLighting.bsl

@@ -16,12 +16,15 @@ technique TiledDeferredLighting
 	code
 	code
 	{	
 	{	
 		[internal]
 		[internal]
-		cbuffer Params : register(b0)
+		cbuffer Params
 		{
 		{
-			// Offsets at which specific light types begin in gLights buffer
-			// Assumed directional lights start at 0
-			// x - offset to point lights, y - offset to spot lights, z - total number of lights
-			uint3 gLightOffsets;
+			// Number of lights per type in the lights buffer
+			// x - directional lights, y - radial lights, z - spot lights, w - total number of lights
+			uint4 gLightCounts;
+			// Strides between different light types in the light buffer
+			// x - stride to radial lights, y - stride to spot lights. Directional lights are assumed to start at 0.
+			uint2 gLightStrides;
+			
 			uint2 gFramebufferSize;
 			uint2 gFramebufferSize;
 		}
 		}
 	
 	
@@ -60,7 +63,7 @@ technique TiledDeferredLighting
 			float3 worldPosition = worldPosition4D.xyz / worldPosition4D.w;
 			float3 worldPosition = worldPosition4D.xyz / worldPosition4D.w;
 			
 			
 			uint4 lightOffsets;
 			uint4 lightOffsets;
-			lightOffsets.x = gLightOffsets[0];
+			lightOffsets.x = gLightCounts[0];
 			lightOffsets.y = 0;
 			lightOffsets.y = 0;
 			lightOffsets.z = sNumLightsPerType[0];
 			lightOffsets.z = sNumLightsPerType[0];
 			lightOffsets.w = sTotalNumLights;
 			lightOffsets.w = sTotalNumLights;
@@ -194,9 +197,9 @@ technique TiledDeferredLighting
 			// Find radial & spot lights overlapping the tile
 			// Find radial & spot lights overlapping the tile
 			for(uint type = 0; type < 2; type++)
 			for(uint type = 0; type < 2; type++)
 			{
 			{
-				uint lightOffset = threadIndex + gLightOffsets[type];
-				uint lightsEnd = gLightOffsets[type + 1];
-				for (uint i = lightOffset; i < lightsEnd && i < MAX_LIGHTS; i += TILE_SIZE)
+				uint lightsStart = threadIndex + gLightStrides[type];
+				uint lightsEnd = lightsStart + gLightCounts[type + 1];
+				for (uint i = lightsStart; i < lightsEnd && i < MAX_LIGHTS; i += TILE_SIZE)
 				{
 				{
 					float4 lightPosition = mul(gMatView, float4(gLights[i].position, 1.0f));
 					float4 lightPosition = mul(gMatView, float4(gLights[i].position, 1.0f));
 					float lightRadius = gLights[i].attRadius;
 					float lightRadius = gLights[i].attRadius;

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

@@ -69,7 +69,7 @@ mixin Surface
 			uint3 lightOffsetAndSize = gGridLightOffsetsAndSize[cellIdx].rgb;
 			uint3 lightOffsetAndSize = gGridLightOffsetsAndSize[cellIdx].rgb;
 			
 			
 			uint4 lightOffsets;
 			uint4 lightOffsets;
-			lightOffsets.x = gLightOffsets[0];
+			lightOffsets.x = gLightCounts.x;
 			lightOffsets.y = lightOffsetAndSize.x;
 			lightOffsets.y = lightOffsetAndSize.x;
 			lightOffsets.z = lightOffsets.y + lightOffsetAndSize.y;
 			lightOffsets.z = lightOffsets.y + lightOffsetAndSize.y;
 			lightOffsets.w = lightOffsets.z + lightOffsetAndSize.z;
 			lightOffsets.w = lightOffsets.z + lightOffsetAndSize.z;

+ 3 - 1
Source/BansheeCore/Include/BsCamera.h

@@ -48,7 +48,9 @@ namespace bs
 		 * Specify that no lighting should be applied to scene objects and everything should be rendered using their
 		 * Specify that no lighting should be applied to scene objects and everything should be rendered using their
 		 * albedo texture.
 		 * albedo texture.
 		 */
 		 */
-		NoLighting = 1 << 2
+		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;
 	typedef Flags<CameraFlag> CameraFlags;

+ 3 - 1
Source/BansheeCore/Include/BsLight.h

@@ -21,7 +21,9 @@ namespace bs
 	{
 	{
 		Directional, 
 		Directional, 
 		Radial, 
 		Radial, 
-		Spot
+		Spot,
+
+		Count // Keep at end
 	};
 	};
 
 
 	/**	Signals which portion of a light is dirty. */
 	/**	Signals which portion of a light is dirty. */

+ 2 - 0
Source/RenderBeast/CMakeSources.cmake

@@ -15,6 +15,7 @@ set(BS_RENDERBEAST_INC_NOFILTER
 	"Include/BsImageBasedLighting.h"
 	"Include/BsImageBasedLighting.h"
 	"Include/BsShadowRendering.h"
 	"Include/BsShadowRendering.h"
 	"Include/BsRendererScene.h"
 	"Include/BsRendererScene.h"
+	"Include/BsStandardDeferredLighting.h"
 )
 )
 
 
 set(BS_RENDERBEAST_SRC_NOFILTER
 set(BS_RENDERBEAST_SRC_NOFILTER
@@ -33,6 +34,7 @@ set(BS_RENDERBEAST_SRC_NOFILTER
 	"Source/BsImageBasedLighting.cpp"
 	"Source/BsImageBasedLighting.cpp"
 	"Source/BsShadowRendering.cpp"
 	"Source/BsShadowRendering.cpp"
 	"Source/BsRendererScene.cpp"
 	"Source/BsRendererScene.cpp"
+	"Source/BsStandardDeferredLighting.cpp"
 )
 )
 
 
 source_group("Header Files" FILES ${BS_RENDERBEAST_INC_NOFILTER})
 source_group("Header Files" FILES ${BS_RENDERBEAST_INC_NOFILTER})

+ 0 - 1
Source/RenderBeast/Include/BsImageBasedLighting.h

@@ -155,7 +155,6 @@ namespace bs { namespace ct
 		GpuParamTexture mGBufferDepth;
 		GpuParamTexture mGBufferDepth;
 
 
 		GpuParamTexture mInColorTextureParam;
 		GpuParamTexture mInColorTextureParam;
-		GpuParamBuffer mInColorBufferParam;
 
 
 		ImageBasedLightingParams mImageBasedParams;
 		ImageBasedLightingParams mImageBasedParams;
 
 

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

@@ -10,14 +10,15 @@
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
 	class GPUReflProbeData;
 	class GPUReflProbeData;
-	class GPULightData;
+	class VisibleLightData;
 
 
 	/** @addtogroup RenderBeast
 	/** @addtogroup RenderBeast
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
 	BS_PARAM_BLOCK_BEGIN(LightGridParamDef)
 	BS_PARAM_BLOCK_BEGIN(LightGridParamDef)
-		BS_PARAM_BLOCK_ENTRY(Vector3I, gLightOffsets)
+		BS_PARAM_BLOCK_ENTRY(Vector4I, gLightCounts)
+		BS_PARAM_BLOCK_ENTRY(Vector2I, gLightStrides)
 		BS_PARAM_BLOCK_ENTRY(INT32, gNumReflProbes)
 		BS_PARAM_BLOCK_ENTRY(INT32, gNumReflProbes)
 		BS_PARAM_BLOCK_ENTRY(INT32, gNumCells)
 		BS_PARAM_BLOCK_ENTRY(INT32, gNumCells)
 		BS_PARAM_BLOCK_ENTRY(Vector3I, gGridSize)
 		BS_PARAM_BLOCK_ENTRY(Vector3I, gGridSize)
@@ -127,7 +128,7 @@ namespace bs { namespace ct
 		LightGrid();
 		LightGrid();
 
 
 		/** Updates the light grid from the provided view. */
 		/** Updates the light grid from the provided view. */
-		void updateGrid(const RendererView& view, const GPULightData& lightData, const GPUReflProbeData& probeData, 
+		void updateGrid(const RendererView& view, const VisibleLightData& lightData, const GPUReflProbeData& probeData, 
 			bool noLighting);
 			bool noLighting);
 
 
 		/** 
 		/** 

+ 46 - 64
Source/RenderBeast/Include/BsLightRendering.h

@@ -5,9 +5,12 @@
 #include "BsRenderBeastPrerequisites.h"
 #include "BsRenderBeastPrerequisites.h"
 #include "BsRendererMaterial.h"
 #include "BsRendererMaterial.h"
 #include "BsParamBlocks.h"
 #include "BsParamBlocks.h"
+#include "BsLight.h"
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
+	struct SceneInfo;
+
 	/** @addtogroup RenderBeast
 	/** @addtogroup RenderBeast
 	 *  @{
 	 *  @{
 	 */
 	 */
@@ -27,18 +30,6 @@ namespace bs { namespace ct
 		float padding;
 		float padding;
 	};
 	};
 
 
-	BS_PARAM_BLOCK_BEGIN(PerLightParamDef)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gLightPositionAndSrcRadius)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gLightColorAndLuminance)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gLightSpotAnglesAndSqrdInvAttRadius)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gLightDirectionAndAttRadius)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gShiftedLightPositionAndType)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gLightGeometry)
-		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatConeTransform)
-	BS_PARAM_BLOCK_END
-
-	extern PerLightParamDef gPerLightParamDef;
-
 	/**	Renderer information specific to a single light. */
 	/**	Renderer information specific to a single light. */
 	class RendererLight
 	class RendererLight
 	{
 	{
@@ -64,7 +55,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 SPtr<RenderTargets>& renderTargets);
+		void bind(const RenderTargets& renderTargets);
 
 
 	private:
 	private:
 		MaterialParamTexture mGBufferA;
 		MaterialParamTexture mGBufferA;
@@ -73,51 +64,20 @@ namespace bs { namespace ct
 		MaterialParamTexture mGBufferDepth;
 		MaterialParamTexture mGBufferDepth;
 	};
 	};
 
 
-	/** Shader that renders directional light sources during deferred rendering light pass. */
-	template<bool MSAA>
-	class DirectionalLightMat : public RendererMaterial<DirectionalLightMat<MSAA>>
-	{
-		RMAT_DEF("DeferredDirectionalLight.bsl");
-
-	public:
-		DirectionalLightMat();
-
-		/** Binds the material for rendering and sets up any global parameters. */
-		void bind(const SPtr<RenderTargets>& gbuffer, const SPtr<GpuParamBlockBuffer>& perCamera);
-
-		/** Updates the per-light buffers used by the material. */
-		void setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight);
-	private:
-		GBufferParams mGBufferParams;
-	};
-
-	/** 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>>
-	{
-		RMAT_DEF("DeferredPointLight.bsl");
-
-	public:
-		PointLightMat();
-
-		/** Binds the material for rendering and sets up any global parameters. */
-		void bind(const SPtr<RenderTargets>& gbuffer, const SPtr<GpuParamBlockBuffer>& perCamera);
-
-		/** Updates the per-light buffers used by the material. */
-		void setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight);
-	private:
-		GBufferParams mGBufferParams;
-	};
-
-	/** Contains GPU buffers used by the renderer to manipulate lights. */
-	class GPULightData
+	/** 
+	 * Contains lights that are visible from a specific set of views, determined by scene information provided to 
+	 * setLights().
+	 */
+	class VisibleLightData
 	{
 	{
 	public:
 	public:
-		GPULightData();
+		VisibleLightData();
 
 
-		/** Updates the internal buffers with a new set of lights. */
-		void setLights(const Vector<LightData>& lightData, UINT32 numDirLights, UINT32 numRadialLights,
-					   UINT32 numSpotLights);
+		/** 
+		 * Updates the internal buffers with a new set of lights. Before calling make sure that light visibility has
+		 * been calculated and assigned to @p sceneInfo.
+		 */
+		void setLights(const SceneInfo& sceneInfo);
 
 
 		/** Returns a GPU bindable buffer containing information about every light. */
 		/** Returns a GPU bindable buffer containing information about every light. */
 		SPtr<GpuBuffer> getLightBuffer() const { return mLightBuffer; }
 		SPtr<GpuBuffer> getLightBuffer() const { return mLightBuffer; }
@@ -131,14 +91,33 @@ namespace bs { namespace ct
 		/** Returns the number of spot point lights in the lights buffer. */
 		/** Returns the number of spot point lights in the lights buffer. */
 		UINT32 getNumSpotLights() const { return mNumLights[2]; }
 		UINT32 getNumSpotLights() const { return mNumLights[2]; }
 
 
+		/** Returns the number of visible lights of the specified type. */
+		UINT32 getNumLights(LightType type) const { return mNumLights[(UINT32)type]; }
+
+		/** Returns the number of visible shadowed lights of the specified type. */
+		UINT32 getNumShadowedLights(LightType type) const { return mNumShadowedLights[(UINT32)type]; }
+
+		/** Returns the number of visible unshadowed lights of the specified type. */
+		UINT32 getNumUnshadowedLights(LightType type) const { return mNumLights[(UINT32)type] - mNumShadowedLights[(UINT32)type]; }
+
+		/** Returns a list of all visible lights of the specified type. */
+		const Vector<const RendererLight*>& getLights(LightType type) const { return mVisibleLights[(UINT32)type]; }
 	private:
 	private:
 		SPtr<GpuBuffer> mLightBuffer;
 		SPtr<GpuBuffer> mLightBuffer;
 
 
-		UINT32 mNumLights[3];
+		UINT32 mNumLights[(UINT32)LightType::Count];
+		UINT32 mNumShadowedLights[(UINT32)LightType::Count];
+
+		// These are rebuilt every call to setLights()
+		Vector<const RendererLight*> mVisibleLights[(UINT32)LightType::Count];
+
+		// Helpers to avoid memory allocations
+		Vector<LightData> mLightDataTemp;
 	};
 	};
 
 
 	BS_PARAM_BLOCK_BEGIN(TiledLightingParamDef)
 	BS_PARAM_BLOCK_BEGIN(TiledLightingParamDef)
-		BS_PARAM_BLOCK_ENTRY(Vector3I, gLightOffsets)
+		BS_PARAM_BLOCK_ENTRY(Vector4I, gLightCounts)
+		BS_PARAM_BLOCK_ENTRY(Vector2I, gLightStrides)
 		BS_PARAM_BLOCK_ENTRY(Vector2I, gFramebufferSize)
 		BS_PARAM_BLOCK_ENTRY(Vector2I, gFramebufferSize)
 	BS_PARAM_BLOCK_END
 	BS_PARAM_BLOCK_END
 
 
@@ -151,10 +130,11 @@ namespace bs { namespace ct
 		TiledDeferredLighting(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet, UINT32 sampleCount);
 		TiledDeferredLighting(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet, UINT32 sampleCount);
 
 
 		/** 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);
+		void execute(const SPtr<RenderTargets>& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera, bool noLighting,
+			bool noShadows);
 
 
 		/** Binds all the active lights. */
 		/** Binds all the active lights. */
-		void setLights(const GPULightData& lightData);
+		void setLights(const VisibleLightData& lightData);
 
 
 		static const UINT32 TILE_SIZE;
 		static const UINT32 TILE_SIZE;
 	private:
 	private:
@@ -164,7 +144,9 @@ namespace bs { namespace ct
 
 
 		GBufferParams mGBufferParams;
 		GBufferParams mGBufferParams;
 
 
-		Vector3I mLightOffsets;
+		Vector4I mUnshadowedLightCounts;
+		Vector4I mLightCounts;
+		Vector2I mLightStrides;
 		GpuParamBuffer mLightBufferParam;
 		GpuParamBuffer mLightBufferParam;
 		GpuParamLoadStoreTexture mOutputTextureParam;
 		GpuParamLoadStoreTexture mOutputTextureParam;
 		GpuParamBuffer mOutputBufferParam;
 		GpuParamBuffer mOutputBufferParam;
@@ -180,10 +162,10 @@ namespace bs { namespace ct
 
 
 		/** @copydoc TiledDeferredLighting::execute() */
 		/** @copydoc TiledDeferredLighting::execute() */
 		virtual void execute(const SPtr<RenderTargets>& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera,
 		virtual void execute(const SPtr<RenderTargets>& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera,
-			bool noLighting) = 0;
+			bool noLighting, bool noShadows) = 0;
 
 
 		/** @copydoc TiledDeferredLighting::setLights() */
 		/** @copydoc TiledDeferredLighting::setLights() */
-		virtual void setLights(const GPULightData& lightData) = 0;
+		virtual void setLights(const VisibleLightData& lightData) = 0;
 	};
 	};
 
 
 	/** Shader that performs a lighting pass over data stored in the Gbuffer. */
 	/** Shader that performs a lighting pass over data stored in the Gbuffer. */
@@ -197,10 +179,10 @@ namespace bs { namespace ct
 
 
 		/** @copydoc ITiledDeferredLightingMat::execute() */
 		/** @copydoc ITiledDeferredLightingMat::execute() */
 		void execute(const SPtr<RenderTargets>& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera,
 		void execute(const SPtr<RenderTargets>& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera,
-			bool noLighting) override;
+			bool noLighting, bool noShaodws) override;
 
 
 		/** @copydoc ITiledDeferredLightingMat::setLights() */
 		/** @copydoc ITiledDeferredLightingMat::setLights() */
-		void setLights(const GPULightData& lightData) override;
+		void setLights(const VisibleLightData& lightData) override;
 	private:
 	private:
 		TiledDeferredLighting mInternal;
 		TiledDeferredLighting mInternal;
 	};
 	};

+ 1 - 3
Source/RenderBeast/Include/BsRenderBeast.h

@@ -210,7 +210,7 @@ namespace bs
 		//// Lighting
 		//// Lighting
 		TiledDeferredLightingMaterials* mTiledDeferredLightingMats = nullptr;
 		TiledDeferredLightingMaterials* mTiledDeferredLightingMats = nullptr;
 		LightGrid* mLightGrid = nullptr;
 		LightGrid* mLightGrid = nullptr;
-		GPULightData* mGPULightData = nullptr;
+		VisibleLightData* mVisibleLightInfo = nullptr;
 
 
 		//// Image based lighting
 		//// Image based lighting
 		TiledDeferredImageBasedLightingMaterials* mTileDeferredImageBasedLightingMats = nullptr;
 		TiledDeferredImageBasedLightingMaterials* mTileDeferredImageBasedLightingMats = nullptr;
@@ -227,8 +227,6 @@ namespace bs
 		SPtr<RenderBeastOptions> mCoreOptions;
 		SPtr<RenderBeastOptions> mCoreOptions;
 
 
 		// Helpers to avoid memory allocations
 		// Helpers to avoid memory allocations
-		Vector<LightData> mLightDataTemp;
-
 		Vector<ReflProbeData> mReflProbeDataTemp;
 		Vector<ReflProbeData> mReflProbeDataTemp;
 		Vector<bool> mReflProbeVisibilityTemp;
 		Vector<bool> mReflProbeVisibilityTemp;
 
 

+ 20 - 3
Source/RenderBeast/Include/BsRenderTargets.h

@@ -22,6 +22,8 @@ namespace bs { namespace ct
 		RTT_GBuffer,
 		RTT_GBuffer,
 		/** Buffer containing intermediate lighting information used during deferred lighting pass. */
 		/** Buffer containing intermediate lighting information used during deferred lighting pass. */
 		RTT_LightAccumulation,
 		RTT_LightAccumulation,
+		/** Buffer containing temporary combined occlusion data for a specific light (from shadow maps or attenuation. */
+		RTT_LightOcclusion,
 		/** Buffer containing final scene color information. */
 		/** Buffer containing final scene color information. */
 		RTT_SceneColor
 		RTT_SceneColor
 	};
 	};
@@ -78,6 +80,15 @@ namespace bs { namespace ct
 		/**	Binds the scene color render target for rendering. */
 		/**	Binds the scene color render target for rendering. */
 		void bindSceneColor(bool readOnlyDepthStencil);
 		void bindSceneColor(bool readOnlyDepthStencil);
 
 
+		/** Binds the light accumulation render target for rendering. */
+		void bindLightAccumulation();
+
+		/** 
+		 * Binds the light occlusion render target for rendering. Light occlusion texture and GBuffer must be allocated,
+		 * and depth must have been previously rendered to the depth buffer. Target is cleared before the method returns.
+		 */
+		void bindLightOcclusion();
+
 		/** 
 		/** 
 		 * Returns the texture for storing the final scene color. If using MSAA see getSceneColorBuffer() instead. Only 
 		 * Returns the texture for storing the final scene color. If using MSAA see getSceneColorBuffer() instead. Only 
 		 * available after bindSceneColor() has been called from this frame.
 		 * available after bindSceneColor() has been called from this frame.
@@ -93,10 +104,13 @@ namespace bs { namespace ct
 		/** Returns the texture for storing of the intermediate lighting information. */
 		/** Returns the texture for storing of the intermediate lighting information. */
 		SPtr<Texture> getLightAccumulation() const;
 		SPtr<Texture> getLightAccumulation() const;
 
 
+		/** Returns the texture for storing shadow/attenuation data for single light, from viewers perspective. */
+		SPtr<Texture> getLightOcclusion() const;
+
 		/**
 		/**
-		* Flattened, buffer version of the texture returned by getLightAccumulation(). Required when MSAA is used, since
-		* random writes to multisampled textures aren't supported on all render backends.
-		*/
+		 * Flattened, buffer version of the texture returned by getLightAccumulation(). Required when MSAA is used, since
+		 * random writes to multisampled textures aren't supported on all render backends.
+		 */
 		SPtr<GpuBuffer> getLightAccumulationBuffer() const;
 		SPtr<GpuBuffer> getLightAccumulationBuffer() const;
 
 
 		/** 
 		/** 
@@ -141,6 +155,7 @@ namespace bs { namespace ct
 		SPtr<PooledRenderTexture> mDepthTex;
 		SPtr<PooledRenderTexture> mDepthTex;
 
 
 		SPtr<PooledRenderTexture> mLightAccumulationTex;
 		SPtr<PooledRenderTexture> mLightAccumulationTex;
+		SPtr<PooledRenderTexture> mLightOcclusionTex;
 		SPtr<PooledStorageBuffer> mFlattenedLightAccumulationBuffer;
 		SPtr<PooledStorageBuffer> mFlattenedLightAccumulationBuffer;
 
 
 		SPtr<PooledRenderTexture> mSceneColorTex;
 		SPtr<PooledRenderTexture> mSceneColorTex;
@@ -149,6 +164,8 @@ namespace bs { namespace ct
 
 
 		SPtr<RenderTexture> mGBufferRT;
 		SPtr<RenderTexture> mGBufferRT;
 		SPtr<RenderTexture> mSceneColorRT;
 		SPtr<RenderTexture> mSceneColorRT;
+		SPtr<RenderTexture> mLightAccumulationRT;
+		SPtr<RenderTexture> mLightOcclusionRT;
 
 
 		PixelFormat mSceneColorFormat;
 		PixelFormat mSceneColorFormat;
 		PixelFormat mAlbedoFormat;
 		PixelFormat mAlbedoFormat;

+ 25 - 1
Source/RenderBeast/Include/BsRendererView.h

@@ -9,9 +9,12 @@
 #include "BsRendererObject.h"
 #include "BsRendererObject.h"
 #include "BsBounds.h"
 #include "BsBounds.h"
 #include "BsConvexVolume.h"
 #include "BsConvexVolume.h"
+#include "BsLight.h"
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
+	class RendererLight;
+
 	/** @addtogroup RenderBeast
 	/** @addtogroup RenderBeast
 	 *  @{
 	 *  @{
 	 */
 	 */
@@ -76,6 +79,7 @@ namespace bs { namespace ct
 		bool isOverlay : 1;
 		bool isOverlay : 1;
 		bool isHDR : 1;
 		bool isHDR : 1;
 		bool noLighting : 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;
@@ -137,6 +141,8 @@ namespace bs { namespace ct
 	struct VisibilityInfo
 	struct VisibilityInfo
 	{
 	{
 		Vector<bool> renderables;
 		Vector<bool> renderables;
+		Vector<bool> radialLights;
+		Vector<bool> spotLights;
 	};
 	};
 
 
 	/** Information used for culling an object against a view. */
 	/** Information used for culling an object against a view. */
@@ -226,6 +232,24 @@ namespace bs { namespace ct
 		void determineVisible(const Vector<RendererObject*>& renderables, const Vector<CullInfo>& cullInfos,
 		void determineVisible(const Vector<RendererObject*>& renderables, const Vector<CullInfo>& cullInfos,
 			Vector<bool>* visibility = nullptr);
 			Vector<bool>* visibility = nullptr);
 
 
+		/**
+		 * Calculates the visibility masks for all the lights of the provided type.
+		 * 
+		 * @param[in]	lights				A set of lights to determine visibility for.
+		 * @param[in]	bounds				Bounding sphere for each provided light. Must be the same size as the @p lights
+		 *									array.
+		 * @param[in]	type				Type of all the lights in the @p lights array.
+		 * @param[out]	visibility			Output parameter that will have the true bit set for any visible light. If the
+		 *									bit for a light is already set to true, the method will never change it to false
+		 *									which allows the same bitfield to be provided to multiple renderer views. Must
+		 *									be the same size as the @p lights array.
+		 *									
+		 *									As a side-effect, per-view visibility data is also calculated and can be
+		 *									retrieved by calling getVisibilityMask().
+		 */
+		void determineVisible(const Vector<RendererLight>& lights, const Vector<Sphere>& bounds, LightType type, 
+			Vector<bool>* visibility = nullptr);
+
 		/**
 		/**
 		 * Culls the provided set of bounds against the current frustum and outputs a set of visibility flags determining
 		 * Culls the provided set of bounds against the current frustum and outputs a set of visibility flags determining
 		 * which entry is or isn't visible by this view. Both inputs must be arrays of the same size.
 		 * which entry is or isn't visible by this view. Both inputs must be arrays of the same size.
@@ -295,4 +319,4 @@ namespace bs { namespace ct
 	};
 	};
 
 
 	/** @} */
 	/** @} */
-}}
+}}

+ 7 - 4
Source/RenderBeast/Include/BsShadowRendering.h

@@ -141,9 +141,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 SPtr<RenderTargets>& renderTargets)
-			: light{light}, shadowMap{shadowMap}, shadowParams{shadowParams}, perCamera{perCameraParams}
-			, renderTargets{renderTargets}
+			const RenderTargets& renderTargets)
+			: light(light), shadowMap(shadowMap), shadowMapFace(shadowMapFace), shadowParams(shadowParams)
+			, perCamera(perCameraParams), renderTargets(renderTargets)
 		{ }
 		{ }
 
 
 		/** Light which is casting the shadow. */
 		/** Light which is casting the shadow. */
@@ -162,7 +162,7 @@ namespace bs { namespace ct
 		const SPtr<GpuParamBlockBuffer>& perCamera;
 		const SPtr<GpuParamBlockBuffer>& perCamera;
 
 
 		/** Contains the GBuffer textures. */
 		/** Contains the GBuffer textures. */
-		SPtr<RenderTargets> renderTargets;
+		const RenderTargets& renderTargets;
 	};
 	};
 
 
 	BS_PARAM_BLOCK_BEGIN(ShadowProjectParamsDef)
 	BS_PARAM_BLOCK_BEGIN(ShadowProjectParamsDef)
@@ -289,6 +289,9 @@ namespace bs { namespace ct
 
 
 	};
 	};
 
 
+	/** Pixel format used for rendering and storing shadow maps. */
+	const PixelFormat SHADOW_MAP_FORMAT = PF_D16;
+
 	/** Information about a shadow cast from a single light. */
 	/** Information about a shadow cast from a single light. */
 	struct ShadowInfo
 	struct ShadowInfo
 	{
 	{

+ 83 - 0
Source/RenderBeast/Include/BsStandardDeferredLighting.h

@@ -0,0 +1,83 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsRenderBeastPrerequisites.h"
+#include "BsModule.h"
+#include "BsRendererMaterial.h"
+#include "BsLightRendering.h"
+
+namespace bs { namespace ct {
+	class RendererLight;
+
+	BS_PARAM_BLOCK_BEGIN(PerLightParamDef)
+		BS_PARAM_BLOCK_ENTRY(Vector4, gLightPositionAndSrcRadius)
+		BS_PARAM_BLOCK_ENTRY(Vector4, gLightColorAndLuminance)
+		BS_PARAM_BLOCK_ENTRY(Vector4, gLightSpotAnglesAndSqrdInvAttRadius)
+		BS_PARAM_BLOCK_ENTRY(Vector4, gLightDirectionAndAttRadius)
+		BS_PARAM_BLOCK_ENTRY(Vector4, gShiftedLightPositionAndType)
+		BS_PARAM_BLOCK_ENTRY(Vector4, gLightGeometry)
+		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatConeTransform)
+	BS_PARAM_BLOCK_END
+
+	extern PerLightParamDef gPerLightParamDef;
+
+	/** Shader that renders directional light sources during deferred rendering light pass. */
+	template<bool MSAA>
+	class DirectionalLightMat : public RendererMaterial<DirectionalLightMat<MSAA>>
+	{
+		RMAT_DEF("DeferredDirectionalLight.bsl");
+
+	public:
+		DirectionalLightMat();
+
+		/** Binds the material for rendering and sets up any global parameters. */
+		void bind(const RenderTargets& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera);
+
+		/** Updates the per-light buffers used by the material. */
+		void setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight);
+	private:
+		GBufferParams mGBufferParams;
+		GpuParamTexture mLightOcclusionTexParam;
+	};
+
+	/** 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>>
+	{
+		RMAT_DEF("DeferredPointLight.bsl");
+
+	public:
+		PointLightMat();
+
+		/** Binds the material for rendering and sets up any global parameters. */
+		void bind(const RenderTargets& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera);
+
+		/** Updates the per-light buffers used by the material. */
+		void setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight);
+	private:
+		GBufferParams mGBufferParams;
+		GpuParamTexture mLightOcclusionTexParam;
+	};
+
+	/** Provides functionality for standard (non-tiled) deferred rendering. */
+	class StandardDeferred : public Module<StandardDeferred>
+	{
+	public:
+		StandardDeferred();
+
+		/** Calculates lighting for the specified light, using the standard deferred renderer. */
+		void renderLight(LightType type, const RendererLight& light, const RendererView& view, 
+			const RenderTargets& renderTargets);
+
+	private:
+		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;
+	};
+}}

+ 2 - 12
Source/RenderBeast/Source/BsImageBasedLighting.cpp

@@ -132,16 +132,11 @@ namespace bs { namespace ct
 		params->getTextureParam(GPT_COMPUTE_PROGRAM, "gGBufferCTex", mGBufferC);
 		params->getTextureParam(GPT_COMPUTE_PROGRAM, "gGBufferCTex", mGBufferC);
 		params->getTextureParam(GPT_COMPUTE_PROGRAM, "gDepthBufferTex", mGBufferDepth);
 		params->getTextureParam(GPT_COMPUTE_PROGRAM, "gDepthBufferTex", mGBufferDepth);
 
 
+		params->getTextureParam(GPT_COMPUTE_PROGRAM, "gInColor", mInColorTextureParam);
 		if (mSampleCount > 1)
 		if (mSampleCount > 1)
-		{
-			params->getBufferParam(GPT_COMPUTE_PROGRAM, "gInColor", mInColorBufferParam);
 			params->getBufferParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputBufferParam);
 			params->getBufferParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputBufferParam);
-		}
 		else
 		else
-		{
-			params->getTextureParam(GPT_COMPUTE_PROGRAM, "gInColor", mInColorTextureParam);
 			params->getLoadStoreTextureParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputTextureParam);
 			params->getLoadStoreTextureParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputTextureParam);
-		}
 
 
 		mParamBuffer = gTiledImageBasedLightingParamDef.createBuffer();
 		mParamBuffer = gTiledImageBasedLightingParamDef.createBuffer();
 		mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
 		mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
@@ -182,16 +177,11 @@ namespace bs { namespace ct
 
 
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
 
 
+		mInColorTextureParam.set(renderTargets->getLightAccumulation());
 		if (mSampleCount > 1)
 		if (mSampleCount > 1)
-		{
-			mInColorBufferParam.set(renderTargets->getLightAccumulationBuffer());
 			mOutputBufferParam.set(renderTargets->getSceneColorBuffer());
 			mOutputBufferParam.set(renderTargets->getSceneColorBuffer());
-		}
 		else
 		else
-		{
-			mInColorTextureParam.set(renderTargets->getLightAccumulation());
 			mOutputTextureParam.set(renderTargets->getSceneColor());
 			mOutputTextureParam.set(renderTargets->getSceneColor());
-		}
 
 
 		UINT32 width = renderTargets->getWidth();
 		UINT32 width = renderTargets->getWidth();
 		UINT32 height = renderTargets->getHeight();
 		UINT32 height = renderTargets->getHeight();

+ 19 - 9
Source/RenderBeast/Source/BsLightGrid.cpp

@@ -242,7 +242,7 @@ namespace bs { namespace ct
 		mGridParamBuffer = gLightGridParamDefDef.createBuffer();
 		mGridParamBuffer = gLightGridParamDefDef.createBuffer();
 	}
 	}
 
 
-	void LightGrid::updateGrid(const RendererView& view, const GPULightData& lightData, const GPUReflProbeData& probeData,
+	void LightGrid::updateGrid(const RendererView& view, const VisibleLightData& lightData, const GPUReflProbeData& probeData,
 		bool noLighting)
 		bool noLighting)
 	{
 	{
 		UINT32 width = view.getRenderTargets()->getWidth();
 		UINT32 width = view.getRenderTargets()->getWidth();
@@ -253,23 +253,33 @@ namespace bs { namespace ct
 		gridSize[1] = (height + CELL_XY_SIZE - 1) / CELL_XY_SIZE;
 		gridSize[1] = (height + CELL_XY_SIZE - 1) / CELL_XY_SIZE;
 		gridSize[2] = NUM_Z_SUBDIVIDES;
 		gridSize[2] = NUM_Z_SUBDIVIDES;
 
 
-		Vector3I lightOffsets;
+		Vector4I lightCount;
+		Vector2I lightStrides;
 		if (!noLighting)
 		if (!noLighting)
 		{
 		{
-			lightOffsets[0] = lightData.getNumDirLights();
-			lightOffsets[1] = lightOffsets[0] + lightData.getNumRadialLights();
-			lightOffsets[2] = lightOffsets[1] + lightData.getNumSpotLights();
+			lightCount[0] = lightData.getNumLights(LightType::Directional);
+			lightCount[1] = lightData.getNumLights(LightType::Radial);
+			lightCount[2] = lightData.getNumLights(LightType::Spot);
+			lightCount[3] = lightCount[0] + lightCount[1] + lightCount[2];
+
+			lightStrides[0] = lightCount[0];
+			lightStrides[1] = lightStrides[0] + lightCount[1];
 		}
 		}
 		else
 		else
 		{
 		{
-			lightOffsets[0] = 0;
-			lightOffsets[1] = 1;
-			lightOffsets[2] = 2;
+			lightCount[0] = 0;
+			lightCount[1] = 0;
+			lightCount[2] = 0;
+			lightCount[3] = 0;
+
+			lightStrides[0] = 0;
+			lightStrides[1] = 0;
 		}
 		}
 
 
 		UINT32 numCells = gridSize[0] * gridSize[1] * gridSize[2];
 		UINT32 numCells = gridSize[0] * gridSize[1] * gridSize[2];
 
 
-		gLightGridParamDefDef.gLightOffsets.set(mGridParamBuffer, lightOffsets);
+		gLightGridParamDefDef.gLightCounts.set(mGridParamBuffer, lightCount);
+		gLightGridParamDefDef.gLightStrides.set(mGridParamBuffer, lightStrides);
 		gLightGridParamDefDef.gNumReflProbes.set(mGridParamBuffer, probeData.getNumProbes());
 		gLightGridParamDefDef.gNumReflProbes.set(mGridParamBuffer, probeData.getNumProbes());
 		gLightGridParamDefDef.gNumCells.set(mGridParamBuffer, numCells);
 		gLightGridParamDefDef.gNumCells.set(mGridParamBuffer, numCells);
 		gLightGridParamDefDef.gGridSize.set(mGridParamBuffer, gridSize);
 		gLightGridParamDefDef.gGridSize.set(mGridParamBuffer, gridSize);

+ 111 - 111
Source/RenderBeast/Source/BsLightRendering.cpp

@@ -10,13 +10,13 @@
 #include "BsGpuBuffer.h"
 #include "BsGpuBuffer.h"
 #include "BsLight.h"
 #include "BsLight.h"
 #include "BsRendererUtility.h"
 #include "BsRendererUtility.h"
+#include "BsStandardDeferredLighting.h"
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
 	static const UINT32 BUFFER_INCREMENT = 16 * sizeof(LightData);
 	static const UINT32 BUFFER_INCREMENT = 16 * sizeof(LightData);
 
 
 	TiledLightingParamDef gTiledLightingParamDef;
 	TiledLightingParamDef gTiledLightingParamDef;
-	PerLightParamDef gPerLightParamDef;
 
 
 	RendererLight::RendererLight(Light* light)
 	RendererLight::RendererLight(Light* light)
 		:internal(light)
 		:internal(light)
@@ -97,110 +97,88 @@ namespace bs { namespace ct
 		mGBufferDepth = material->getParamTexture("gDepthBufferTex");
 		mGBufferDepth = material->getParamTexture("gDepthBufferTex");
 	}
 	}
 
 
-	void GBufferParams::bind(const SPtr<RenderTargets>& renderTargets)
+	void GBufferParams::bind(const RenderTargets& renderTargets)
 	{
 	{
-		mGBufferA.set(renderTargets->getGBufferA());
-		mGBufferB.set(renderTargets->getGBufferB());
-		mGBufferC.set(renderTargets->getGBufferC());
-		mGBufferDepth.set(renderTargets->getSceneDepth());
+		mGBufferA.set(renderTargets.getGBufferA());
+		mGBufferB.set(renderTargets.getGBufferB());
+		mGBufferC.set(renderTargets.getGBufferC());
+		mGBufferDepth.set(renderTargets.getSceneDepth());
 	}
 	}
 
 
-	template<bool MSAA>
-	DirectionalLightMat<MSAA>::DirectionalLightMat()
-		:mGBufferParams(mMaterial, mParamsSet)
-	{
-
-	}
-
-	template<bool MSAA>
-	void DirectionalLightMat<MSAA>::_initDefines(ShaderDefines& defines)
-	{
-		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);
-	}
-
-	template<bool MSAA>
-	void DirectionalLightMat<MSAA>::bind(const SPtr<RenderTargets>& gbuffer, const SPtr<GpuParamBlockBuffer>& perCamera)
-	{
-		RendererUtility::instance().setPass(mMaterial, 0);
-
-		mGBufferParams.bind(gbuffer);
-		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
-	}
-
-	template<bool MSAA>
-	void DirectionalLightMat<MSAA>::setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight)
-	{
-		mParamsSet->setParamBlockBuffer("PerLight", perLight, true);
-		
-		gRendererUtility().setPassParams(mParamsSet);
-	}
-
-	template class DirectionalLightMat<true>;
-	template class DirectionalLightMat<false>;
-
-	template<bool MSAA, bool InsideGeometry>
-	PointLightMat<MSAA, InsideGeometry>::PointLightMat()
-		:mGBufferParams(mMaterial, mParamsSet)
-	{
-	}
-
-	template<bool MSAA, bool InsideGeometry>
-	void PointLightMat<MSAA, InsideGeometry>::_initDefines(ShaderDefines& defines)
-	{
-		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);
-	}
+	VisibleLightData::VisibleLightData()
+		:mNumLights{}, mNumShadowedLights{}
+	{ }
 
 
-	template<bool MSAA, bool InsideGeometry>
-	void PointLightMat<MSAA, InsideGeometry>::bind(const SPtr<RenderTargets>& gbuffer, 
-		const SPtr<GpuParamBlockBuffer>& perCamera)
+	void VisibleLightData::setLights(const SceneInfo& sceneInfo)
 	{
 	{
-		RendererUtility::instance().setPass(mMaterial, 0);
+		for (UINT32 i = 0; i < (UINT32)LightType::Count; i++)
+			mVisibleLights[i].clear();
 
 
-		mGBufferParams.bind(gbuffer);
-		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
-	}
+		// Generate a list of lights and their GPU buffers
+		UINT32 numDirLights = (UINT32)sceneInfo.directionalLights.size();
+		for (UINT32 i = 0; i < numDirLights; i++)
+			mVisibleLights[(UINT32)LightType::Directional].push_back(&sceneInfo.directionalLights[i]);
 
 
-	template<bool MSAA, bool InsideGeometry>
-	void PointLightMat<MSAA, InsideGeometry>::setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight)
-	{
-		mParamsSet->setParamBlockBuffer("PerLight", perLight, true);
-		
-		gRendererUtility().setPassParams(mParamsSet);
-	}
+		UINT32 numRadialLights = (UINT32)sceneInfo.radialLights.size();
+		for(UINT32 i = 0; i < numRadialLights; i++)
+		{
+			if (!sceneInfo.radialLightVisibility[i])
+				continue;
 
 
-	template class PointLightMat<false, false>;
-	template class PointLightMat<false, true>;
-	template class PointLightMat<true, false>;
-	template class PointLightMat<true, true>;
+			mVisibleLights[(UINT32)LightType::Radial].push_back(&sceneInfo.radialLights[i]);
+		}
 
 
-	GPULightData::GPULightData()
-		:mNumLights{}
-	{ }
+		UINT32 numSpotLights = (UINT32)sceneInfo.spotLights.size();
+		for (UINT32 i = 0; i < numSpotLights; i++)
+		{
+			if (!sceneInfo.spotLightVisibility[i])
+				continue;
 
 
-	void GPULightData::setLights(const Vector<LightData>& lightData, UINT32 numDirLights, UINT32 numRadialLights,
-									UINT32 numSpotLights)
-	{
-		mNumLights[0] = numDirLights;
-		mNumLights[1] = numRadialLights;
-		mNumLights[2] = numSpotLights;
+			mVisibleLights[(UINT32)LightType::Spot].push_back(&sceneInfo.spotLights[i]);
+		}
 
 
-		Vector3I lightOffsets;
-		lightOffsets[0] = numDirLights;
-		lightOffsets[1] = lightOffsets[0] + numRadialLights;
-		lightOffsets[2] = lightOffsets[1] + numSpotLights;
+		for (UINT32 i = 0; i < (UINT32)LightType::Count; i++)
+			mNumLights[i] = (UINT32)mVisibleLights[i].size();
 
 
-		UINT32 totalNumLights = (UINT32)lightOffsets[2];
+		// Partition all visible lights so that unshadowed ones come first
+		auto partition = [](Vector<const RendererLight*>& entries)
+		{
+			int first = 0;
+			for (int i = 0; i < entries.size(); ++i)
+			{
+				if(entries[i]->internal->getCastsShadow())
+				{
+					first = i;
+					break;
+				}
+			}
+
+			for(int i = first + 1; i < entries.size(); ++i)
+			{
+				if(!entries[i]->internal->getCastsShadow())
+				{
+					std::swap(entries[i], entries[first]);
+					++first;
+				}
+			}
+
+			return first;
+		};
+
+		for (UINT32 i = 0; i < (UINT32)LightType::Count; i++)
+			mNumShadowedLights[i] = mNumLights[i] - partition(mVisibleLights[i]);
+
+		// Generate light data to initialize the GPU buffer with
+		for(auto& lightsPerType : mVisibleLights)
+		{
+			for(auto& entry : lightsPerType)
+			{
+				mLightDataTemp.push_back(LightData());
+				entry->getParameters(mLightDataTemp.back());
+			}
+		}
 
 
-		UINT32 size = totalNumLights * sizeof(LightData);
+		UINT32 size = (UINT32)mLightDataTemp.size() * sizeof(LightData);
 		UINT32 curBufferSize;
 		UINT32 curBufferSize;
 
 
 		if (mLightBuffer != nullptr)
 		if (mLightBuffer != nullptr)
@@ -223,7 +201,9 @@ namespace bs { namespace ct
 		}
 		}
 
 
 		if (size > 0)
 		if (size > 0)
-			mLightBuffer->writeData(0, size, lightData.data(), BWT_DISCARD);
+			mLightBuffer->writeData(0, size, mLightDataTemp.data(), BWT_DISCARD);
+
+		mLightDataTemp.clear();
 	}
 	}
 
 
 	const UINT32 TiledDeferredLighting::TILE_SIZE = 16;
 	const UINT32 TiledDeferredLighting::TILE_SIZE = 16;
@@ -231,7 +211,6 @@ namespace bs { namespace ct
 	TiledDeferredLighting::TiledDeferredLighting(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet,
 	TiledDeferredLighting::TiledDeferredLighting(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet,
 													UINT32 sampleCount)
 													UINT32 sampleCount)
 		: mSampleCount(sampleCount), mMaterial(material), mParamsSet(paramsSet), mGBufferParams(material, paramsSet)
 		: mSampleCount(sampleCount), mMaterial(material), mParamsSet(paramsSet), mGBufferParams(material, paramsSet)
-		, mLightOffsets()
 	{
 	{
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 
 
@@ -247,8 +226,8 @@ 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)
+	void TiledDeferredLighting::execute(const SPtr<RenderTargets>& renderTargets, 
+		const SPtr<GpuParamBlockBuffer>& perCamera, bool noLighting, bool noShadows)
 	{
 	{
 		Vector2I framebufferSize;
 		Vector2I framebufferSize;
 		framebufferSize[0] = renderTargets->getWidth();
 		framebufferSize[0] = renderTargets->getWidth();
@@ -257,20 +236,32 @@ namespace bs { namespace ct
 
 
 		if (noLighting)
 		if (noLighting)
 		{
 		{
-			Vector3I lightOffsets;
-			lightOffsets[0] = 0;
-			lightOffsets[1] = 0;
-			lightOffsets[2] = 0;
-
-			gTiledLightingParamDef.gLightOffsets.set(mParamBuffer, lightOffsets);
+			Vector4I lightCounts;
+			lightCounts[0] = 0;
+			lightCounts[1] = 0;
+			lightCounts[2] = 0;
+			lightCounts[3] = 0;
+
+			Vector2I lightStrides;
+			lightStrides[0] = 0;
+			lightStrides[1] = 0;
+
+			gTiledLightingParamDef.gLightCounts.set(mParamBuffer, lightCounts);
+			gTiledLightingParamDef.gLightStrides.set(mParamBuffer, lightStrides);
 		}
 		}
 		else
 		else
 		{
 		{
-			gTiledLightingParamDef.gLightOffsets.set(mParamBuffer, mLightOffsets);
+			if(noShadows)
+				gTiledLightingParamDef.gLightCounts.set(mParamBuffer, mLightCounts);
+			else
+				gTiledLightingParamDef.gLightCounts.set(mParamBuffer, mUnshadowedLightCounts);
+
+			gTiledLightingParamDef.gLightStrides.set(mParamBuffer, mLightStrides);
 		}
 		}
+
 		mParamBuffer->flushToGPU();
 		mParamBuffer->flushToGPU();
 
 
-		mGBufferParams.bind(renderTargets);
+		mGBufferParams.bind(*renderTargets);
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
 
 
 		if (mSampleCount > 1)
 		if (mSampleCount > 1)
@@ -296,13 +287,22 @@ namespace bs { namespace ct
 		RenderAPI::instance().dispatchCompute(numTilesX, numTilesY);
 		RenderAPI::instance().dispatchCompute(numTilesX, numTilesY);
 	}
 	}
 
 
-	void TiledDeferredLighting::setLights(const GPULightData& lightData)
+	void TiledDeferredLighting::setLights(const VisibleLightData& lightData)
 	{
 	{
 		mLightBufferParam.set(lightData.getLightBuffer());
 		mLightBufferParam.set(lightData.getLightBuffer());
 
 
-		mLightOffsets[0] = lightData.getNumDirLights();
-		mLightOffsets[1] = mLightOffsets[0] + lightData.getNumRadialLights();
-		mLightOffsets[2] = mLightOffsets[1] + lightData.getNumSpotLights();
+		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>
 	template<int MSAA_COUNT>
@@ -321,13 +321,13 @@ namespace bs { namespace ct
 
 
 	template<int MSAA_COUNT>
 	template<int MSAA_COUNT>
 	void TTiledDeferredLightingMat<MSAA_COUNT>::execute(const SPtr<RenderTargets>& gbuffer,
 	void TTiledDeferredLightingMat<MSAA_COUNT>::execute(const SPtr<RenderTargets>& gbuffer,
-		const SPtr<GpuParamBlockBuffer>& perCamera, bool noLighting)
+		const SPtr<GpuParamBlockBuffer>& perCamera, bool noLighting, bool noShadows)
 	{
 	{
-		mInternal.execute(gbuffer, perCamera, noLighting);
+		mInternal.execute(gbuffer, perCamera, noLighting, noShadows);
 	}
 	}
 
 
 	template<int MSAA_COUNT>
 	template<int MSAA_COUNT>
-	void TTiledDeferredLightingMat<MSAA_COUNT>::setLights(const GPULightData& lightData)
+	void TTiledDeferredLightingMat<MSAA_COUNT>::setLights(const VisibleLightData& lightData)
 	{
 	{
 		mInternal.setLights(lightData);
 		mInternal.setLights(lightData);
 	}
 	}

+ 79 - 48
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -35,6 +35,7 @@
 #include "BsLightGrid.h"
 #include "BsLightGrid.h"
 #include "BsSkybox.h"
 #include "BsSkybox.h"
 #include "BsShadowRendering.h"
 #include "BsShadowRendering.h"
+#include "BsStandardDeferredLighting.h"
 
 
 using namespace std::placeholders;
 using namespace std::placeholders;
 
 
@@ -85,13 +86,14 @@ namespace bs { namespace ct
 		mTileDeferredImageBasedLightingMats = bs_new<TiledDeferredImageBasedLightingMaterials>();
 		mTileDeferredImageBasedLightingMats = bs_new<TiledDeferredImageBasedLightingMaterials>();
 
 
 		mPreintegratedEnvBRDF = TiledDeferredImageBasedLighting::generatePreintegratedEnvBRDF();
 		mPreintegratedEnvBRDF = TiledDeferredImageBasedLighting::generatePreintegratedEnvBRDF();
-		mGPULightData = bs_new<GPULightData>();
+		mVisibleLightInfo = bs_new<VisibleLightData>();
 		mGPUReflProbeData = bs_new<GPUReflProbeData>();
 		mGPUReflProbeData = bs_new<GPUReflProbeData>();
 		mLightGrid = bs_new<LightGrid>();
 		mLightGrid = bs_new<LightGrid>();
 
 
 		GpuResourcePool::startUp();
 		GpuResourcePool::startUp();
 		PostProcessing::startUp();
 		PostProcessing::startUp();
 		ShadowRendering::startUp(mCoreOptions->shadowMapSize);
 		ShadowRendering::startUp(mCoreOptions->shadowMapSize);
+		StandardDeferred::startUp();
 	}
 	}
 
 
 	void RenderBeast::destroyCore()
 	void RenderBeast::destroyCore()
@@ -106,13 +108,14 @@ namespace bs { namespace ct
 		mSkyboxFilteredReflections = nullptr;
 		mSkyboxFilteredReflections = nullptr;
 		mSkyboxIrradiance = nullptr;
 		mSkyboxIrradiance = nullptr;
 
 
+		StandardDeferred::shutDown();
 		ShadowRendering::shutDown();
 		ShadowRendering::shutDown();
 		PostProcessing::shutDown();
 		PostProcessing::shutDown();
 		GpuResourcePool::shutDown();
 		GpuResourcePool::shutDown();
 
 
 		bs_delete(mSkyboxMat);
 		bs_delete(mSkyboxMat);
 		bs_delete(mSkyboxSolidColorMat);
 		bs_delete(mSkyboxSolidColorMat);
-		bs_delete(mGPULightData);
+		bs_delete(mVisibleLightInfo);
 		bs_delete(mGPUReflProbeData);
 		bs_delete(mGPUReflProbeData);
 		bs_delete(mLightGrid);
 		bs_delete(mLightGrid);
 		bs_delete(mFlatFramebufferToTextureMat);
 		bs_delete(mFlatFramebufferToTextureMat);
@@ -379,50 +382,26 @@ namespace bs { namespace ct
 		for(UINT32 i = 0; i < numViews; i++)
 		for(UINT32 i = 0; i < numViews; i++)
 			views[i]->determineVisible(sceneInfo.renderables, sceneInfo.renderableCullInfos, &sceneInfo.renderableVisibility);
 			views[i]->determineVisible(sceneInfo.renderables, sceneInfo.renderableCullInfos, &sceneInfo.renderableVisibility);
 
 
-		// Generate a list of lights and their GPU buffers
-		UINT32 numDirLights = (UINT32)sceneInfo.directionalLights.size();
-		for (UINT32 i = 0; i < numDirLights; i++)
-		{
-			mLightDataTemp.push_back(LightData());
-			sceneInfo.directionalLights[i].getParameters(mLightDataTemp.back());
-		}
-
+		// Calculate light visibility for all views
 		UINT32 numRadialLights = (UINT32)sceneInfo.radialLights.size();
 		UINT32 numRadialLights = (UINT32)sceneInfo.radialLights.size();
-		UINT32 numVisibleRadialLights = 0;
 		sceneInfo.radialLightVisibility.resize(numRadialLights, false);
 		sceneInfo.radialLightVisibility.resize(numRadialLights, false);
 		sceneInfo.radialLightVisibility.assign(numRadialLights, false);
 		sceneInfo.radialLightVisibility.assign(numRadialLights, false);
-		for (UINT32 i = 0; i < numViews; i++)
-			views[i]->calculateVisibility(sceneInfo.radialLightWorldBounds, sceneInfo.radialLightVisibility);
-
-		for(UINT32 i = 0; i < numRadialLights; i++)
-		{
-			if (!sceneInfo.radialLightVisibility[i])
-				continue;
-
-			mLightDataTemp.push_back(LightData());
-			sceneInfo.radialLights[i].getParameters(mLightDataTemp.back());
-			numVisibleRadialLights++;
-		}
 
 
 		UINT32 numSpotLights = (UINT32)sceneInfo.spotLights.size();
 		UINT32 numSpotLights = (UINT32)sceneInfo.spotLights.size();
-		UINT32 numVisibleSpotLights = 0;
 		sceneInfo.spotLightVisibility.resize(numSpotLights, false);
 		sceneInfo.spotLightVisibility.resize(numSpotLights, false);
 		sceneInfo.spotLightVisibility.assign(numSpotLights, false);
 		sceneInfo.spotLightVisibility.assign(numSpotLights, false);
-		for (UINT32 i = 0; i < numViews; i++)
-			views[i]->calculateVisibility(sceneInfo.spotLightWorldBounds, sceneInfo.spotLightVisibility);
 
 
-		for (UINT32 i = 0; i < numSpotLights; i++)
+		for (UINT32 i = 0; i < numViews; i++)
 		{
 		{
-			if (!sceneInfo.spotLightVisibility[i])
-				continue;
+			views[i]->determineVisible(sceneInfo.radialLights, sceneInfo.radialLightWorldBounds, LightType::Radial,
+				&sceneInfo.radialLightVisibility);
 
 
-			mLightDataTemp.push_back(LightData());
-			sceneInfo.spotLights[i].getParameters(mLightDataTemp.back());
-			numVisibleSpotLights++;
+			views[i]->determineVisible(sceneInfo.spotLights, sceneInfo.spotLightWorldBounds, LightType::Spot,
+				&sceneInfo.spotLightVisibility);
 		}
 		}
 
 
-		mGPULightData->setLights(mLightDataTemp, numDirLights, numVisibleRadialLights, numVisibleSpotLights);
-		mLightDataTemp.clear();
+		// Update GPU light data
+		mVisibleLightInfo->setLights(sceneInfo);
 
 
 		// Gemerate reflection probes and their GPU buffers
 		// Gemerate reflection probes and their GPU buffers
 		UINT32 numProbes = (UINT32)sceneInfo.reflProbes.size();
 		UINT32 numProbes = (UINT32)sceneInfo.reflProbes.size();
@@ -487,10 +466,22 @@ namespace bs { namespace ct
 		Matrix4 viewProj = viewProps.viewProjTransform;
 		Matrix4 viewProj = viewProps.viewProjTransform;
 		UINT32 numSamples = viewProps.numSamples;
 		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->beginRendering(true);
 		viewInfo->beginRendering(true);
 
 
 		// Prepare light grid required for transparent object rendering
 		// Prepare light grid required for transparent object rendering
-		mLightGrid->updateGrid(*viewInfo, *mGPULightData, *mGPUReflProbeData, viewProps.noLighting);
+		mLightGrid->updateGrid(*viewInfo, *mVisibleLightInfo, *mGPUReflProbeData, viewProps.noLighting);
 
 
 		SPtr<GpuParamBlockBuffer> gridParams;
 		SPtr<GpuParamBlockBuffer> gridParams;
 		SPtr<GpuBuffer> gridLightOffsetsAndSize, gridLightIndices;
 		SPtr<GpuBuffer> gridLightOffsetsAndSize, gridLightIndices;
@@ -537,7 +528,7 @@ namespace bs { namespace ct
 
 
 				element.gridLightOffsetsAndSizeParam.set(gridLightOffsetsAndSize);
 				element.gridLightOffsetsAndSizeParam.set(gridLightOffsetsAndSize);
 				element.gridLightIndicesParam.set(gridLightIndices);
 				element.gridLightIndicesParam.set(gridLightIndices);
-				element.lightsBufferParam.set(mGPULightData->getLightBuffer());
+				element.lightsBufferParam.set(mVisibleLightInfo->getLightBuffer());
 
 
 				// Image based lighting params
 				// Image based lighting params
 				ImageBasedLightingParams& iblParams = element.imageBasedParams;
 				ImageBasedLightingParams& iblParams = element.imageBasedParams;
@@ -609,32 +600,68 @@ namespace bs { namespace ct
 		RenderAPI& rapi = RenderAPI::instance();
 		RenderAPI& rapi = RenderAPI::instance();
 		rapi.setRenderTarget(nullptr);
 		rapi.setRenderTarget(nullptr);
 
 
-		// Render light pass into light accumulation buffer
+		// 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);
 		ITiledDeferredLightingMat* lightingMat = mTiledDeferredLightingMats->get(numSamples);
+		lightingMat->setLights(*mVisibleLightInfo);
+		lightingMat->execute(renderTargets, perCameraBuffer, viewProps.noLighting, !allowShadows);
 
 
-		renderTargets->allocate(RTT_LightAccumulation);
+		// If we're using flattened accumulation buffer for MSAA we need to copy its contents to the MSAA texture before
+		// continuing
+		bool isMSAA = numSamples > 1;
+		if(isMSAA)
+		{
+			mFlatFramebufferToTextureMat->execute(renderTargets->getLightAccumulationBuffer(), 
+				renderTargets->getLightAccumulation());
+		}
+
+		// Render shadowed lights into light accumulation texture, using standard deferred
+		allowShadows = false; // DEBUG ONLY
+		if (allowShadows)
+		{
+			renderTargets->allocate(RTT_LightOcclusion);
 
 
-		lightingMat->setLights(*mGPULightData);
-		lightingMat->execute(renderTargets, perCameraBuffer, viewProps.noLighting);
+			UINT32 viewIdx = sceneCamera->getRendererId();
 
 
-		renderTargets->allocate(RTT_SceneColor);
+			for(UINT32 i = 0; i < (UINT32)LightType::Count; i++)
+			{
+				LightType lightType = (LightType)i;
 
 
-		// Render image based lighting and add it with light accumulation, output to scene color
-		// Note: Image based lighting is split from direct lighting in order to reduce load on GPU shared memory. The
-		// image based shader ends up re-doing a lot of calculations and it could be beneficial to profile and see if
-		// both methods can be squeezed into the same shader.
+				auto& lights = mVisibleLightInfo->getLights(lightType);
+				UINT32 count = mVisibleLightInfo->getNumShadowedLights(lightType);
+				UINT32 offset = mVisibleLightInfo->getNumUnshadowedLights(lightType);
+
+				for (UINT32 j = 0; j < count; j++)
+				{
+					renderTargets->bindLightOcclusion();
+
+					UINT32 lightIdx = offset + j;
+					const RendererLight& light = *lights[lightIdx];
+					ShadowRendering::instance().renderShadowOcclusion(*mScene, mCoreOptions->shadowFilteringQuality,
+						light, viewIdx);
+
+					renderTargets->bindLightAccumulation();
+					StandardDeferred::instance().renderLight(lightType, light, *viewInfo, *renderTargets);
+				}
+			}
+
+			renderTargets->release(RTT_LightOcclusion);
+		}
+
+		// Render image based lighting, add it to light accumulation and output scene color
+		renderTargets->allocate(RTT_SceneColor);
 		imageBasedLightingMat->execute(renderTargets, perCameraBuffer, mPreintegratedEnvBRDF);
 		imageBasedLightingMat->execute(renderTargets, perCameraBuffer, mPreintegratedEnvBRDF);
 
 
 		renderTargets->release(RTT_LightAccumulation);
 		renderTargets->release(RTT_LightAccumulation);
 		renderTargets->release(RTT_GBuffer);
 		renderTargets->release(RTT_GBuffer);
 
 
-		bool usingFlattenedFB = numSamples > 1;
-
 		renderTargets->bindSceneColor(true);
 		renderTargets->bindSceneColor(true);
 
 
 		// If we're using flattened framebuffer for MSAA we need to copy its contents to the MSAA scene texture before
 		// If we're using flattened framebuffer for MSAA we need to copy its contents to the MSAA scene texture before
 		// continuing
 		// continuing
-		if(usingFlattenedFB)
+		if(isMSAA)
 		{
 		{
 			mFlatFramebufferToTextureMat->execute(renderTargets->getSceneColorBuffer(), 
 			mFlatFramebufferToTextureMat->execute(renderTargets->getSceneColorBuffer(), 
 												  renderTargets->getSceneColor());
 												  renderTargets->getSceneColor());
@@ -660,6 +687,9 @@ namespace bs { namespace ct
 		renderTargets->bindSceneColor(false);
 		renderTargets->bindSceneColor(false);
 
 
 		// Render transparent objects
 		// 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();
 		const Vector<RenderQueueElement>& transparentElements = viewInfo->getTransparentQueue()->getSortedElements();
 		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
 		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
 		{
 		{
@@ -985,6 +1015,7 @@ namespace bs { namespace ct
 		viewDesc.isOverlay = false;
 		viewDesc.isOverlay = false;
 		viewDesc.isHDR = hdr;
 		viewDesc.isHDR = hdr;
 		viewDesc.noLighting = false;
 		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;

+ 74 - 2
Source/RenderBeast/Source/BsRenderTargets.cpp

@@ -152,10 +152,55 @@ namespace bs { namespace ct
 				mFlattenedLightAccumulationBuffer =
 				mFlattenedLightAccumulationBuffer =
 					texPool.get(POOLED_STORAGE_BUFFER_DESC::createStandard(BF_16X4F, bufferNumElements));
 					texPool.get(POOLED_STORAGE_BUFFER_DESC::createStandard(BF_16X4F, bufferNumElements));
 			}
 			}
+
+			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
 			else
+				rebuildRT = true;
+
+			if (rebuildRT)
 			{
 			{
-				mLightAccumulationTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, width,
-					height, TU_LOADSTORE, mViewTarget.numSamples, false));
+				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);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -188,6 +233,11 @@ namespace bs { namespace ct
 			if (mFlattenedLightAccumulationBuffer != nullptr)
 			if (mFlattenedLightAccumulationBuffer != nullptr)
 				texPool.release(mFlattenedLightAccumulationBuffer);
 				texPool.release(mFlattenedLightAccumulationBuffer);
 		}
 		}
+		else if(type == RTT_LightOcclusion)
+		{
+			if (mLightOcclusionTex != nullptr)
+				texPool.release(mLightOcclusionTex);
+		}
 	}
 	}
 
 
 	void RenderTargets::bindGBuffer()
 	void RenderTargets::bindGBuffer()
@@ -219,6 +269,23 @@ namespace bs { namespace ct
 		rapi.setViewport(area);
 		rapi.setViewport(area);
 	}
 	}
 
 
+	void RenderTargets::bindLightAccumulation()
+	{
+		RenderAPI& rapi = RenderAPI::instance();
+		rapi.setRenderTarget(mLightAccumulationRT);
+	}
+
+	void RenderTargets::bindLightOcclusion()
+	{
+		RenderAPI& rapi = RenderAPI::instance();
+		rapi.setRenderTarget(mLightOcclusionRT);
+
+		Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
+		rapi.setViewport(area);
+
+		RenderAPI::instance().clearViewport(FBT_COLOR, Color::ZERO);
+	}
+
 	SPtr<Texture> RenderTargets::getSceneColor() const
 	SPtr<Texture> RenderTargets::getSceneColor() const
 	{
 	{
 		return mSceneColorTex->texture;
 		return mSceneColorTex->texture;
@@ -270,6 +337,11 @@ namespace bs { namespace ct
 		return mLightAccumulationTex->texture;
 		return mLightAccumulationTex->texture;
 	}
 	}
 
 
+	SPtr<Texture> RenderTargets::getLightOcclusion() const
+	{
+		return mLightOcclusionTex->texture;
+	}
+
 	SPtr<GpuBuffer> RenderTargets::getLightAccumulationBuffer() const
 	SPtr<GpuBuffer> RenderTargets::getLightAccumulationBuffer() const
 	{
 	{
 		return mFlattenedLightAccumulationBuffer->buffer;
 		return mFlattenedLightAccumulationBuffer->buffer;

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

@@ -502,6 +502,7 @@ namespace bs {	namespace ct
 		viewDesc.isOverlay = camera->getFlags().isSet(CameraFlag::Overlay);
 		viewDesc.isOverlay = camera->getFlags().isSet(CameraFlag::Overlay);
 		viewDesc.isHDR = camera->getFlags().isSet(CameraFlag::HDR);
 		viewDesc.isHDR = camera->getFlags().isSet(CameraFlag::HDR);
 		viewDesc.noLighting = camera->getFlags().isSet(CameraFlag::NoLighting);
 		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;

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

@@ -7,6 +7,7 @@
 #include "BsShader.h"
 #include "BsShader.h"
 #include "BsRenderTargets.h"
 #include "BsRenderTargets.h"
 #include "BsRendererUtility.h"
 #include "BsRendererUtility.h"
+#include "BsLightRendering.h"
 #include "BsGpuParamsSet.h"
 #include "BsGpuParamsSet.h"
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
@@ -209,6 +210,50 @@ namespace bs { namespace ct
 		mTransparentQueue->sort();
 		mTransparentQueue->sort();
 	}
 	}
 
 
+	void RendererView::determineVisible(const Vector<RendererLight>& lights, const Vector<Sphere>& bounds, 
+		LightType lightType, Vector<bool>* visibility)
+	{
+		// Special case for directional lights, they're always visible
+		if(lightType == LightType::Directional)
+		{
+			if (visibility)
+				visibility->assign(lights.size(), true);
+
+			return;
+		}
+
+		Vector<bool>* perViewVisibility;
+		if(lightType == LightType::Radial)
+		{
+			mVisibility.radialLights.clear();
+			mVisibility.radialLights.resize(lights.size(), false);
+
+			perViewVisibility = &mVisibility.radialLights;
+		}
+		else // Spot
+		{
+			mVisibility.spotLights.clear();
+			mVisibility.spotLights.resize(lights.size(), false);
+
+			perViewVisibility = &mVisibility.spotLights;
+		}
+
+		if (mProperties.isOverlay)
+			return;
+
+		calculateVisibility(bounds, *perViewVisibility);
+
+		if(visibility != nullptr)
+		{
+			for (UINT32 i = 0; i < (UINT32)lights.size(); i++)
+			{
+				bool visible = (*visibility)[i];
+
+				(*visibility)[i] = visible || (*perViewVisibility)[i];
+			}
+		}
+	}
+
 	void RendererView::calculateVisibility(const Vector<CullInfo>& cullInfos, Vector<bool>& visibility) const
 	void RendererView::calculateVisibility(const Vector<CullInfo>& cullInfos, Vector<bool>& visibility) const
 	{
 	{
 		UINT64 cameraLayers = mProperties.visibleLayers;
 		UINT64 cameraLayers = mProperties.visibleLayers;

+ 6 - 6
Source/RenderBeast/Source/BsShadowRendering.cpp

@@ -390,7 +390,7 @@ namespace bs { namespace ct
 		:mLastUsedCounter(0)
 		:mLastUsedCounter(0)
 	{
 	{
 		mAtlas = GpuResourcePool::instance().get(
 		mAtlas = GpuResourcePool::instance().get(
-			POOLED_RENDER_TEXTURE_DESC::create2D(PF_D24S8, size, size, TU_DEPTHSTENCIL));
+			POOLED_RENDER_TEXTURE_DESC::create2D(SHADOW_MAP_FORMAT, size, size, TU_DEPTHSTENCIL));
 	}
 	}
 
 
 	ShadowMapAtlas::~ShadowMapAtlas()
 	ShadowMapAtlas::~ShadowMapAtlas()
@@ -448,7 +448,7 @@ namespace bs { namespace ct
 		:ShadowMapBase(size)
 		:ShadowMapBase(size)
 	{
 	{
 		mShadowMap = GpuResourcePool::instance().get(
 		mShadowMap = GpuResourcePool::instance().get(
-			POOLED_RENDER_TEXTURE_DESC::createCube(PF_D24S8, size, size, TU_DEPTHSTENCIL));
+			POOLED_RENDER_TEXTURE_DESC::createCube(SHADOW_MAP_FORMAT, size, size, TU_DEPTHSTENCIL));
 
 
 		RENDER_TEXTURE_DESC rtDesc;
 		RENDER_TEXTURE_DESC rtDesc;
 		rtDesc.depthStencilSurface.texture = mShadowMap->texture;
 		rtDesc.depthStencilSurface.texture = mShadowMap->texture;
@@ -468,8 +468,8 @@ namespace bs { namespace ct
 	ShadowCascadedMap::ShadowCascadedMap(UINT32 size)
 	ShadowCascadedMap::ShadowCascadedMap(UINT32 size)
 		:ShadowMapBase(size)
 		:ShadowMapBase(size)
 	{
 	{
-		mShadowMap = GpuResourcePool::instance().get(
-			POOLED_RENDER_TEXTURE_DESC::create2D(PF_D24S8, size, size, TU_DEPTHSTENCIL, 0, false, NUM_CASCADE_SPLITS));
+		mShadowMap = GpuResourcePool::instance().get(POOLED_RENDER_TEXTURE_DESC::create2D(SHADOW_MAP_FORMAT, size, size, 
+			TU_DEPTHSTENCIL, 0, false, NUM_CASCADE_SPLITS));
 
 
 		RENDER_TEXTURE_DESC rtDesc;
 		RENDER_TEXTURE_DESC rtDesc;
 		rtDesc.depthStencilSurface.texture = mShadowMap->texture;
 		rtDesc.depthStencilSurface.texture = mShadowMap->texture;
@@ -802,7 +802,7 @@ namespace bs { namespace ct
 				SPtr<Texture> shadowMap = mShadowCubemaps[shadowInfo.textureIdx].getTexture();
 				SPtr<Texture> shadowMap = mShadowCubemaps[shadowInfo.textureIdx].getTexture();
 				SPtr<RenderTargets> renderTargets = view->getRenderTargets();
 				SPtr<RenderTargets> renderTargets = view->getRenderTargets();
 
 
-				ShadowProjectParams shadowParams(*light, shadowMap, 0, shadowParamBuffer, perViewBuffer, renderTargets);
+				ShadowProjectParams shadowParams(*light, shadowMap, 0, shadowParamBuffer, perViewBuffer, *renderTargets);
 				mProjectOmniMaterials.bind(effectiveShadowQuality, viewerInsideVolume, viewProps.numSamples > 1, shadowParams);
 				mProjectOmniMaterials.bind(effectiveShadowQuality, viewerInsideVolume, viewProps.numSamples > 1, shadowParams);
 
 
 				gRendererUtility().draw(gRendererUtility().getRadialLightStencil());
 				gRendererUtility().draw(gRendererUtility().getRadialLightStencil());
@@ -897,7 +897,7 @@ namespace bs { namespace ct
 
 
 				SPtr<RenderTargets> renderTargets = view->getRenderTargets();
 				SPtr<RenderTargets> renderTargets = view->getRenderTargets();
 				ShadowProjectParams shadowParams(*light, shadowMap, shadowMapFace, shadowParamBuffer, perViewBuffer, 
 				ShadowProjectParams shadowParams(*light, shadowMap, shadowMapFace, shadowParamBuffer, perViewBuffer, 
-					renderTargets);
+					*renderTargets);
 				mProjectMaterials.bind(effectiveShadowQuality, isCSM, viewProps.numSamples > 1, shadowParams);
 				mProjectMaterials.bind(effectiveShadowQuality, isCSM, viewProps.numSamples > 1, shadowParams);
 
 
 				if(!isCSM)
 				if(!isCSM)

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

@@ -0,0 +1,172 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsStandardDeferredLighting.h"
+#include "BsRendererUtility.h"
+#include "BsRendererView.h"
+#include "BsGpuParamsSet.h"
+#include "BsRenderTargets.h"
+#include "BsMesh.h"
+
+namespace bs { namespace ct {
+	PerLightParamDef gPerLightParamDef;
+
+	template<bool MSAA>
+	DirectionalLightMat<MSAA>::DirectionalLightMat()
+		:mGBufferParams(mMaterial, mParamsSet)
+	{
+		const GpuParams& gpuParams = *mParamsSet->getGpuParams();
+		gpuParams.getTextureParam(GPT_FRAGMENT_PROGRAM, "gLightOcclusionTex", mLightOcclusionTexParam);
+	}
+
+	template<bool MSAA>
+	void DirectionalLightMat<MSAA>::_initDefines(ShaderDefines& defines)
+	{
+		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);
+	}
+
+	template<bool MSAA>
+	void DirectionalLightMat<MSAA>::bind(const RenderTargets& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera)
+	{
+		RendererUtility::instance().setPass(mMaterial, 0);
+
+		mGBufferParams.bind(renderTargets);
+		mLightOcclusionTexParam.set(renderTargets.getLightOcclusion());
+		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
+	}
+
+	template<bool MSAA>
+	void DirectionalLightMat<MSAA>::setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight)
+	{
+		mParamsSet->setParamBlockBuffer("PerLight", perLight, true);
+		
+		gRendererUtility().setPassParams(mParamsSet);
+	}
+
+	template class DirectionalLightMat<true>;
+	template class DirectionalLightMat<false>;
+
+	template<bool MSAA, bool InsideGeometry>
+	PointLightMat<MSAA, InsideGeometry>::PointLightMat()
+		:mGBufferParams(mMaterial, mParamsSet)
+	{
+		const GpuParams& gpuParams = *mParamsSet->getGpuParams();
+		gpuParams.getTextureParam(GPT_FRAGMENT_PROGRAM, "gLightOcclusionTex", mLightOcclusionTexParam);
+	}
+
+	template<bool MSAA, bool InsideGeometry>
+	void PointLightMat<MSAA, InsideGeometry>::_initDefines(ShaderDefines& defines)
+	{
+		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);
+	}
+
+	template<bool MSAA, bool InsideGeometry>
+	void PointLightMat<MSAA, InsideGeometry>::bind(const RenderTargets& renderTargets, 
+		const SPtr<GpuParamBlockBuffer>& perCamera)
+	{
+		RendererUtility::instance().setPass(mMaterial, 0);
+
+		mGBufferParams.bind(renderTargets);
+		mLightOcclusionTexParam.set(renderTargets.getLightOcclusion());
+		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
+	}
+
+	template<bool MSAA, bool InsideGeometry>
+	void PointLightMat<MSAA, InsideGeometry>::setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight)
+	{
+		mParamsSet->setParamBlockBuffer("PerLight", perLight, true);
+		
+		gRendererUtility().setPassParams(mParamsSet);
+	}
+
+	template class PointLightMat<false, false>;
+	template class PointLightMat<false, true>;
+	template class PointLightMat<true, false>;
+	template class PointLightMat<true, true>;
+
+	StandardDeferred::StandardDeferred()
+	{
+		mPerLightBuffer = gPerLightParamDef.createBuffer();
+	}
+
+	void StandardDeferred::renderLight(LightType lightType, const RendererLight& light, const RendererView& view, 
+		const RenderTargets& renderTargets)
+	{
+		const auto& viewProps = view.getProperties();
+
+		bool isMSAA = view.getProperties().numSamples > 1;
+		SPtr<GpuParamBlockBuffer> perViewBuffer = view.getPerViewBuffer();
+
+		light.getParameters(mPerLightBuffer);
+
+		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);
+			}
+
+			gRendererUtility().drawScreenQuad();
+		}
+		else // Radial or spot
+		{
+			// Check if viewer is inside the light volume
+			float distSqrd = (light.internal->getBounds().getCenter() - viewProps.viewOrigin).squaredLength();
+
+			// Extend the bounds slighty to cover the case when the viewer is outside, but the near plane is intersecting
+			// the light bounds. We need to be conservative since the material for rendering outside will not properly
+			// render the inside of the light volume.
+			float boundRadius = light.internal->getBounds().getRadius() + viewProps.nearPlane * 3.0f;
+
+			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);
+				}
+			}
+
+			SPtr<Mesh> stencilMesh;
+			if(lightType == LightType::Radial)
+				stencilMesh = RendererUtility::instance().getRadialLightStencil();
+			else // Spot
+				stencilMesh = RendererUtility::instance().getSpotLightStencil();
+
+			gRendererUtility().draw(stencilMesh);
+		}
+	}
+}}