Explorar o código

Added shaders for projecting shadow maps

BearishSun %!s(int64=8) %!d(string=hai) anos
pai
achega
a5365395d8

+ 12 - 8
Data/Raw/Engine/DataList.json

@@ -132,17 +132,13 @@
             "Path": "ShadowDepthBase.bslinc",
             "UUID": "ff6f2a9d-6766-4f80-984b-c159a5fd3c5e"
         },
-        {
-            "Path": "ShadowFiltering.bslinc",
-            "UUID": "50cfc08b-4869-4373-9b7e-22de12c26b20"
-        },
-        {
-            "Path": "CubeShadowFiltering.bslinc",
-            "UUID": "f2b61e2a-20a7-4721-8808-76c1737251b4"
-        },
         {
             "Path": "DeferredLightCommon.bslinc",
             "UUID": "8ffd1df9-3de4-442d-adca-95e8766fa81a"
+        },
+        {
+            "Path": "ShadowProjectionCommon.bslinc",
+            "UUID": "36da8807-b201-482b-b320-96f5300d1751"
         }
     ],
     "Shaders": [
@@ -285,6 +281,14 @@
         {
             "Path": "DeferredPointLight.bsl",
             "UUID": "428d9fde-9838-4367-9857-57bd80c8f599"
+        },
+        {
+            "Path": "ShadowProject.bsl",
+            "UUID": "93667cf9-c699-4d92-ba20-6e2e912f76fa"
+        },
+        {
+            "Path": "ShadowProjectOmni.bsl",
+            "UUID": "50447773-98e9-410c-8f64-eacbb9622c52"
         }
     ],
     "Skin": [

+ 32 - 0
Data/Raw/Engine/Includes/PerCameraData.bslinc

@@ -70,6 +70,38 @@ Technique : base("PerCameraData") =
 			{
 				return -gNDCZToWorldZ.y + (gNDCZToWorldZ.x / viewZ);
 			}
+			
+			/** Converts position in NDC to UV coordinates mapped to the screen rectangle. */ 
+			float2 NDCToUV(float2 ndcPos)
+			{
+				return ndcPos.xy * gClipToUVScaleOffset.xy + gClipToUVScaleOffset.zw;
+			}
+			
+			/** Converts position in UV coordinates mapped to the screen, to screen coordinates in pixels. */
+			uint2 UVToScreen(float2 uv)
+			{
+				return (uint2)(uv * (float2)gViewportRectangle.zw - ((float2)gViewportRectangle.xy + 0.5f));
+			}
+			
+			/** Converts position in NDC to screen coordinates in pixels. */
+			uint2 NDCToScreen(float2 ndcPos)
+			{
+				float2 uv = NDCToUV(ndcPos);
+				return UVToScreen(uv);
+			}
+			
+			/** Converts position in NDC to world space. */
+			float3 NDCToWorld(float2 ndcPos, float depth)
+			{
+				// x, y are now in clip space, z, w are in view space
+				// We multiply them by a special inverse view-projection matrix, that had the projection entries that effect
+				// z, w eliminated (since they are already in view space)
+				// Note: Multiply by depth should be avoided if using ortographic projection
+				float4 mixedSpacePos = float4(ndcPos.xy * -depth, depth, 1);
+				float4 worldPosition4D = mul(gMatScreenToWorld, mixedSpacePos);
+				
+				return worldPosition4D.xyz / worldPosition4D.w;
+			}
 		};
 	};
 };

+ 46 - 0
Data/Raw/Engine/Includes/ShadowProjectionCommon.bslinc

