소스 검색

Reflection probe support added to forward path shaders

BearishSun 8 년 전
부모
커밋
9bc64c077b

+ 9 - 7
Data/Raw/Engine/Includes/ImageBasedLighting.bslinc

@@ -1,4 +1,8 @@
-Technique : base("ImageBasedLighting") =
+#include "$ENGINE$\ReflectionCubemapCommon.bslinc"
+
+Technique 
+ : base("ImageBasedLighting")
+ : inherits("ReflectionCubemapCommon") =
 {
 	Language = "HLSL11";
 
@@ -46,6 +50,7 @@ Technique : base("ImageBasedLighting") =
 				uint gReflCubemapNumMips;
 				uint gNumProbes;
 				uint gSkyCubemapAvailable;
+				uint gUseReflectionMaps;
 				uint gSkyCubemapNumMips;
 				float gSkyBrightness;
 			}	
@@ -139,10 +144,9 @@ Technique : base("ImageBasedLighting") =
 			
 			float3 gatherReflectionRadiance(float3 worldPos, float3 dir, float roughness, float3 specularColor, uint probeOffset, uint numProbes)
 			{
-				#if CAPTURING_REFLECTIONS
+				if(gUseReflectionMaps == 0)
 					return specularColor;
-				#else
-				
+										
 				float mipLevel = mapRoughnessToMipLevel(roughness, gReflCubemapNumMips);
 				
 				float3 output = 0;
@@ -180,7 +184,7 @@ Technique : base("ImageBasedLighting") =
 						leftoverContribution *= (1.0f - contribution);
 					}
 				}
-				
+					
 				if(gSkyCubemapAvailable > 0)
 				{
 					float skyMipLevel = mapRoughnessToMipLevel(roughness, gSkyCubemapNumMips);
@@ -190,8 +194,6 @@ Technique : base("ImageBasedLighting") =
 				}
 						
 				return output;
-						
-				#endif
 			}
 			
 			float3 getImageBasedSpecular(float3 worldPos, float3 V, float3 R, SurfaceData surfaceData, uint probeOffset, uint numProbes)

+ 2 - 1
Data/Raw/Engine/Includes/LightGridCommon.bslinc

@@ -11,7 +11,8 @@ Technique : base("LightGridCommon") =
 				// 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;			
+				uint3 gLightOffsets;
+				uint gNumReflProbes;
 				uint gNumCells;
 				uint3 gGridSize;
 				uint gMaxNumLightsPerCell;

+ 41 - 8
Data/Raw/Engine/Shaders/LightGridLLCreation.bsl

@@ -1,6 +1,7 @@
 #include "$ENGINE$\PerCameraData.bslinc"
 #define USE_LIGHT_GRID_INDICES
 #include "$ENGINE$\LightingCommon.bslinc"
+#include "$ENGINE$\ImageBasedLighting.bslinc"
 #include "$ENGINE$\LightGridCommon.bslinc"
 
 Blocks =
@@ -12,7 +13,8 @@ Blocks =
 Technique
  : inherits("PerCameraData")
  : inherits("LightingCommon")
- : inherits("LightGridCommon") =
+ : inherits("LightGridCommon")
+ : inherits("ImageBasedLighting") =
 {
 	Language = "HLSL11";
 	
@@ -20,15 +22,22 @@ Technique
 	{
 		Compute = 
 		{
-			RWBuffer<uint> gLinkedListCounter : register(u0);
-			RWBuffer<uint> gLinkedListHeads : register(u1);
-			RWBuffer<uint4> gLinkedList : register(u2);
-					
+			RWBuffer<uint> gLightsCounter;
+			RWBuffer<uint> gLightsLLHeads;
+			RWBuffer<uint4> gLightsLL;
+				
+			RWBuffer<uint> gProbesCounter;
+			RWBuffer<uint> gProbesLLHeads;
+			RWBuffer<uint2> gProbesLL;
+				
 			// Generates a an axis aligned bounding box in NDC and transforms it to view space.
 			// Note: This will overlap other cells, so it might be better to use frustum planes
 			// instead of AABB, although frustum testing procedure could result in more false positive
 			void calcCellAABB(uint3 cellIdx, out float3 center, out float3 extent)
 			{
+				// Note:: AABB calculation in tiled deferred image based lighting shader uses less instructions than this,
+				// see if it can be applied here.
+			
 				// Convert grid XY coordinates to clip coordinates
 				float2 a = 2.0f / gGridSize.xy;
 			
@@ -115,18 +124,42 @@ Technique
 						if(distSqrd <= (lightRadius * lightRadius))
 						{
 							uint nextLink;
-							InterlockedAdd(gLinkedListCounter[0], 1U, nextLink);
+							InterlockedAdd(gLightsCounter[0], 1U, nextLink);
 							
 							if(nextLink < maxNumLinks)
 							{
 								uint prevLink;
-								InterlockedExchange(gLinkedListHeads[cellIdx], nextLink, prevLink);
+								InterlockedExchange(gLightsLLHeads[cellIdx], nextLink, prevLink);
 								
-								gLinkedList[nextLink] = uint4(i, type, prevLink, 0);
+								gLightsLL[nextLink] = uint4(i, type, prevLink, 0);
 							}
 						}
 					}
 				}
+				
+				for(uint i = 0; i < gNumReflProbes; ++i)
+				{
+					float4 probePosition = mul(gMatView, float4(gReflectionProbes[i].position, 1.0f));
+					float probeRadius = gReflectionProbes[i].radius;
+					
+					// Calculate distance from box to light
+					float3 distances = max(abs(probePosition - cellCenter) - cellExtent, 0);
+					float distSqrd = dot(distances, distances);
+					
+					if(distSqrd <= (probeRadius * probeRadius))
+					{
+						uint nextLink;
+						InterlockedAdd(gProbesCounter[0], 1U, nextLink);
+						
+						if(nextLink < maxNumLinks)
+						{
+							uint prevLink;
+							InterlockedExchange(gProbesLLHeads[cellIdx], nextLink, prevLink);
+							
+							gProbesLL[nextLink] = uint2(i, prevLink);
+						}
+					}
+				}
 			}
 		};
 	};

+ 49 - 12
Data/Raw/Engine/Shaders/LightGridLLReduction.bsl