@@ -0,0 +1,46 @@
+#include "$ENGINE$/PerCameraData.bslinc"
+
+Technique 
+  : base("ShadowProjectionCommon")
+  : inherits("PerCameraData") =
+{
+	Pass =
+	{
+		Common = 
+		{
+			struct VStoFS
+			{
+				float4 position : SV_POSITION;
+			};
+		};
+	
+		Vertex =
+		{
+			struct VertexInput
+			{
+				float3 position : POSITION;
+			};
+			
+			#if NEEDS_TRANSFORM
+			cbuffer VertParams
+			{
+				float4 gPositionAndScale;
+			};
+			#endif
+			
+			VStoFS main(VertexInput input)
+			{
+				VStoFS output;
+				
+				#if NEEDS_TRANSFORM
+					float3 worldPos = input.position.xyz * gPositionAndScale.w + gPositionAndScale.xyz;
+					output.position = mul(gMatViewProj, float4(worldPos, 1));
+				#else
+					output.position = float4(input.position, 1);
+				#endif
+			
+				return output;
+			}			
+		};
+	};
+};

+ 1 - 3
Data/Raw/Engine/Shaders/DeferredPointLight.bsl

@@ -86,9 +86,7 @@ Technique : inherits("DeferredLightCommon") =
 			float4 main(VStoFS input, uint sampleIdx : SV_SampleIndex) : SV_Target0
 			{
 				float2 ndcPos = input.screenPos.xy / input.screenPos.w;
-				float2 screenUV = ndcPos * gClipToUVScaleOffset.xy + gClipToUVScaleOffset.zw;
-
-				uint2 pixelPos = (uint2)(screenUV * (float2)gViewportRectangle.zw - ((float2)gViewportRectangle.xy + 0.5f));
+				uint2 pixelPos = NDCToScreen(ndcPos);
 				
 				#if MSAA_COUNT > 1
 				SurfaceData surfaceData = getGBufferData(pixelPos, sampleIdx);

+ 68 - 12
Data/Raw/Engine/Includes/ShadowFiltering.bslinc → Data/Raw/Engine/Shaders/ShadowProject.bsl

@@ -1,4 +1,9 @@
-Technique : base("ShadowFiltering") =
+#include "$ENGINE$/GBufferInput.bslinc"
+#include "$ENGINE$/ShadowProjectionCommon.bslinc"
+
+Technique
+ : inherits("GBufferInput")
+ : inherits("ShadowProjectionCommon") = 
 {
 	Pass =
 	{
@@ -9,9 +14,16 @@ Technique : base("ShadowFiltering") =
 		
 			cbuffer Params
 			{
+				// Transform a point in mixed space (xy - clip space, z - view space) to a point
+				// in shadow space
+				float4x4 gMixedToShadowSpace;
 				float2 gShadowMapSize;
 				float2 gShadowMapSizeInv;
-				float gSoftTransitionScale;				
+				float gSoftTransitionScale;
+				float gFadePercent;
+				
+				float gFadePlaneDepth;
+				float gInvFadePlaneRange;
 			};
 			
 			// Converts a set of shadow depths into occlusion values, where 1 means scene object is occluded and 0
@@ -19,13 +31,14 @@ Technique : base("ShadowFiltering") =
 			float4 getOcclusion(float4 shadowDepth, float sceneDepth)
 			{
 				// Offset the shadow a bit to reduce shadow acne and use scale for soft transitions.
-				return saturate((depthSamples - sceneDepth) * gSoftTransitionScale + 1);
+				// Visualization (Mathematica): Plot[1.0 - Clip[(500 - x)*0.5 + 1, {0, 1}], {x, 480, 520}]
+				return 1.0f - saturate((shadowDepth - sceneDepth) * gSoftTransitionScale + 1);
 			}
 			
 			// Takes UV coordinates as input and returns a location to sample from, and a fraction
 			// that can be used for bilinear interpolation between the samples. Returned sample
 			// center is always located on a border between texels, in UV space.
-			void getFilteringInfo(float2 uv, out float2 fraction)
+			float2 getFilteringInfo(float2 uv, out float2 fraction)
 			{
 				// UV to texel position
 				float2 texelXY = uv * gShadowMapSize;
@@ -52,7 +65,7 @@ Technique : base("ShadowFiltering") =
 				float2 sampleCenter = getFilteringInfo(uv, fraction);
 							
 				// Gather four samples. Samples are returned in counter-clockwise order, starting with lower left
-				float4 depthSamples = gShadowTex.GatherRed(gShadowSampler, samplerCenter);
+				float4 depthSamples = gShadowTex.GatherRed(gShadowSampler, sampleCenter);
 				
 				// Convert samples to occlusion
 				float4 occlusion = getOcclusion(depthSamples, sceneDepth);
@@ -69,10 +82,10 @@ Technique : base("ShadowFiltering") =
 								
 				// Gather 16 samples in four 2x2 gathers. Samples are returned in counter-clockwise order, starting with lower left.
 				// Gathers are performed in clockwise order, starting with top left block.
-				float4 topLeftSamples = gShadowTex.GatherRed(gShadowSampler, samplerCenter, int2(-1, -1));
-				float4 topRightSamples = gShadowTex.GatherRed(gShadowSampler, samplerCenter, int2(1, -1));
-				float4 botLeftSamples = gShadowTex.GatherRed(gShadowSampler, samplerCenter, int2(-1, 1));
-				float4 botRightSamples = gShadowTex.GatherRed(gShadowSampler, samplerCenter, int2(1, 1));
+				float4 topLeftSamples = gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(-1, -1));
+				float4 topRightSamples = gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(1, -1));
+				float4 botLeftSamples = gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(-1, 1));
+				float4 botRightSamples = gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(1, 1));
 				
 				// Convert samples to occlusion
 				float4 topLeftOcclusion = getOcclusion(topLeftSamples, sceneDepth);
@@ -145,9 +158,9 @@ Technique : base("ShadowFiltering") =
 				{
 					int y = -2 + i * 2;
 				
-					float4 left = getOcclusion(gShadowTex.GatherRed(gShadowSampler, samplerCenter, int2(-2, y)), sceneDepth);
-					float4 middle = getOcclusion(gShadowTex.GatherRed(gShadowSampler, samplerCenter, int2(0, y)), sceneDepth);
-					float4 right = getOcclusion(gShadowTex.GatherRed(gShadowSampler, samplerCenter, int2(2, y)), sceneDepth);
+					float4 left = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(-2, y)), sceneDepth);
+					float4 middle = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(0, y)), sceneDepth);
+					float4 right = getOcclusion(gShadowTex.GatherRed(gShadowSampler, sampleCenter, int2(2, y)), sceneDepth);
 					
 					rows[i] = accumulateRows6x2(fraction.x, left, middle, right);
 				}
@@ -161,6 +174,49 @@ Technique : base("ShadowFiltering") =
 				// Calc average occlusion using 5x5 area and return
 				return occlusionAccumulator * (1.0f / 25.0f);				
 			}
+
+			float4 main(VStoFS input, uint sampleIdx : SV_SampleIndex) : SV_Target0
+			{
+				// Get depth & calculate world position
+				#if MSAA_COUNT > 1
+				uint2 screenPos = NDCToScreen(input.position.xy);
+				float deviceZ = gDepthBufferTex.Load(screenPos, sampleIdx).r;
+				#else
+				float2 screenUV = NDCToUV(input.position.xy);				
+				float deviceZ = gDepthBufferTex.Sample(gDepthBufferSamp, screenUV).r;
+				#endif
+				
+				float depth = convertFromDeviceZ(deviceZ);
+				float4 mixedSpacePos = float4(input.position.xy * -depth, depth, 1);
+				
+				float4 shadowPosition = mul(gMixedToShadowSpace, mixedSpacePos); 
+				shadowPosition.xy /= shadowPosition.w;
+				
+				// Clamp depth range because pixels in the shadow map that haven't been rendered to will have a value of 1,
+				// and we want those to remain unshadowed.
+				float lightSpaceDepth = min(shadowPosition.z, 0.999999f);
+				
+				float occlusion = 0.0f;
+				#if SHADOW_QUALITY <= 1
+					occlusion = PCF1x1(shadowPosition.xy, lightSpaceDepth);
+				#elif SHADOW_QUALITY == 2
+					occlusion = PCF2x2(shadowPosition.xy, lightSpaceDepth);
+				#elif SHADOW_QUALITY == 3
+					occlusion = PCF4x4(shadowPosition.xy, lightSpaceDepth);
+				#else
+					occlusion = PCF6x6(shadowPosition.xy, lightSpaceDepth);
+				#endif
+				
+				float alpha = 1.0f;
+				#if FADE_PLANE
+					alpha = 1.0f - saturate((depth - gFadePlaneDepth) * gInvFadePlaneRange);
+				#endif
+
+				occlusion *= gFadePercent;
+				
+				// Encode to get better precision in the blacks, similar to gamma correction but cheaper to execute
+				return float4(sqrt(occlusion), 0.0f, 0.0f, alpha);
+			}
 		};
 	};
 };