@@ -11,12 +11,19 @@ Technique
 	{
 		Compute = 
 		{
-			Buffer<uint> gLinkedListHeads : register(t0);
-			Buffer<uint4> gLinkedList : register(t1);
+			Buffer<uint> gLightsLLHeads;
+			Buffer<uint4> gLightsLL;
+						
+			Buffer<uint> gProbesLLHeads;
+			Buffer<uint2> gProbesLL;
 			
-			RWBuffer<uint> gGridDataCounter : register(u0);
-			RWBuffer<uint4> gGridLightOffsetAndSize : register(u1);
-			RWBuffer<uint> gGridLightIndices : register(u2);
+			RWBuffer<uint> gGridDataCounter;
+			
+			RWBuffer<uint4> gGridLightOffsetAndSize;
+			RWBuffer<uint> gGridLightIndices;
+
+			RWBuffer<uint2> gGridProbeOffsetAndSize;
+			RWBuffer<uint> gGridProbeIndices;
 			
 			[numthreads(THREADGROUP_SIZE, THREADGROUP_SIZE, THREADGROUP_SIZE)]
 			void main(
@@ -31,13 +38,14 @@ Technique
 				uint maxNumLinks = gNumCells * gMaxNumLightsPerCell;	
 				uint cellIdx = (dispatchThreadId.z * gGridSize.y + dispatchThreadId.y) * gGridSize.x + dispatchThreadId.x;
 				
-				// First count total number of lights affecting the tile
-				uint currentIdx = gLinkedListHeads[cellIdx];
+				// Reduce lights
+				//// First count total number of lights affecting the tile
+				uint currentIdx = gLightsLLHeads[cellIdx];
 				uint numRadialLights = 0;
 				uint numSpotLights = 0;
 				while(currentIdx != 0xFFFFFFFF)
 				{
-					uint4 entry = gLinkedList[currentIdx];
+					uint4 entry = gLightsLL[currentIdx];
 				
 					if(entry.y == 1) // Radial
 						numRadialLights++;
@@ -47,24 +55,53 @@ Technique
 					currentIdx = entry.z;
 				}
 				
-				// Allocate enough room and remember the offset to indices
+				//// Allocate enough room and remember the offset to indices
 				uint numLights = numRadialLights + numSpotLights;
 				uint indicesStart;
 				InterlockedAdd(gGridDataCounter[0], numLights, indicesStart);
 				gGridLightOffsetAndSize[cellIdx] = uint4(indicesStart, numRadialLights, numSpotLights, 0);
 				
-				// Actually write light indices (reverse order, so that radial lights come first, as is the convention)
-				currentIdx = gLinkedListHeads[cellIdx];
+				//// Actually write light indices (reverse order, so that radial lights come first, as is the convention)
+				currentIdx = gLightsLLHeads[cellIdx];
 				uint lightIdx = 0;
 				while(currentIdx != 0xFFFFFFFF)
 				{
-					uint4 entry = gLinkedList[currentIdx];
+					uint4 entry = gLightsLL[currentIdx];
 				
 					gGridLightIndices[indicesStart + numLights - 1 - lightIdx] = entry.x;
 					
 					currentIdx = entry.z;
 					lightIdx++;
 				}
+				
+				// Reduce probes
+				//// First count total number of probes affecting the tile
+				currentIdx = gProbesLLHeads[cellIdx];
+				uint numProbes = 0;
+				while(currentIdx != 0xFFFFFFFF)
+				{
+					uint2 entry = gProbesLL[currentIdx];
+				
+					numProbes++;
+					currentIdx = entry.y;
+				}
+				
+				//// Allocate enough room and remember the offset to indices
+				InterlockedAdd(gGridDataCounter[1], numProbes, indicesStart);
+				gGridProbeOffsetAndSize[cellIdx] = uint2(indicesStart, numProbes);
+				
+				//// Actually write probe indices (reverse order, in order to restore original order since LL was formed in reverse)
+				currentIdx = gProbesLLHeads[cellIdx];
+				uint probeIdx = 0;
+				while(currentIdx != 0xFFFFFFFF)
+				{
+					uint2 entry = gProbesLL[currentIdx];
+				
+					gGridProbeIndices[indicesStart + numProbes - 1 - probeIdx] = entry.x;
+					
+					currentIdx = entry.y;
+					probeIdx++;
+				}
 			}
 		};
 	};

+ 10 - 6
Data/Raw/Engine/Shaders/Transparent.bsl

@@ -59,7 +59,8 @@ Technique
 			Texture2D gRoughnessTex : register(t2);
 			Texture2D gMetalnessTex : register(t3);
 			
-			Buffer<uint3> gGridOffsetsAndSize : register(t4);
+			Buffer<uint4> gGridLightOffsetsAndSize;
+			Buffer<uint2> gGridProbeOffsetsAndSize;
 
 			cbuffer MaterialParams : register(b5)
 			{
@@ -80,13 +81,15 @@ Technique
 				
 				uint2 pixelPos = (uint2)input.position.xy;
 				uint cellIdx = calcCellIdx(pixelPos, input.position.z);
-				uint3 offsetAndSize = gGridOffsetsAndSize[cellIdx];
+				uint3 lightOffsetAndSize = gGridLightOffsetsAndSize[cellIdx].rgb;
 				
 				uint4 lightOffsets;
 				lightOffsets.x = gLightOffsets[0];
-				lightOffsets.y = offsetAndSize.x;
-				lightOffsets.z = lightOffsets.y + offsetAndSize.y;
-				lightOffsets.w = lightOffsets.z + offsetAndSize.z;
+				lightOffsets.y = lightOffsetAndSize.x;
+				lightOffsets.z = lightOffsets.y + lightOffsetAndSize.y;
+				lightOffsets.w = lightOffsets.z + lightOffsetAndSize.z;
+				
+				uint2 reflProbeOffsetAndSize = gGridProbeOffsetsAndSize[cellIdx];
 				
 				float3 V = normalize(gViewOrigin - input.worldPosition);
 				float3 N = surfaceData.worldNormal.xyz;
@@ -95,7 +98,8 @@ Technique
 				
 				float4 directLighting = getDirectLighting(input.worldPosition, V, specR, surfaceData, lightOffsets);
 				float3 indirectDiffuse = getSkyIndirectDiffuse(surfaceData.worldNormal) * surfaceData.albedo;
-				float3 imageBasedSpecular = getImageBasedSpecular(input.worldPosition, V, specR, surfaceData, 0, 0);
+				float3 imageBasedSpecular = getImageBasedSpecular(input.worldPosition, V, specR, surfaceData, 
+					reflProbeOffsetAndSize.x, reflProbeOffsetAndSize.y);
 
 				float3 totalLighting = directLighting.rgb;
 				totalLighting.rgb += indirectDiffuse;

+ 65 - 22
Source/RenderBeast/Include/BsImageBasedLighting.h

@@ -49,6 +49,7 @@ namespace bs { namespace ct
 		BS_PARAM_BLOCK_ENTRY(INT32, gReflCubemapNumMips)
 		BS_PARAM_BLOCK_ENTRY(INT32, gNumProbes)
 		BS_PARAM_BLOCK_ENTRY(INT32, gSkyCubemapAvailable)
+		BS_PARAM_BLOCK_ENTRY(INT32, gUseReflectionMaps)
 		BS_PARAM_BLOCK_ENTRY(INT32, gSkyCubemapNumMips)
 		BS_PARAM_BLOCK_ENTRY(float, gSkyBrightness)
 	BS_PARAM_BLOCK_END
@@ -79,6 +80,34 @@ namespace bs { namespace ct
 
 	extern TiledImageBasedLightingParamDef gTiledImageBasedLightingParamDef;
 
+	/** Helper struct containing all parameters for binding image lighting related data to the GPU programs using them .*/
+	struct ImageBasedLightingParams
+	{
+		/** 
+		 * Initializes the parameters from the provided @p params object. 
+		 *
+		 * @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]	optional	If true no warnings will be thrown if some or all of the parameters will be found.
+		 * @param[in]	gridIndices	Set to true if grid indices (used by light grid) parameter is required.
+		 */
+		void populate(const SPtr<GpuParamsSet>& paramsSet, GpuProgramType programType, bool optional, bool gridIndices);
+
+		GpuParamTexture skyReflectionsTexParam;
+		GpuParamSampState skyReflectionsSampParam;
+
+		GpuParamTexture skyIrradianceTexParam;
+
+		GpuParamTexture reflectionProbeCubemapsTexParam;
+		GpuParamSampState reflectionProbeCubemapsSampParam;
+
+		GpuParamTexture preintegratedEnvBRDFParam;
+		GpuParamBuffer reflectionProbesParam;
+
+		GpuParamBuffer reflectionProbeIndicesParam;
+		UINT32 reflProbeParamsBindingIdx;
+	};
+
 	/** Functionality common to all versions of TiledDeferredImageBasedLightingMat<T>. */
 	class TiledDeferredImageBasedLighting
 	{
@@ -91,11 +120,18 @@ namespace bs { namespace ct
 					 const SPtr<Texture>& preintegratedGF);
 
 		/** Binds all the active reflection probes. */
-		void setReflectionProbes(const GPUReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps);
+		void setReflectionProbes(const GPUReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps, 
+			bool capturingReflections);
 
 		/** 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);
 
+		/** Returns a param buffer containing information required to evaluate reflection probe data. */
+		SPtr<GpuParamBlockBuffer> getReflectionsParamBuffer() const { return mReflectionsParamBuffer; }
+
+		/** Returns a sampler state object that should be used for evaluating reflection maps. */
+		SPtr<SamplerState> getReflectionsSamplerState() const { return mReflectionSamplerState; }
+
 		/**
 		 * 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
@@ -120,11 +156,7 @@ namespace bs { namespace ct
 		GpuParamTexture mInColorTextureParam;
 		GpuParamBuffer mInColorBufferParam;
 
-		GpuParamTexture mSkyReflectionsParam;
-		GpuParamTexture mSkyIrradianceParam;
-		GpuParamTexture mReflectionProbeCubemapsParam;
-		GpuParamTexture mPreintegratedEnvBRDFParam;
-		GpuParamBuffer mReflectionProbesParam;
+		ImageBasedLightingParams mImageBasedParams;
 
 		GpuParamLoadStoreTexture mOutputTextureParam;
 		GpuParamBuffer mOutputBufferParam;
@@ -140,21 +172,28 @@ namespace bs { namespace ct
 	public:
 		virtual ~ITiledDeferredImageBasedLightingMat() {}
 
-		/** @copydoc ITiledDeferredImageBasedLightingMat::execute() */
+		/** @copydoc TiledDeferredImageBasedLighting::execute() */
 		virtual void execute(const SPtr<RenderTargets>& renderTargets, const SPtr<GpuParamBlockBuffer>& perCamera,
 			const SPtr<Texture>& preintegratedGF) = 0;
 
-		/** @copydoc ITiledDeferredImageBasedLightingMat::setReflectionProbes() */
-		virtual void setReflectionProbes(const GPUReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps) = 0;
+		/** @copydoc TiledDeferredImageBasedLighting::setReflectionProbes() */
+		virtual void setReflectionProbes(const GPUReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps,
+			bool capturingReflections) = 0;
 
-		/** @copydoc ITiledDeferredImageBasedLightingMat::setSky() */
+		/** @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;
 	};
 
 	/** Shader that performs a lighting pass over data stored in the Gbuffer. */
-	template<int MSAA_COUNT, bool CapturingReflections>
+	template<int MSAA_COUNT>
 	class TTiledDeferredImageBasedLightingMat : public ITiledDeferredImageBasedLightingMat, 
-		public RendererMaterial<TTiledDeferredImageBasedLightingMat<MSAA_COUNT, CapturingReflections>>
+		public RendererMaterial<TTiledDeferredImageBasedLightingMat<MSAA_COUNT>>
 	{
 		RMAT_DEF("TiledDeferredImageBasedLighting.bsl");
 
@@ -166,10 +205,17 @@ namespace bs { namespace ct
 			const SPtr<Texture>& preintegratedGF) override;
 
 		/** @copydoc ITiledDeferredImageBasedLightingMat::setReflectionProbes() */
-		void setReflectionProbes(const GPUReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps) override;
+		void setReflectionProbes(const GPUReflProbeData& 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;
 	};
@@ -182,17 +228,14 @@ namespace bs { namespace ct
 		~TiledDeferredImageBasedLightingMaterials();
 
 		/**
-		* Returns a version of the tile-deferred image based lighting material that matches the parameters.
-		*
-		* @param[in]   msaa						Number of samples per pixel.
-		* @param[in]   capturingReflections		If true reflection probes will not be evaluated and instead the material's
-		*										specular color will be returned instead. Useful when rendering reflection
-		*										probes.
-		*/
-		ITiledDeferredImageBasedLightingMat* get(UINT32 msaa, bool capturingReflections);
+		 * 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);
 
 	private:
-		ITiledDeferredImageBasedLightingMat* mInstances[8];
+		ITiledDeferredImageBasedLightingMat* mInstances[4];
 	};
 
 	/** @} */

+ 58 - 22
Source/RenderBeast/Include/BsLightGrid.h

@@ -9,6 +9,7 @@
 
 namespace bs { namespace ct
 {
+	class GPUReflProbeData;
 	class GPULightData;
 
 	/** @addtogroup RenderBeast
@@ -17,6 +18,7 @@ namespace bs { namespace ct
 
 	BS_PARAM_BLOCK_BEGIN(LightGridParamDef)
 		BS_PARAM_BLOCK_ENTRY(Vector3I, gLightOffsets)
+		BS_PARAM_BLOCK_ENTRY(INT32, gNumReflProbes)
 		BS_PARAM_BLOCK_ENTRY(INT32, gNumCells)
 		BS_PARAM_BLOCK_ENTRY(Vector3I, gGridSize)
 		BS_PARAM_BLOCK_ENTRY(INT32, gMaxNumLightsPerCell)
@@ -25,7 +27,10 @@ namespace bs { namespace ct
 
 	extern LightGridParamDef gLightGridParamDefDef;
 
-	/** Shader that creates a linked list for each light grid cell, containing which light affects each cell. */
+	/** 
+	 * Shader that creates a linked list for each light grid cell, containing which lights and reflection probes affects
+	 * each cell. 
+	 */
 	class LightGridLLCreationMat : public RendererMaterial<LightGridLLCreationMat>
 	{
 		RMAT_DEF("LightGridLLCreation.bsl");
@@ -35,22 +40,32 @@ namespace bs { namespace ct
 
 		/** Binds parameter buffers and prepares any internal buffers. Must be called before execute(). */
 		void setParams(const Vector3I& gridSize, const SPtr<GpuParamBlockBuffer>& gridParams, 
-					   const SPtr<GpuBuffer>& lightsBuffer);
+					   const SPtr<GpuBuffer>& lightsBuffer, const SPtr<GpuBuffer>& probesBuffer);
 
 		/** Binds the material for rendering, sets up per-camera parameters and executes it. */
 		void execute(const RendererCamera& view);
 
 		/** Returns the buffers generated by execute(). */
-		void getOutputs(SPtr<GpuBuffer>& linkedListHeads, SPtr<GpuBuffer>& linkedList) const;
+		void getOutputs(SPtr<GpuBuffer>& lightsLLHeads, SPtr<GpuBuffer>& lightsLL, SPtr<GpuBuffer>& probesLLHeads, 
+			SPtr<GpuBuffer>& probesLL) const;
 	private:
 		GpuParamBuffer mLightBufferParam;
-		GpuParamBuffer mLinkedListCounterParam;
-		GpuParamBuffer mLinkedListHeadsParam;
-		GpuParamBuffer mLinkedListParam;
+		GpuParamBuffer mLightsCounterParam;
+		GpuParamBuffer mLightsLLHeadsParam;
+		GpuParamBuffer mLightsLLParam;
+
+		GpuParamBuffer mProbesBufferParam;
+		GpuParamBuffer mProbesCounterParam;
+		GpuParamBuffer mProbesLLHeadsParam;
+		GpuParamBuffer mProbesLLParam;
 
-		SPtr<GpuBuffer> mLinkedListCounter;
-		SPtr<GpuBuffer> mLinkedListHeads;
-		SPtr<GpuBuffer> mLinkedList;
+		SPtr<GpuBuffer> mLightsCounter;
+		SPtr<GpuBuffer> mLightsLLHeads;
+		SPtr<GpuBuffer> mLightsLL;
+
+		SPtr<GpuBuffer> mProbesCounter;
+		SPtr<GpuBuffer> mProbesLLHeads;
+		SPtr<GpuBuffer> mProbesLL;
 
 		UINT32 mBufferNumCells;
 		Vector3I mGridSize;
@@ -66,25 +81,38 @@ namespace bs { namespace ct
 
 		/** Binds parameter buffers and prepares any internal buffers. Must be called before execute(). */
 		void setParams(const Vector3I& gridSize, const SPtr<GpuParamBlockBuffer>& gridParams, 
-					   const SPtr<GpuBuffer>& linkedListHeads, const SPtr<GpuBuffer>& linkedList);
+			const SPtr<GpuBuffer>& lightLLHeads, const SPtr<GpuBuffer>& lightLL,
+			const SPtr<GpuBuffer>& probeLLHeads, const SPtr<GpuBuffer>& probeLL);
 
 		/** Binds the material for renderingand executes it. */
 		void execute(const RendererCamera& view);
 
 		/** Returns the buffers generated by execute(). */
-		void getOutputs(SPtr<GpuBuffer>& gridOffsetsAndSize, SPtr<GpuBuffer>& gridLightIndices) const;
+		void getOutputs(SPtr<GpuBuffer>& gridLightOffsetsAndSize, SPtr<GpuBuffer>& gridLightIndices,
+			SPtr<GpuBuffer>& gridProbeOffsetsAndSize, SPtr<GpuBuffer>& gridProbeIndices) const;
 	private:
-		GpuParamBuffer mLinkedListHeadsParam;
-		GpuParamBuffer mLinkedListParam;
+		GpuParamBuffer mLightsLLHeadsParam;
+		GpuParamBuffer mLightsLLParam;
+
+		GpuParamBuffer mProbesLLHeadsParam;
+		GpuParamBuffer mProbesLLParam;
 
 		GpuParamBuffer mGridDataCounterParam;
+
 		GpuParamBuffer mGridLightOffsetAndSizeParam;
 		GpuParamBuffer mGridLightIndicesParam;
 
+		GpuParamBuffer mGridProbeOffsetAndSizeParam;
+		GpuParamBuffer mGridProbeIndicesParam;
+
 		SPtr<GpuBuffer> mGridDataCounter;
+
 		SPtr<GpuBuffer> mGridLightOffsetAndSize;
 		SPtr<GpuBuffer> mGridLightIndices;
 
+		SPtr<GpuBuffer> mGridProbeOffsetAndSize;
+		SPtr<GpuBuffer> mGridProbeIndices;
+
 		UINT32 mBufferNumCells;
 		Vector3I mGridSize;
 	};
@@ -99,20 +127,28 @@ namespace bs { namespace ct
 		LightGrid();
 
 		/** Updates the light grid from the provided view. */
-		void updateGrid(const RendererCamera& view, const GPULightData& lightData, bool noLighting);
+		void updateGrid(const RendererCamera& view, const GPULightData& lightData, const GPUReflProbeData& probeData, 
+			bool noLighting);
 
 		/** 
 		 * Returns the buffers containing light indices per grid cell and global grid parameters. 
 		 *
-		 * @param[out]	gridOffsetsAndSize	Flattened array of grid cells, where each entry contains the number of lights
-		 *									affecting that cell, and a index into the @p gridLightIndices buffer.
-		 * @param[out]	gridLightIndices	A list of light indices. Each cell's indices start at specific position and
-		 *									are placed sequentially one after another. Lookup into this array is done
-		 *									through offset & size provided by @p gridOffsetsAndSize. 
-		 * @param[out]	gridParams			Global grid parameter block.
+		 * @param[out]	gridLightOffsetsAndSize	Flattened array of grid cells, where each entry contains the number of 
+		 *										lights affecting that cell, and a index into the @p gridLightIndices buffer.
+		 * @param[out]	gridLightIndices		A list of light indices. Each cell's indices start at specific position and
+		 *										are placed sequentially one after another. Lookup into this array is done
+		 *										through offset & size provided by @p gridLightOffsetsAndSize. 
+		 * @param[out]	gridProbeOffsetsAndSize	Flattened array of grid cells, where each entry contains the number of
+		 *										reflection probes affecting that cell, and a index into the 
+		 *										@p gridProbeIndices buffer.
+		 * @param[out]	gridProbeIndices		A list of reflection probe indices. Each cell's indices start at specific
+		 *										position and are placed sequentially one after another. Lookup into this
+		 *										array is done through offset & size provided by @p gridProbeOffsetsAndSize.
+		 * @param[out]	gridParams				Global grid parameter block.
 		 */
-		void getOutputs(SPtr<GpuBuffer>& gridOffsetsAndSize, SPtr<GpuBuffer>& gridLightIndices, 
-						SPtr<GpuParamBlockBuffer>& gridParams) const;
+		void getOutputs(SPtr<GpuBuffer>& gridLightOffsetsAndSize, SPtr<GpuBuffer>& gridLightIndices, 
+			SPtr<GpuBuffer>& gridProbeOffsetsAndSize, SPtr<GpuBuffer>& gridProbeIndices, 
+			SPtr<GpuParamBlockBuffer>& gridParams) const;
 
 	private:
 		LightGridLLCreationMat mLLCreationMat;

+ 12 - 2
Source/RenderBeast/Include/BsRendererObject.h

@@ -7,6 +7,7 @@
 #include "BsRenderable.h"
 #include "BsParamBlocks.h"
 #include "BsMaterialParam.h"
+#include "BsImageBasedLighting.h"
 
 namespace bs { namespace ct
 {
@@ -71,7 +72,7 @@ namespace bs { namespace ct
 		 * Parameter to which to bind a buffer containing light grid offsets and size, per grid cell. Used for forward
 		 * rendering. 
 		 */
-		GpuParamBuffer gridOffsetsAndSizeParam;
+		GpuParamBuffer gridLightOffsetsAndSizeParam;
 
 		/** Parameter to which to bind a buffer containing all light indices, as mapped by grid offsets & size. */
 		GpuParamBuffer gridLightIndicesParam;
@@ -79,6 +80,15 @@ namespace bs { namespace ct
 		/** Parameter to which to bind light buffer used for forward rendering. */
 		GpuParamBuffer lightsBufferParam;
 
+		/** 
+		 * Parameter to which to bind a buffer containing reflection probe grid offsets and size, per grid cell. Used for
+		 * forward rendering. 
+		 */
+		GpuParamBuffer gridProbeOffsetsAndSizeParam;
+
+		/** Collection of parameters used for image based lighting. */
+		ImageBasedLightingParams imageBasedParams;
+
 		/** GPU buffer containing element's bone matrices, if it requires any. */
 		SPtr<GpuBuffer> boneMatrixBuffer;
 
@@ -116,4 +126,4 @@ namespace bs { namespace ct
 	};
 
 	/** @} */
-}}
+}}

+ 85 - 65
Source/RenderBeast/Source/BsImageBasedLighting.cpp

@@ -4,6 +4,7 @@
 #include "BsMaterial.h"
 #include "BsShader.h"
 #include "BsGpuBuffer.h"
+#include "BsGpuParamsSet.h"
 #include "BsReflectionProbe.h"
 #include "BsLightProbeCache.h"
 #include "BsGpuParamsSet.h"
@@ -81,6 +82,40 @@ namespace bs { namespace ct
 		output.invBoxTransform.setInverseTRS(output.position, probe->getRotation(), output.boxExtents);
 	}
 
+	void ImageBasedLightingParams::populate(const SPtr<GpuParamsSet>& paramsSet, GpuProgramType programType, bool optional, 
+		bool gridIndices)
+	{
+		SPtr<GpuParams> params = paramsSet->getGpuParams();
+
+		// Sky
+		if (!optional || params->hasTexture(programType, "gSkyReflectionTex"))
+		{
+			params->getTextureParam(programType, "gSkyReflectionTex", skyReflectionsTexParam);
+			params->getSamplerStateParam(programType, "gSkyReflectionSamp", skyReflectionsSampParam);
+
+			params->getTextureParam(programType, "gSkyIrradianceTex", skyIrradianceTexParam);
+		}
+
+		// Reflections
+		if (!optional || params->hasTexture(programType, "gReflProbeCubemaps"))
+		{
+			params->getTextureParam(programType, "gReflProbeCubemaps", reflectionProbeCubemapsTexParam);
+			params->getSamplerStateParam(programType, "gReflProbeSamp", reflectionProbeCubemapsSampParam);
+
+			params->getBufferParam(programType, "gReflectionProbes", reflectionProbesParam);
+
+			params->getTextureParam(programType, "gPreintegratedEnvBRDF", preintegratedEnvBRDFParam);
+		}
+
+		if(gridIndices)
+		{
+			if (!optional || params->hasBuffer(programType, "gReflectionProbeIndices"))
+				params->getBufferParam(programType, "gReflectionProbeIndices", reflectionProbeIndicesParam);
+		}
+
+		reflProbeParamsBindingIdx = paramsSet->getParamBlockBufferIndex("ReflProbeParams");
+	}
+
 	// 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
 	// due to increased thread group load.
@@ -119,15 +154,7 @@ namespace bs { namespace ct
 		mParamBuffer = gTiledImageBasedLightingParamDef.createBuffer();
 		mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
 
-		// Sky
-		params->getTextureParam(GPT_COMPUTE_PROGRAM, "gSkyReflectionTex", mSkyReflectionsParam);
-		params->getTextureParam(GPT_COMPUTE_PROGRAM, "gSkyIrradianceTex", mSkyIrradianceParam);
-
-		// Reflections
-		params->getTextureParam(GPT_COMPUTE_PROGRAM, "gReflProbeCubemaps", mReflectionProbeCubemapsParam);
-		params->getTextureParam(GPT_COMPUTE_PROGRAM, "gPreintegratedEnvBRDF", mPreintegratedEnvBRDFParam);
-
-		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gReflectionProbes", mReflectionProbesParam);
+		mImageBasedParams.populate(mParamsSet, GPT_COMPUTE_PROGRAM, false, false);
 
 		mReflectionsParamBuffer = gReflProbeParamsParamDef.createBuffer();
 		mParamsSet->setParamBlockBuffer("ReflProbeParams", mReflectionsParamBuffer);
@@ -139,8 +166,8 @@ namespace bs { namespace ct
 
 		mReflectionSamplerState = SamplerState::create(reflSamplerDesc);
 
-		params->setSamplerState(GPT_COMPUTE_PROGRAM, "gSkyReflectionSamp", mReflectionSamplerState);
-		params->setSamplerState(GPT_COMPUTE_PROGRAM, "gReflProbeSamp", mReflectionSamplerState);
+		mImageBasedParams.skyReflectionsSampParam.set(mReflectionSamplerState);
+		mImageBasedParams.reflectionProbeCubemapsSampParam.set(mReflectionSamplerState);
 	}
 
 	void TiledDeferredImageBasedLighting::execute(const SPtr<RenderTargets>& renderTargets,
@@ -159,7 +186,7 @@ namespace bs { namespace ct
 		mGBufferC.set(renderTargets->getGBufferC());
 		mGBufferDepth.set(renderTargets->getSceneDepth());
 
-		mPreintegratedEnvBRDFParam.set(preintegratedGF);
+		mImageBasedParams.preintegratedEnvBRDFParam.set(preintegratedGF);
 
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
 
@@ -187,10 +214,10 @@ namespace bs { namespace ct
 	}
 
 	void TiledDeferredImageBasedLighting::setReflectionProbes(const GPUReflProbeData& probeData,
-		const SPtr<Texture>& reflectionCubemaps)
+		const SPtr<Texture>& reflectionCubemaps, bool capturingReflections)
 	{
-		mReflectionProbesParam.set(probeData.getProbeBuffer());
-		mReflectionProbeCubemapsParam.set(reflectionCubemaps);
+		mImageBasedParams.reflectionProbesParam.set(probeData.getProbeBuffer());
+		mImageBasedParams.reflectionProbeCubemapsTexParam.set(reflectionCubemaps);
 
 		gReflProbeParamsParamDef.gNumProbes.set(mReflectionsParamBuffer, probeData.getNumProbes());
 
@@ -199,13 +226,14 @@ namespace bs { namespace ct
 			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)
 	{
-		mSkyReflectionsParam.set(skyReflections);
-		mSkyIrradianceParam.set(skyIrradiance);
+		mImageBasedParams.skyReflectionsTexParam.set(skyReflections);
+		mImageBasedParams.skyIrradianceTexParam.set(skyIrradiance);
 
 		UINT32 skyReflectionsAvailable = 0;
 		UINT32 numMips = 0;
@@ -317,10 +345,10 @@ namespace bs { namespace ct
 					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)
+					// 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
+					// 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;
@@ -356,84 +384,76 @@ namespace bs { namespace ct
 		return texture;
 	}
 
-	template<int MSAA_COUNT, bool CapturingReflections>
-	TTiledDeferredImageBasedLightingMat<MSAA_COUNT, CapturingReflections>::TTiledDeferredImageBasedLightingMat()
+	template<int MSAA_COUNT>
+	TTiledDeferredImageBasedLightingMat<MSAA_COUNT>::TTiledDeferredImageBasedLightingMat()
 		:mInternal(mMaterial, mParamsSet, MSAA_COUNT)
 	{
 
 	}
 
-	template<int MSAA_COUNT, bool CapturingReflections>
-	void TTiledDeferredImageBasedLightingMat<MSAA_COUNT, CapturingReflections>::_initDefines(ShaderDefines& defines)
+	template<int MSAA_COUNT>
+	void TTiledDeferredImageBasedLightingMat<MSAA_COUNT>::_initDefines(ShaderDefines& defines)
 	{
 		defines.set("TILE_SIZE", TiledDeferredImageBasedLighting::TILE_SIZE);
 		defines.set("MSAA_COUNT", MSAA_COUNT);
-		defines.set("CAPTURING_REFLECTIONS", CapturingReflections);
 	}
 
-	template<int MSAA_COUNT, bool CapturingReflections>
-	void TTiledDeferredImageBasedLightingMat<MSAA_COUNT, CapturingReflections>::execute(const SPtr<RenderTargets>& gbuffer,
+	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, bool CapturingReflections>
-	void TTiledDeferredImageBasedLightingMat<MSAA_COUNT, CapturingReflections>::setReflectionProbes(
-		const GPUReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps)
+	template<int MSAA_COUNT>
+	void TTiledDeferredImageBasedLightingMat<MSAA_COUNT>::setReflectionProbes(const GPUReflProbeData& probeData, 
+		const SPtr<Texture>& reflectionCubemaps, bool capturingReflections)
 	{
-		mInternal.setReflectionProbes(probeData, reflectionCubemaps);
+		mInternal.setReflectionProbes(probeData, reflectionCubemaps, capturingReflections);
 	}
 
-	template<int MSAA_COUNT, bool CapturingReflections>
-	void TTiledDeferredImageBasedLightingMat<MSAA_COUNT, CapturingReflections>::setSky(const SPtr<Texture>& skyReflections,
+	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, false>>();
-		mInstances[1] = bs_new<TTiledDeferredImageBasedLightingMat<2, false>>();
-		mInstances[2] = bs_new<TTiledDeferredImageBasedLightingMat<4, false>>();
-		mInstances[3] = bs_new<TTiledDeferredImageBasedLightingMat<8, false>>();
-
-		mInstances[4] = bs_new<TTiledDeferredImageBasedLightingMat<1, true>>();
-		mInstances[5] = bs_new<TTiledDeferredImageBasedLightingMat<2, true>>();
-		mInstances[6] = bs_new<TTiledDeferredImageBasedLightingMat<4, true>>();
-		mInstances[7] = bs_new<TTiledDeferredImageBasedLightingMat<8, true>>();
+		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 < 8; i++)
+		for (UINT32 i = 0; i < 4; i++)
 			bs_delete(mInstances[i]);
 	}
 
-	ITiledDeferredImageBasedLightingMat* TiledDeferredImageBasedLightingMaterials::get(UINT32 msaa, bool capturingReflections)
+	ITiledDeferredImageBasedLightingMat* TiledDeferredImageBasedLightingMaterials::get(UINT32 msaa)
 	{
-		if (!capturingReflections)
-		{
-			if (msaa == 1)
-				return mInstances[0];
-			else if (msaa == 2)
-				return mInstances[1];
-			else if (msaa == 4)
-				return mInstances[2];
-			else
-				return mInstances[3];
-		}
+		if (msaa == 1)
+			return mInstances[0];
+		else if (msaa == 2)
+			return mInstances[1];
+		else if (msaa == 4)
+			return mInstances[2];
 		else
-		{
-			if (msaa == 1)
-				return mInstances[4];
-			else if (msaa == 2)
-				return mInstances[5];
-			else if (msaa == 4)
-				return mInstances[6];
-			else
-				return mInstances[7];
-		}
+			return mInstances[3];
 	}
 }}

+ 91 - 37
Source/RenderBeast/Source/BsLightGrid.cpp

@@ -7,6 +7,7 @@
 #include "BsRendererCamera.h"
 #include "BsRenderTargets.h"
 #include "BsLightRendering.h"
+#include "BsImageBasedLighting.h"
 
 namespace bs { namespace ct
 {
@@ -23,9 +24,14 @@ namespace bs { namespace ct
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 
 		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLights", mLightBufferParam);
-		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLinkedListCounter", mLinkedListCounterParam);
-		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLinkedListHeads", mLinkedListHeadsParam);
-		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLinkedList", mLinkedListParam);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLightsCounter", mLightsCounterParam);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLightsLLHeads", mLightsLLHeadsParam);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLightsLL", mLightsLLParam);
+
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gReflectionProbes", mProbesBufferParam);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gProbesCounter", mProbesCounterParam);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gProbesLLHeads", mProbesLLHeadsParam);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gProbesLL", mProbesLLParam);
 
 		GPU_BUFFER_DESC desc;
 		desc.elementCount = 1;
@@ -34,8 +40,11 @@ namespace bs { namespace ct
 		desc.type = GBT_STANDARD;
 		desc.elementSize = 0;
 
-		mLinkedListCounter = GpuBuffer::create(desc);
-		mLinkedListCounterParam.set(mLinkedListCounter);
+		mLightsCounter = GpuBuffer::create(desc);
+		mLightsCounterParam.set(mLightsCounter);
+
+		mProbesCounter = GpuBuffer::create(desc);
+		mProbesCounterParam.set(mProbesCounter);
 	}
 
 	void LightGridLLCreationMat::_initDefines(ShaderDefines& defines)
@@ -44,7 +53,7 @@ namespace bs { namespace ct
 	}
 
 	void LightGridLLCreationMat::setParams(const Vector3I& gridSize, const SPtr<GpuParamBlockBuffer>& gridParams,
-											   const SPtr<GpuBuffer>& lightsBuffer)
+		const SPtr<GpuBuffer>& lightsBuffer, const SPtr<GpuBuffer>& probesBuffer)
 	{
 		mGridSize = gridSize;
 		UINT32 numCells = gridSize[0] * gridSize[1] * gridSize[2];
@@ -58,31 +67,45 @@ namespace bs { namespace ct
 			desc.type = GBT_STANDARD;
 			desc.elementSize = 0;
 
-			mLinkedListHeads = GpuBuffer::create(desc);
-			mLinkedListHeadsParam.set(mLinkedListHeads);
+			mLightsLLHeads = GpuBuffer::create(desc);
+			mLightsLLHeadsParam.set(mLightsLLHeads);
+
+			mProbesLLHeads = GpuBuffer::create(desc);
+			mProbesLLHeadsParam.set(mProbesLLHeads);
 
 			desc.format = BF_32X4U;
 			desc.elementCount = numCells * MAX_LIGHTS_PER_CELL;
 
-			mLinkedList = GpuBuffer::create(desc);
-			mLinkedListParam.set(mLinkedList);
+			mLightsLL = GpuBuffer::create(desc);
+			mLightsLLParam.set(mLightsLL);
+
+			desc.format = BF_32X2U;
+			mProbesLL = GpuBuffer::create(desc);
+			mProbesLLParam.set(mProbesLL);
 
 			mBufferNumCells = numCells;
 		}
 
 		UINT32 zero = 0;
-		mLinkedListCounter->writeData(0, sizeof(UINT32), &zero, BWT_DISCARD);
+		mLightsCounter->writeData(0, sizeof(UINT32), &zero, BWT_DISCARD);
+		mProbesCounter->writeData(0, sizeof(UINT32), &zero, BWT_DISCARD);
 
 		// Note: Add a method to clear buffer data directly? e.g. GpuBuffer->clear(value);
-		UINT32* headsClearData = (UINT32*)bs_stack_alloc(mLinkedListHeads->getSize());
-		memset(headsClearData, 0xFFFFFFFF, mLinkedListHeads->getSize());
+		UINT32* headsClearData = (UINT32*)bs_stack_alloc(mLightsLLHeads->getSize());
+		memset(headsClearData, 0xFFFFFFFF, mLightsLLHeads->getSize());
 
-		mLinkedListHeads->writeData(0, mLinkedListHeads->getSize(), headsClearData, BWT_DISCARD);
+		mLightsLLHeads->writeData(0, mLightsLLHeads->getSize(), headsClearData, BWT_DISCARD);
+		bs_stack_free(headsClearData);
+
+		headsClearData = (UINT32*)bs_stack_alloc(mProbesLLHeads->getSize());
+		memset(headsClearData, 0xFFFFFFFF, mProbesLLHeads->getSize());
 
+		mProbesLLHeads->writeData(0, mProbesLLHeads->getSize(), headsClearData, BWT_DISCARD);
 		bs_stack_free(headsClearData);
 
 		mParamsSet->setParamBlockBuffer("GridParams", gridParams, true);
 		mLightBufferParam.set(lightsBuffer);
+		mProbesBufferParam.set(probesBuffer);
 	}
 
 	void LightGridLLCreationMat::execute(const RendererCamera& view)
@@ -99,10 +122,13 @@ namespace bs { namespace ct
 		RenderAPI::instance().dispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
 	}
 
-	void LightGridLLCreationMat::getOutputs(SPtr<GpuBuffer>& linkedListHeads, SPtr<GpuBuffer>& linkedList) const
+	void LightGridLLCreationMat::getOutputs(SPtr<GpuBuffer>& lightsLLHeads, SPtr<GpuBuffer>& lightsLL, 
+		SPtr<GpuBuffer>& probesLLHeads, SPtr<GpuBuffer>& probesLL) const
 	{
-		linkedListHeads = mLinkedListHeads;
-		linkedList = mLinkedList;
+		lightsLLHeads = mLightsLLHeads;
+		lightsLL = mLightsLL;
+		probesLLHeads = mProbesLLHeads;
+		probesLL = mProbesLL;
 	}
 
 	LightGridLLReductionMat::LightGridLLReductionMat()
@@ -110,15 +136,22 @@ namespace bs { namespace ct
 	{
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 
-		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLinkedListHeads", mLinkedListHeadsParam);
-		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLinkedList", mLinkedListParam);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLightsLLHeads", mLightsLLHeadsParam);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLightsLL", mLightsLLParam);
+
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gProbesLLHeads", mProbesLLHeadsParam);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gProbesLL", mProbesLLParam);
 
 		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gGridDataCounter", mGridDataCounterParam);
+
 		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gGridLightOffsetAndSize", mGridLightOffsetAndSizeParam);
 		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gGridLightIndices", mGridLightIndicesParam);
 
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gGridProbeOffsetAndSize", mGridProbeOffsetAndSizeParam);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gGridProbeIndices", mGridProbeIndicesParam);
+
 		GPU_BUFFER_DESC desc;
-		desc.elementCount = 1;
+		desc.elementCount = 2;
 		desc.format = BF_32X1U;
 		desc.randomGpuWrite = true;
 		desc.type = GBT_STANDARD;
@@ -134,7 +167,8 @@ namespace bs { namespace ct
 	}
 
 	void LightGridLLReductionMat::setParams(const Vector3I& gridSize, const SPtr<GpuParamBlockBuffer>& gridParams,
-											const SPtr<GpuBuffer>& linkedListHeads, const SPtr<GpuBuffer>& linkedList)
+		const SPtr<GpuBuffer>& lightsLLHeads, const SPtr<GpuBuffer>& lightsLL,
+		const SPtr<GpuBuffer>& probeLLHeads, const SPtr<GpuBuffer>& probeLL)
 	{
 		mGridSize = gridSize;
 		UINT32 numCells = gridSize[0] * gridSize[1] * gridSize[2];
@@ -151,21 +185,33 @@ namespace bs { namespace ct
 			mGridLightOffsetAndSize = GpuBuffer::create(desc);
 			mGridLightOffsetAndSizeParam.set(mGridLightOffsetAndSize);
 
+			desc.format = BF_32X2U;
+
+			mGridProbeOffsetAndSize = GpuBuffer::create(desc);
+			mGridProbeOffsetAndSizeParam.set(mGridProbeOffsetAndSize);
+
 			desc.format = BF_32X1U;
 			desc.elementCount = numCells * MAX_LIGHTS_PER_CELL;
 			mGridLightIndices = GpuBuffer::create(desc);
 			mGridLightIndicesParam.set(mGridLightIndices);
 
+			mGridProbeIndices = GpuBuffer::create(desc);
+			mGridProbeIndicesParam.set(mGridProbeIndices);
+
 			mBufferNumCells = numCells;
 		}
 
 		// Note: Add a method to clear buffer data directly? e.g. GpuBuffer->clear(value);
-		UINT32 zero = 0;
-		mGridDataCounter->writeData(0, sizeof(UINT32), &zero, BWT_DISCARD);
+		UINT32 zeros[] = { 0, 0 };
+		mGridDataCounter->writeData(0, sizeof(UINT32) * 2, zeros, BWT_DISCARD);
 
 		mParamsSet->setParamBlockBuffer("GridParams", gridParams, true);
-		mLinkedListHeadsParam.set(linkedListHeads);
-		mLinkedListParam.set(linkedList);
+
+		mLightsLLHeadsParam.set(lightsLLHeads);
+		mLightsLLParam.set(lightsLL);
+
+		mProbesLLHeadsParam.set(probeLLHeads);
+		mProbesLLParam.set(probeLL);
 	}
 
 	void LightGridLLReductionMat::execute(const RendererCamera& view)
@@ -182,10 +228,13 @@ namespace bs { namespace ct
 		RenderAPI::instance().dispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
 	}
 
-	void LightGridLLReductionMat::getOutputs(SPtr<GpuBuffer>& gridOffsetsAndSize, SPtr<GpuBuffer>& gridLightIndices) const
+	void LightGridLLReductionMat::getOutputs(SPtr<GpuBuffer>& gridLightOffsetsAndSize, SPtr<GpuBuffer>& gridLightIndices,
+		SPtr<GpuBuffer>& gridProbeOffsetsAndSize, SPtr<GpuBuffer>& gridProbeIndices) const
 	{
-		gridOffsetsAndSize = mGridLightOffsetAndSize;
+		gridLightOffsetsAndSize = mGridLightOffsetAndSize;
 		gridLightIndices = mGridLightIndices;
+		gridProbeOffsetsAndSize = mGridProbeOffsetAndSize;
+		gridProbeIndices = mGridProbeIndices;
 	}
 
 	LightGrid::LightGrid()
@@ -193,7 +242,8 @@ namespace bs { namespace ct
 		mGridParamBuffer = gLightGridParamDefDef.createBuffer();
 	}
 
-	void LightGrid::updateGrid(const RendererCamera& view, const GPULightData& lightData, bool noLighting)
+	void LightGrid::updateGrid(const RendererCamera& view, const GPULightData& lightData, const GPUReflProbeData& probeData,
+		bool noLighting)
 	{
 		UINT32 width = view.getRenderTargets()->getWidth();
 		UINT32 height = view.getRenderTargets()->getHeight();
@@ -220,26 +270,30 @@ namespace bs { namespace ct
 		UINT32 numCells = gridSize[0] * gridSize[1] * gridSize[2];
 
 		gLightGridParamDefDef.gLightOffsets.set(mGridParamBuffer, lightOffsets);
+		gLightGridParamDefDef.gNumReflProbes.set(mGridParamBuffer, probeData.getNumProbes());
 		gLightGridParamDefDef.gNumCells.set(mGridParamBuffer, numCells);
 		gLightGridParamDefDef.gGridSize.set(mGridParamBuffer, gridSize);
 		gLightGridParamDefDef.gMaxNumLightsPerCell.set(mGridParamBuffer, MAX_LIGHTS_PER_CELL);
 		gLightGridParamDefDef.gGridPixelSize.set(mGridParamBuffer, Vector2I(CELL_XY_SIZE, CELL_XY_SIZE));
 
-		mLLCreationMat.setParams(gridSize, mGridParamBuffer, lightData.getLightBuffer());
+		mLLCreationMat.setParams(gridSize, mGridParamBuffer, lightData.getLightBuffer(), probeData.getProbeBuffer());
 		mLLCreationMat.execute(view);
 
-		SPtr<GpuBuffer> linkedListHeads;
-		SPtr<GpuBuffer> linkedList;
-		mLLCreationMat.getOutputs(linkedListHeads, linkedList);
+		SPtr<GpuBuffer> lightLLHeads;
+		SPtr<GpuBuffer> lightLL;
+		SPtr<GpuBuffer> probeLLHeads;
+		SPtr<GpuBuffer> probeLL;
+		mLLCreationMat.getOutputs(lightLLHeads, lightLL, probeLLHeads, probeLL);
 
-		mLLReductionMat.setParams(gridSize, mGridParamBuffer, linkedListHeads, linkedList);
+		mLLReductionMat.setParams(gridSize, mGridParamBuffer, lightLLHeads, lightLL, probeLLHeads, probeLL);
 		mLLReductionMat.execute(view);
 	}
 
-	void LightGrid::getOutputs(SPtr<GpuBuffer>& gridOffsetsAndSize, SPtr<GpuBuffer>& gridLightIndices, 
-							   SPtr<GpuParamBlockBuffer>& gridParams) const
+	void LightGrid::getOutputs(SPtr<GpuBuffer>& gridLightOffsetsAndSize, SPtr<GpuBuffer>& gridLightIndices,
+		SPtr<GpuBuffer>& gridProbeOffsetsAndSize, SPtr<GpuBuffer>& gridProbeIndices, 
+		SPtr<GpuParamBlockBuffer>& gridParams) const
 	{
-		mLLReductionMat.getOutputs(gridOffsetsAndSize, gridLightIndices);
+		mLLReductionMat.getOutputs(gridLightOffsetsAndSize, gridLightIndices, gridProbeOffsetsAndSize, gridProbeIndices);
 		gridParams = mGridParamBuffer;
 	}
-}}
+}}

+ 7 - 2
Source/RenderBeast/Source/BsObjectRendering.cpp

@@ -63,12 +63,17 @@ namespace bs { namespace ct
 		if (gpuParams->hasBuffer(GPT_FRAGMENT_PROGRAM, "gLights"))
 			gpuParams->getBufferParam(GPT_FRAGMENT_PROGRAM, "gLights", element.lightsBufferParam);
 
-		if(gpuParams->hasBuffer(GPT_FRAGMENT_PROGRAM, "gGridOffsetsAndSize"))
-			gpuParams->getBufferParam(GPT_FRAGMENT_PROGRAM, "gGridOffsetsAndSize", element.gridOffsetsAndSizeParam);
+		if(gpuParams->hasBuffer(GPT_FRAGMENT_PROGRAM, "gGridLightOffsetsAndSize"))
+			gpuParams->getBufferParam(GPT_FRAGMENT_PROGRAM, "gGridLightOffsetsAndSize", element.gridLightOffsetsAndSizeParam);
 
 		if (gpuParams->hasBuffer(GPT_FRAGMENT_PROGRAM, "gGridLightIndices"))
 			gpuParams->getBufferParam(GPT_FRAGMENT_PROGRAM, "gGridLightIndices", element.gridLightIndicesParam);
 
+		if (gpuParams->hasBuffer(GPT_FRAGMENT_PROGRAM, "gGridProbeOffsetsAndSize"))
+			gpuParams->getBufferParam(GPT_FRAGMENT_PROGRAM, "gGridProbeOffsetsAndSize", element.gridProbeOffsetsAndSizeParam);
+
+		element.imageBasedParams.populate(element.params, GPT_FRAGMENT_PROGRAM, true, true);
+
 		const Map<String, SHADER_OBJECT_PARAM_DESC>& bufferDescs = shader->getBufferParams();
 		String boneMatricesParamName;
 

+ 39 - 10
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -948,19 +948,31 @@ namespace bs { namespace ct
 		perCameraBuffer->flushToGPU();
 
 		Matrix4 viewProj = viewInfo->getViewProjMatrix();
+		UINT32 numSamples = viewInfo->getNumSamples();
 
 		viewInfo->beginRendering(true);
 
 		// Prepare light grid required for transparent object rendering
-		mLightGrid->updateGrid(*viewInfo, *mGPULightData, viewInfo->renderWithNoLighting());
+		mLightGrid->updateGrid(*viewInfo, *mGPULightData, *mGPUReflProbeData, viewInfo->renderWithNoLighting());
 
 		SPtr<GpuParamBlockBuffer> gridParams;
-		SPtr<GpuBuffer> gridOffsetsAndSize, gridLightIndices;
-		mLightGrid->getOutputs(gridOffsetsAndSize, gridLightIndices, 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(*mGPUReflProbeData, mReflCubemapArrayTex, viewInfo->isRenderingReflections());
+		imageBasedLightingMat->setSky(mSkyboxFilteredReflections, mSkyboxIrradiance, mSkybox->getBrightness());
 
 		// Assign camera and per-call data to all relevant renderables
 		const VisibilityInfo& visibility = viewInfo->getVisibilityMasks();
 		UINT32 numRenderables = (UINT32)mRenderables.size();
+		SPtr<GpuParamBlockBuffer> reflParamBuffer = imageBasedLightingMat->getReflectionsParamBuffer();
+		SPtr<SamplerState> reflSamplerState = imageBasedLightingMat->getReflectionsSamplerState();
 		for (UINT32 i = 0; i < numRenderables; i++)
 		{
 			if (!visibility.renderables[i])
@@ -974,12 +986,35 @@ namespace bs { namespace ct
 				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.gridOffsetsAndSizeParam.set(gridOffsetsAndSize);
+				element.gridLightOffsetsAndSizeParam.set(gridLightOffsetsAndSize);
 				element.gridLightIndicesParam.set(gridLightIndices);
 				element.lightsBufferParam.set(mGPULightData->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(mGPUReflProbeData->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);
 			}
 		}
 
@@ -1033,7 +1068,6 @@ namespace bs { namespace ct
 		rapi.setRenderTarget(nullptr);
 
 		// Render light pass into light accumulation buffer
-		UINT32 numSamples = viewInfo->getNumSamples();
 		ITiledDeferredLightingMat* lightingMat = mTiledDeferredLightingMats->get(numSamples);
 
 		renderTargets->allocate(RTT_LightAccumulation);
@@ -1047,11 +1081,6 @@ namespace bs { namespace ct
 		// 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.
-		ITiledDeferredImageBasedLightingMat* imageBasedLightingMat =
-			mTileDeferredImageBasedLightingMats->get(numSamples, viewInfo->isRenderingReflections());
-
-		imageBasedLightingMat->setReflectionProbes(*mGPUReflProbeData, mReflCubemapArrayTex);
-		imageBasedLightingMat->setSky(mSkyboxFilteredReflections, mSkyboxIrradiance, mSkybox->getBrightness());
 		imageBasedLightingMat->execute(renderTargets, perCameraBuffer, mPreintegratedEnvBRDF);
 
 		renderTargets->release(RTT_LightAccumulation);