+ 38 - 10
Data/Raw/Engine/Includes/CubeShadowFiltering.bslinc → Data/Raw/Engine/Shaders/ShadowProjectOmni.bsl

@@ -1,4 +1,9 @@
-Technique : base("CubeShadowFiltering")
+#include "$ENGINE$/GBufferInput.bslinc"
+#include "$ENGINE$/ShadowProjectionCommon.bslinc"
+
+Technique
+ : inherits("GBufferInput")
+ : inherits("ShadowProjectionCommon") = 
 {
 	Pass =
 	{
@@ -72,10 +77,14 @@ Technique : base("CubeShadowFiltering")
 			cbuffer Params
 			{
 				float4x4 gFaceVPMatrices[6];
+				float4 gLightPosAndRadius;
 				float gInvResolution;
+				float gFadePercent;
+				float gDepthBias;
 			};			
 			
-			float cubemapPCF(float3 worldPos, float3 lightPos, float lightRadius, float depthBias)
+			// Returns occlusion where 1 = fully shadowed, 0 = not shadowed
+			float cubemapPCF(float3 worldPos, float3 lightPos, float lightRadius)
 			{
 				float3 toLight = lightPos - worldPos;
 				float distToLight = length(toLight);
@@ -106,22 +115,20 @@ Technique : base("CubeShadowFiltering")
 					faceIdx = toLight.y > 0.0f ? 2 : 3;
 				
 				// Get position of the receiver in shadow space
-				float shadowPos = mul(gFaceVPMatrices[faceIdx], worldPos);
+				float4 shadowPos = mul(gFaceVPMatrices[faceIdx], worldPos);
 				
 				float receiverDepth = shadowPos.z / shadowPos.w;
-				float shadowBias = depthBias / shadowPos.w;
-				
-				// TODO: Sampler state must be greater or equal
+				float shadowBias = gDepthBias / shadowPos.w;
 				
 				float occlusion = 0.0f;
 				#if SHADOW_QUALITY <= 1
-					occlusion = gShadowCubeTex.SampleCmpLevelZero(gShadowCubeSampler, lightDir, receiverDepth + shadowBias);
+					//occlusion = gShadowCubeTex.SampleCmpLevelZero(gShadowCubeSampler, lightDir, receiverDepth - shadowBias);
 				#elif SHADOW_QUALITY == 2
 					[unroll]
 					for(int i = 0; i < 4; ++i)
 					{
 						float sampleDir = lightDir + side * discSamples4[i].x + up * discSamples4[i].y;
-						occlusion += gShadowCubeTex.SampleCmpLevelZero(gShadowCubeSampler, sampleDir, receiverDepth + shadowBias);
+						//occlusion += gShadowCubeTex.SampleCmpLevelZero(gShadowCubeSampler, sampleDir, receiverDepth - shadowBias);
 					}
 					
 					occlusion /= 4;
@@ -130,7 +137,7 @@ Technique : base("CubeShadowFiltering")
 					for(int i = 0; i < 12; ++i)
 					{
 						float sampleDir = lightDir + side * discSamples12[i].x + up * discSamples12[i].y;
-						occlusion += gShadowCubeTex.SampleCmpLevelZero(gShadowCubeSampler, sampleDir, receiverDepth + shadowBias);
+						//occlusion += gShadowCubeTex.SampleCmpLevelZero(gShadowCubeSampler, sampleDir, receiverDepth - shadowBias);
 					}
 					
 					occlusion /= 12;
@@ -139,7 +146,7 @@ Technique : base("CubeShadowFiltering")
 					for(int i = 0; i < 32; ++i)
 					{
 						float sampleDir = lightDir + side * discSamples32[i].x + up * discSamples32[i].y;
-						occlusion += gShadowCubeTex.SampleCmpLevelZero(gShadowCubeSampler, sampleDir, receiverDepth + shadowBias);
+						//occlusion += gShadowCubeTex.SampleCmpLevelZero(gShadowCubeSampler, sampleDir, receiverDepth - shadowBias);
 					}
 					
 					occlusion /= 32;
@@ -147,6 +154,27 @@ Technique : base("CubeShadowFiltering")
 				
 				return occlusion;
 			}
+			
+			float4 main(VStoFS input, uint sampleIdx : SV_SampleIndex) : SV_Target0
+			{
+				// Get depth & calculate world position
+				#if MSAA_COUNT > 1
+				uint2 screenPos = NDCToScreen(input.position.xy);
+				float deviceZ = gDepthBufferTex.Load(screenPos, sampleIdx).r;
+				#else
+				float2 screenUV = NDCToUV(input.position.xy);				
+				float deviceZ = gDepthBufferTex.Sample(gDepthBufferSamp, screenUV).r;
+				#endif
+				
+				float depth = convertFromDeviceZ(deviceZ);
+				float3 worldPos = NDCToWorld(input.position.xy, depth);
+			
+				float occlusion = cubemapPCF(worldPos, gLightPosAndRadius.xyz, gLightPosAndRadius.w);
+				occlusion *= gFadePercent;
+				
+				// Encode to get better precision in the blacks, similar to gamma correction but cheaper to execute
+				return sqrt(occlusion);
+			}
 		};
 	};
 };

+ 2 - 2
Source/BansheeUtility/Source/BsMatrix4.cpp

@@ -331,8 +331,8 @@ namespace bs
 	}
 
 	Matrix4 Matrix4::projectionPerspective(const Degree& horzFOV, float aspect, float near, float far)
-    {
-	    // Note: Duplicate code in Camera, bring it all here eventually
+	{
+		// Note: Duplicate code in Camera, bring it all here eventually
 		static constexpr float INFINITE_FAR_PLANE_ADJUST = 0.00001f;
 
 		Radian thetaX(horzFOV * 0.5f);

+ 67 - 0
Source/RenderBeast/Include/BsShadowRendering.h

@@ -10,6 +10,7 @@
 #include "BsRendererMaterial.h"
 #include "BsTextureAtlasLayout.h"
 #include "BsLight.h"
+#include "BsLightRendering.h"
 
 namespace bs { namespace ct
 {
@@ -90,6 +91,72 @@ namespace bs { namespace ct
 			const SPtr<GpuParamBlockBuffer>& shadowCubeMasks);
 	};
 
+	BS_PARAM_BLOCK_BEGIN(ShadowProjectParamsDef)
+		BS_PARAM_BLOCK_ENTRY(Matrix4, gMixedToShadowSpace)
+		BS_PARAM_BLOCK_ENTRY(Vector2, gShadowMapSize)
+		BS_PARAM_BLOCK_ENTRY(Vector2, gShadowMapSizeInv)
+		BS_PARAM_BLOCK_ENTRY(float, gSoftTransitionScale)
+		BS_PARAM_BLOCK_ENTRY(float, gFadePercent)
+		BS_PARAM_BLOCK_ENTRY(float, gFadePlaneDepth)
+		BS_PARAM_BLOCK_ENTRY(float, gInvFadePlaneRange)
+		BS_PARAM_BLOCK_END
+
+	extern ShadowProjectParamsDef gShadowProjectParamsDef;
+
+	/** Material used for projecting depth into a shadow accumulation buffer for non-omnidirectional shadow maps. */
+	template<int ShadowQuality, bool Directional, bool MSAA>
+	class ShadowProjectMat : public RendererMaterial<ShadowProjectMat<ShadowQuality, Directional, MSAA>>
+	{
+		RMAT_DEF("ShadowProject.bsl");
+
+	public:
+		ShadowProjectMat();
+
+		/** Binds the material to the pipeline, ready to be used on subsequent draw calls. */
+		void bind(const SPtr<Texture>& shadowMap, const SPtr<GpuParamBlockBuffer>& shadowParams, 
+			const SPtr<GpuParamBlockBuffer>& perCamera);
+
+	private:
+		SPtr<SamplerState> mSamplerState;
+
+		GBufferParams mGBufferParams;
+
+		GpuParamTexture mShadowMapParam;
+		GpuParamSampState mShadowSamplerParam;
+	};
+
+	BS_PARAM_BLOCK_BEGIN(ShadowProjectOmniParamsDef)
+		BS_PARAM_BLOCK_ENTRY_ARRAY(Matrix4, gFaceVPMatrices, 6)
+		BS_PARAM_BLOCK_ENTRY(Vector4, gLightPosAndRadius)
+		BS_PARAM_BLOCK_ENTRY(float, gInvResolution)
+		BS_PARAM_BLOCK_ENTRY(float, gFadePercent)
+		BS_PARAM_BLOCK_ENTRY(float, gDepthBias)
+		BS_PARAM_BLOCK_END
+
+	extern ShadowProjectOmniParamsDef gShadowProjectOmniParamsDef;
+
+	/** Material used for projecting depth into a shadow accumulation buffer for omnidirectional shadow maps. */
+	template<int ShadowQuality, bool MSAA>
+	class ShadowProjectOmniMat : public RendererMaterial<ShadowProjectOmniMat<ShadowQuality, MSAA>>
+	{
+		RMAT_DEF("ShadowProjectOmni.bsl");
+
+	public:
+		ShadowProjectOmniMat();
+
+		/** Binds the material to the pipeline, ready to be used on subsequent draw calls. */
+		void bind(const SPtr<Texture>& shadowMap, const SPtr<GpuParamBlockBuffer>& shadowParams,
+			const SPtr<GpuParamBlockBuffer>& perCamera);
+
+	private:
+		SPtr<SamplerState> mSamplerState;
+
+		GBufferParams mGBufferParams;
+
+		GpuParamTexture mShadowMapParam;
+		GpuParamSampState mShadowSamplerParam;
+	};
+
 	/** Information about a shadow cast from a single light. */
 	struct ShadowInfo
 	{

+ 20 - 16
Source/RenderBeast/Source/BsLightRendering.cpp

@@ -87,25 +87,25 @@ namespace bs { namespace ct
 
 		Matrix4 transform = Matrix4::TRS(internal->getPosition(), internal->getRotation(), Vector3::ONE);
 		gPerLightParamDef.gMatConeTransform.set(buffer, transform);
-	}
+	}
 
 	GBufferParams::GBufferParams(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet)
 	{
-		SPtr<GpuParams> params = paramsSet->getGpuParams();
-
-		auto& texParams = material->getShader()->getTextureParams();
-		for (auto& entry : texParams)
-		{
-			if (entry.second.rendererSemantic == RPS_GBufferA)
-				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferA);
-			else if (entry.second.rendererSemantic == RPS_GBufferB)
-				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferB);
-			else if (entry.second.rendererSemantic == RPS_GBufferC)
-				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferC);
-			else if (entry.second.rendererSemantic == RPS_GBufferDepth)
-				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferDepth);
-		}
-	}
+		SPtr<GpuParams> params = paramsSet->getGpuParams();
+
+		auto& texParams = material->getShader()->getTextureParams();
+		for (auto& entry : texParams)
+		{
+			if (entry.second.rendererSemantic == RPS_GBufferA)
+				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferA);
+			else if (entry.second.rendererSemantic == RPS_GBufferB)
+				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferB);
+			else if (entry.second.rendererSemantic == RPS_GBufferC)
+				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferC);
+			else if (entry.second.rendererSemantic == RPS_GBufferDepth)
+				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferDepth);
+		}
+	}
 
 	void GBufferParams::bind(const SPtr<RenderTargets>& renderTargets)
 	{
@@ -144,6 +144,8 @@ namespace bs { namespace ct
 	void DirectionalLightMat<MSAA>::setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight)
 	{
 		mParamsSet->setParamBlockBuffer("PerLight", perLight, true);
+		
+		gRendererUtility().setPassParams(mParamsSet);
 	}
 
 	template class DirectionalLightMat<true>;
@@ -181,6 +183,8 @@ namespace bs { namespace ct
 	void PointLightMat<MSAA, InsideGeometry>::setPerLightParams(const SPtr<GpuParamBlockBuffer>& perLight)
 	{
 		mParamsSet->setParamBlockBuffer("PerLight", perLight, true);
+		
+		gRendererUtility().setPassParams(mParamsSet);
 	}
 
 	template class PointLightMat<false, false>;

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

@@ -85,6 +85,153 @@ namespace bs { namespace ct
 		gRendererUtility().setPassParams(mParamsSet);
 	}
 
+	ShadowProjectParamsDef gShadowProjectParamsDef;
+
+	template<int ShadowQuality, bool Directional, bool MSAA>
+	ShadowProjectMat<ShadowQuality, Directional, MSAA>::ShadowProjectMat()
+		: mGBufferParams(mMaterial, mParamsSet)
+	{
+		SPtr<GpuParams> params = mParamsSet->getGpuParams();
+
+		params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gShadowTex", mShadowMapParam);
+		params->getSamplerStateParam(GPT_FRAGMENT_PROGRAM, "gShadowSampler", mShadowSamplerParam);
+
+		SAMPLER_STATE_DESC desc;
+		desc.minFilter = FO_POINT;
+		desc.magFilter = FO_POINT;
+		desc.mipFilter = FO_POINT;
+		desc.addressMode.u = TAM_CLAMP;
+		desc.addressMode.v = TAM_CLAMP;
+		desc.addressMode.w = TAM_CLAMP;
+
+		mSamplerState = SamplerState::create(desc);
+	}
+
+	template<int ShadowQuality, bool Directional, bool MSAA>
+	void ShadowProjectMat<ShadowQuality, Directional, MSAA>::_initDefines(ShaderDefines& defines)
+	{
+		switch(ShadowQuality)
+		{
+		default:
+		case 1:
+			defines.set("SHADOW_QUALITY", 1);
+			break;
+		case 2:
+			defines.set("SHADOW_QUALITY", 2);
+			break;
+		case 3:
+			defines.set("SHADOW_QUALITY", 3);
+			break;
+		case 4:
+			defines.set("SHADOW_QUALITY", 4);
+			break;
+		}
+
+		defines.set("FADE_PLANE", Directional ? 1 : 0);
+		defines.set("NEEDS_TRANSFORM", Directional ? 0 : 1);
+
+		defines.set("MSAA_COUNT", MSAA ? 2 : 1); // Actual count doesn't matter, as long as its >1 if enabled
+	}
+
+	template<int ShadowQuality, bool Directional, bool MSAA>
+	void ShadowProjectMat<ShadowQuality, Directional, MSAA>::bind(const SPtr<Texture>& shadowMap, 
+		const SPtr<GpuParamBlockBuffer>& shadowParams, const SPtr<GpuParamBlockBuffer>& perCameraParams)
+	{
+		mShadowMapParam.set(shadowMap);
+		mShadowSamplerParam.set(mSamplerState);
+
+		mParamsSet->setParamBlockBuffer("Params", shadowParams);
+		mParamsSet->setParamBlockBuffer("PerCamera", perCameraParams);
+
+		gRendererUtility().setPass(mMaterial);
+		gRendererUtility().setPassParams(mParamsSet);
+	}
+
+#define TEMPL_INSTANTIATE(QUALITY)								\
+	template class ShadowProjectMat<QUALITY, true, true>;		\
+	template class ShadowProjectMat<QUALITY, true, false>;		\
+	template class ShadowProjectMat<QUALITY, false, true>;		\
+	template class ShadowProjectMat<QUALITY, false, false>;
+	
+TEMPL_INSTANTIATE(0)
+TEMPL_INSTANTIATE(1)
+TEMPL_INSTANTIATE(2)
+TEMPL_INSTANTIATE(3)
+
+#undef TEMPL_INSTANTIATE
+
+	ShadowProjectOmniParamsDef gShadowProjectOmniParamsDef;
+
+	template<int ShadowQuality, bool MSAA>
+	ShadowProjectOmniMat<ShadowQuality, MSAA>::ShadowProjectOmniMat()
+		: mGBufferParams(mMaterial, mParamsSet)
+	{
+		SPtr<GpuParams> params = mParamsSet->getGpuParams();
+
+		params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gShadowCubeTex", mShadowMapParam);
+		params->getSamplerStateParam(GPT_FRAGMENT_PROGRAM, "gShadowCubeSampler", mShadowSamplerParam);
+
+		SAMPLER_STATE_DESC desc;
+		desc.minFilter = FO_LINEAR;
+		desc.magFilter = FO_LINEAR;
+		desc.mipFilter = FO_POINT;
+		desc.addressMode.u = TAM_CLAMP;
+		desc.addressMode.v = TAM_CLAMP;
+		desc.addressMode.w = TAM_CLAMP;
+		desc.comparisonFunc = CMPF_GREATER_EQUAL;
+
+		mSamplerState = SamplerState::create(desc);
+	}
+
+	template<int ShadowQuality, bool MSAA>
+	void ShadowProjectOmniMat<ShadowQuality, MSAA>::_initDefines(ShaderDefines& defines)
+	{
+		switch(ShadowQuality)
+		{
+		default:
+		case 1:
+			defines.set("SHADOW_QUALITY", 1);
+			break;
+		case 2:
+			defines.set("SHADOW_QUALITY", 2);
+			break;
+		case 3:
+			defines.set("SHADOW_QUALITY", 3);
+			break;
+		case 4:
+			defines.set("SHADOW_QUALITY", 4);
+			break;
+		}
+
+		defines.set("NEEDS_TRANSFORM", 1);
+		defines.set("MSAA_COUNT", MSAA ? 2 : 1); // Actual count doesn't matter, as long as its >1 if enabled
+	}
+
+	template<int ShadowQuality, bool MSAA>
+	void ShadowProjectOmniMat<ShadowQuality, MSAA>::bind(const SPtr<Texture>& shadowMap, 
+		const SPtr<GpuParamBlockBuffer>& shadowParams, const SPtr<GpuParamBlockBuffer>& perCameraParams)
+	{
+		mShadowMapParam.set(shadowMap);
+		mShadowSamplerParam.set(mSamplerState);
+
+		mParamsSet->setParamBlockBuffer("Params", shadowParams);
+		mParamsSet->setParamBlockBuffer("PerCamera", perCameraParams);
+
+		gRendererUtility().setPass(mMaterial);
+		gRendererUtility().setPassParams(mParamsSet);
+	}
+
+#define TEMPL_INSTANTIATE(QUALITY)								\
+	template class ShadowProjectOmniMat<QUALITY, true>;			\
+	template class ShadowProjectOmniMat<QUALITY, false>;		\
+	
+TEMPL_INSTANTIATE(0)
+TEMPL_INSTANTIATE(1)
+TEMPL_INSTANTIATE(2)
+TEMPL_INSTANTIATE(3)
+
+#undef TEMPL_INSTANTIATE
+
 	void ShadowInfo::updateNormArea(UINT32 atlasSize)
 	{
 		normArea.x = area.x / (float)atlasSize;