Procházet zdrojové kódy

Started work on shadow mapping

BearishSun před 8 roky
rodič
revize
ae757a15ef

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

@@ -127,6 +127,10 @@
         {
         {
             "Path": "GBufferOutput.bslinc",
             "Path": "GBufferOutput.bslinc",
             "UUID": "46df32e8-6400-46d5-9ac2-beefdc9016ad"
             "UUID": "46df32e8-6400-46d5-9ac2-beefdc9016ad"
+        },
+        {
+            "Path": "ShadowDepthBase.bslinc",
+            "UUID": "ff6f2a9d-6766-4f80-984b-c159a5fd3c5e"
         }
         }
     ],
     ],
     "Shaders": [
     "Shaders": [
@@ -249,6 +253,14 @@
         {
         {
             "Path": "TiledDeferredImageBasedLighting.bsl",
             "Path": "TiledDeferredImageBasedLighting.bsl",
             "UUID": "6029db14-107f-43df-9a33-7105c56aa0fd"
             "UUID": "6029db14-107f-43df-9a33-7105c56aa0fd"
+        },
+        {
+            "Path": "ShadowDepthCube.bsl",
+            "UUID": "285c7b78-053a-4763-899e-8e11b5d4dac7"
+        },
+        {
+            "Path": "ShadowDepthNormal.bsl",
+            "UUID": "c9b64475-375d-410e-8cd4-e1b1181318d4"
         }
         }
     ],
     ],
     "Skin": [
     "Skin": [

+ 21 - 0
Data/Raw/Engine/Includes/NormalVertexInput.bslinc

@@ -35,6 +35,16 @@ Technique
 				#endif				
 				#endif				
 			};
 			};
 			
 			
+			// Vertex input containing only position data
+			struct VertexInput_PO
+			{
+				float3 position : POSITION;
+				
+				#ifdef USE_BLEND_SHAPES
+					float3 deltaPosition : POSITION1;
+				#endif	
+			};
+			
 			struct VertexIntermediate
 			struct VertexIntermediate
 			{
 			{
 				float3 worldNormal; // Note: Half-precision could be used
 				float3 worldNormal; // Note: Half-precision could be used
@@ -90,6 +100,17 @@ Technique
 				return mul(gMatWorld, position);
 				return mul(gMatWorld, position);
 			}
 			}
 			
 			
+			float4 getVertexWorldPosition(VertexInput_PO input)
+			{
+				#ifdef USE_BLEND_SHAPES
+					float4 position = float4(input.position + input.deltaPosition, 1.0f);
+				#else
+					float4 position = float4(input.position, 1.0f);
+				#endif			
+			
+				return mul(gMatWorld, position);
+			}
+			
 			void populateVertexOutput(VertexInput input, VertexIntermediate intermediate, inout VStoFS result)
 			void populateVertexOutput(VertexInput input, VertexIntermediate intermediate, inout VStoFS result)
 			{
 			{
 				result.uv0 = input.uv0;
 				result.uv0 = input.uv0;

+ 114 - 0
Data/Raw/Engine/Includes/ShadowDepthBase.bslinc

@@ -0,0 +1,114 @@
+#include "$ENGINE$\GBufferOutput.bslinc"
+#include "$ENGINE$\PerCameraData.bslinc"
+#include "$ENGINE$\PerObjectData.bslinc"
+
+#include "$ENGINE$\SkinnedVertexInput.bslinc"
+#include "$ENGINE$\NormalVertexInput.bslinc"
+#define USE_BLEND_SHAPES
+#include "$ENGINE$\SkinnedVertexInput.bslinc"
+#include "$ENGINE$\NormalVertexInput.bslinc"
+#undef USE_BLEND_SHAPES
+
+Technique : base("ShadowDepthBase") =
+{
+	Pass =
+	{
+		Common =
+		{
+			struct ShadowVStoFS
+			{
+				float4 position : SV_Position;
+				
+				#ifdef USES_GS
+				float4 worldPos : TEXCOORD0;
+				#endif
+			};
+			
+			cbuffer ShadowParams
+			{
+				float gDepthBias;
+				float gDepthRange;
+			};
+		};
+	
+		Vertex =
+		{
+			void linearizeDepth(inout float4 clipPos)
+			{
+				// Clamp to near plane if behind it
+				if (clipPos.z < 0)
+				{
+					clipPos.z = 0.000001f;
+					clipPos.w = 1.0f;
+				}
+
+				// Output linear depth in range [0, 1]
+				// TODO - Handle case for backends using [-1, 1] depth range
+				float linearDepth = clipPos.z * gDepthRange + gDepthBias;
+				clipPos.z = linearDepth * clipPos.w;
+			}		
+		
+			ShadowVStoFS main(VertexInput_PO input)
+			{
+				ShadowVStoFS output;
+			
+				float4 worldPosition = getVertexWorldPosition(input);
+				
+				#ifdef USES_GS
+				output.worldPos = worldPosition;
+				output.position = worldPosition;
+				#else
+				float4 clipPos = mul(gMatViewProj, worldPosition);
+				linearizeDepth(clipPos);
+				
+				output.position = clipPos;
+				#endif
+				
+				return output;
+			}
+		};
+	};
+};
+
+Technique 
+ : inherits("GBufferOutput")
+ : inherits("PerCameraData")
+ : inherits("PerObjectData")
+ : inherits("NormalVertexInput")
+ : inherits("ShadowDepthBase")
+ : inherits("ShadowDepth") =
+{
+};
+
+Technique 
+ : inherits("GBufferOutput")
+ : inherits("PerCameraData")
+ : inherits("PerObjectData")
+ : inherits("SkinnedVertexInput")
+ : inherits("ShadowDepthBase")
+ : inherits("ShadowDepth") =
+{
+	Tags = { "Skinned" };
+};
+
+Technique 
+ : inherits("GBufferOutput")
+ : inherits("PerCameraData")
+ : inherits("PerObjectData")
+ : inherits("MorphVertexInput")
+ : inherits("ShadowDepthBase")
+ : inherits("ShadowDepth") =
+{
+	Tags = { "Morph" };
+};
+
+Technique 
+ : inherits("GBufferOutput")
+ : inherits("PerCameraData")
+ : inherits("PerObjectData")
+ : inherits("SkinnedMorphVertexInput")
+ : inherits("ShadowDepthBase")
+ : inherits("ShadowDepth") =
+{
+	Tags = { "SkinnedMorph" };
+};

+ 31 - 6
Data/Raw/Engine/Includes/SkinnedVertexInput.bslinc

@@ -44,6 +44,18 @@ Technique
 				#endif
 				#endif
 			};
 			};
 			
 			
+			// Vertex input containing only position data
+			struct VertexInput_PO
+			{
+				float3 position : POSITION;
+				uint4 blendIndices : BLENDINDICES;
+				float4 blendWeights : BLENDWEIGHT;
+				
+				#ifdef USE_BLEND_SHAPES
+					float3 deltaPosition : POSITION1;
+				#endif
+			};
+			
 			struct VertexIntermediate
 			struct VertexIntermediate
 			{
 			{
 				float3x4 blendMatrix;
 				float3x4 blendMatrix;
@@ -61,12 +73,12 @@ Technique
 				return float3x4(row0, row1, row2);
 				return float3x4(row0, row1, row2);
 			}
 			}
 			
 			
-			float3x4 getBlendMatrix(VertexInput input)
+			float3x4 getBlendMatrix(float4 blendWeights, uint4 blendIndices)
 			{
 			{
-				float3x4 result = input.blendWeights.x * getBoneMatrix(input.blendIndices.x);
-				result += input.blendWeights.y * getBoneMatrix(input.blendIndices.y);
-				result += input.blendWeights.z * getBoneMatrix(input.blendIndices.z);
-				result += input.blendWeights.w * getBoneMatrix(input.blendIndices.w);
+				float3x4 result = blendWeights.x * getBoneMatrix(blendIndices.x);
+				result += blendWeights.y * getBoneMatrix(blendIndices.y);
+				result += blendWeights.z * getBoneMatrix(blendIndices.z);
+				result += blendWeights.w * getBoneMatrix(blendIndices.w);
 				
 				
 				return result;
 				return result;
 			}
 			}
@@ -100,7 +112,7 @@ Technique
 			{
 			{
 				VertexIntermediate result;
 				VertexIntermediate result;
 				
 				
-				result.blendMatrix = getBlendMatrix(input);
+				result.blendMatrix = getBlendMatrix(input.blendWeights, input.blendIndices);
 				
 				
 				float tangentSign;
 				float tangentSign;
 				float3x3 tangentToLocal = getSkinnedTangentToLocal(input, result.blendMatrix, tangentSign);
 				float3x3 tangentToLocal = getSkinnedTangentToLocal(input, result.blendMatrix, tangentSign);
@@ -125,6 +137,19 @@ Technique
 				return mul(gMatWorld, position);
 				return mul(gMatWorld, position);
 			}
 			}
 			
 			
+			float4 getVertexWorldPosition(VertexInput_PO input)
+			{
+				#ifdef USE_BLEND_SHAPES
+					float4 position = float4(input.position + input.deltaPosition, 1.0f);
+				#else
+					float4 position = float4(input.position, 1.0f);
+				#endif
+			
+				float3x4 blendMatrix = getBlendMatrix(input.blendWeights, input.blendIndices);
+				position = float4(mul(blendMatrix, position), 1.0f);
+				return mul(gMatWorld, position);
+			}
+			
 			void populateVertexOutput(VertexInput input, VertexIntermediate intermediate, inout VStoFS result)
 			void populateVertexOutput(VertexInput input, VertexIntermediate intermediate, inout VStoFS result)
 			{
 			{
 				result.uv0 = input.uv0;
 				result.uv0 = input.uv0;

+ 65 - 0
Data/Raw/Engine/Shaders/ShadowDepthCube.bsl

@@ -0,0 +1,65 @@
+#define USES_GS
+#include "$ENGINE$\ShadowDepthBase.bslinc"
+
+Technique : base("ShadowDepth") =
+{ 
+	Pass =
+	{
+		Geometry =
+		{
+			struct GSToPS
+			{
+				float4 position : SV_Position;
+				uint targetIdx : SV_RenderTargetArrayIndex;
+			};
+
+			cbuffer ShadowCubeParams
+			{
+				float4x4 gFaceVPMatrices[6];
+				uint gFaceMasks[6];
+				uint padding[2];
+			};
+			
+			[maxvertexcount(18)]
+			void main(triangle ShadowVStoFS inputs[3], inout TriangleStream<GSToPS> outStream)
+			{
+				// Output a triangle to all relevant faces
+				[unroll]
+				for (int faceIdx = 0; faceIdx < 6; faceIdx++)
+				{
+					// Check the per-object masks that were determined based on CPU frustum culling
+					[branch]
+					if (gFaceMasks[faceIdx] > 0)
+					{
+						float4 clipPos[3];
+						
+						[unroll]
+						for (int vertIdx = 0; vertIdx < 3; vertIdx++)
+							clipPos[vertIdx] = mul(gFaceVPMatrices[faceIdx], inputs[vertIdx].worldPos);
+
+						// Per-triangle frustum culling
+						// Note: Test if this helps or hurts performance
+						float4 testMask = saturate(clipPos[0].xyxy * float4(-1, -1, 1, 1) - clipPos[0].w);
+						testMask *= saturate(clipPos[1].xyxy * float4(-1, -1, 1, 1) - clipPos[1].w);
+						testMask *= saturate(clipPos[2].xyxy * float4(-1, -1, 1, 1) - clipPos[2].w);
+
+						[branch]	
+						if (all(testMask == 0))
+						{				
+							GSToPS output;
+							output.targetIdx = faceIdx;
+
+							[unroll]
+							for (int vertIdx = 0; vertIdx < 3; vertIdx++)
+							{
+								output.position = clipPos[vertIdx];
+								outStream.Append(output);
+							}
+							outStream.RestartStrip();
+						}
+					}
+				}
+			}
+		};
+	};
+};

+ 4 - 0
Data/Raw/Engine/Shaders/ShadowDepthNormal.bsl

@@ -0,0 +1,4 @@
+#include "$ENGINE$\ShadowDepthBase.bslinc"
+
+Technique : base("ShadowDepth") =
+{ };

+ 0 - 7
Source/BansheeCore/Include/BsCamera.h

@@ -29,13 +29,6 @@ namespace bs
 		PostProcess = 1<<2
 		PostProcess = 1<<2
 	};
 	};
 
 
-	/**	Projection type to use by the camera. */
-    enum ProjectionType
-    {
-		PT_ORTHOGRAPHIC, /**< Projection type where object size remains constant and parallel lines remain parallel. */
-		PT_PERSPECTIVE /**< Projection type that emulates human vision. Objects farther away appear smaller. */
-    };
-
 	/**	Flags that describe a camera. */
 	/**	Flags that describe a camera. */
 	enum class CameraFlag
 	enum class CameraFlag
 	{
 	{

+ 7 - 0
Source/BansheeCore/Include/BsCommonTypes.h

@@ -344,6 +344,13 @@ namespace bs
 		TEX_TYPE_CUBE_MAP	BS_SCRIPT_EXPORT(n:TextureCube) = 4 
 		TEX_TYPE_CUBE_MAP	BS_SCRIPT_EXPORT(n:TextureCube) = 4 
 	};
 	};
 
 
+	/**	Projection type to use by the camera. */
+	enum ProjectionType
+	{
+		PT_ORTHOGRAPHIC, /**< Projection type where object size remains constant and parallel lines remain parallel. */
+		PT_PERSPECTIVE /**< Projection type that emulates human vision. Objects farther away appear smaller. */
+	};
+
 	/**	Contains data about a type used for GPU data parameters. */
 	/**	Contains data about a type used for GPU data parameters. */
 	struct GpuParamDataTypeInfo
 	struct GpuParamDataTypeInfo
 	{
 	{

+ 12 - 1
Source/BansheeUtility/Include/BsConvexVolume.h

@@ -11,6 +11,17 @@ namespace bs
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
+	/**	Clip planes that form the camera frustum (visible area). */
+	enum FrustumPlane
+	{
+		FRUSTUM_PLANE_NEAR = 0,
+		FRUSTUM_PLANE_FAR = 1,
+		FRUSTUM_PLANE_LEFT = 2,
+		FRUSTUM_PLANE_RIGHT = 3,
+		FRUSTUM_PLANE_TOP = 4,
+		FRUSTUM_PLANE_BOTTOM = 5
+	};
+
 	/** Represents a convex volume defined by planes representing the volume border. */
 	/** Represents a convex volume defined by planes representing the volume border. */
 	class BS_UTILITY_EXPORT ConvexVolume
 	class BS_UTILITY_EXPORT ConvexVolume
 	{
 	{
@@ -19,7 +30,7 @@ namespace bs
 		ConvexVolume(const Vector<Plane>& planes);
 		ConvexVolume(const Vector<Plane>& planes);
 
 
 		/** Creates frustum planes from the provided projection matrix. */
 		/** Creates frustum planes from the provided projection matrix. */
-		ConvexVolume(const Matrix4& projectionMatrix);
+		ConvexVolume(const Matrix4& projectionMatrix, bool useNearPlane = true);
 
 
 		/**
 		/**
 		 * Checks does the volume intersects the provided axis aligned box.
 		 * Checks does the volume intersects the provided axis aligned box.

+ 17 - 13
Source/BansheeUtility/Include/BsMatrix4.h

@@ -97,22 +97,23 @@ namespace bs
 		}
 		}
 
 
 		/** Returns a row of the matrix. */
 		/** Returns a row of the matrix. */
-		float* operator[] (UINT32 row)
-        {
-            assert(row < 4);
+		Vector4& operator[] (UINT32 row)
+		{
+			assert(row < 4);
 
 
-            return m[row];
-        }
+			return *(Vector4*)m[row];
+		}
 
 
-        const float *operator[] (UINT32 row) const
-        {
-            assert(row < 4);
+		/** Returns a row of the matrix. */
+		const Vector4& operator[] (UINT32 row) const
+		{
+			assert(row < 4);
 
 
-            return m[row];
-        }
+			return *(Vector4*)m[row];
+		}
 
 
-        Matrix4 operator* (const Matrix4 &rhs) const
-        {
+		Matrix4 operator* (const Matrix4 &rhs) const
+		{
 			Matrix4 r;
 			Matrix4 r;
 
 
 			r.m[0][0] = m[0][0] * rhs.m[0][0] + m[0][1] * rhs.m[1][0] + m[0][2] * rhs.m[2][0] + m[0][3] * rhs.m[3][0];
 			r.m[0][0] = m[0][0] * rhs.m[0][0] + m[0][1] * rhs.m[1][0] + m[0][2] * rhs.m[2][0] + m[0][3] * rhs.m[3][0];
@@ -456,7 +457,10 @@ namespace bs
 		/** Creates a 4x4 perspective projection matrix. */
 		/** Creates a 4x4 perspective projection matrix. */
 		static Matrix4 projectionPerspective(const Degree& horzFOV, float aspect, float near, float far);
 		static Matrix4 projectionPerspective(const Degree& horzFOV, float aspect, float near, float far);
 
 
-		/** Creates a view matrix and applies optional reflection. */
+		/** Creates a 4x4 ortographic projection matrix. */
+		static Matrix4 projectionOrthographic(float left, float right, float top, float bottom, float near, float far);
+
+		/** Creates a view matrix. */
 		static Matrix4 view(const Vector3& position, const Quaternion& orientation);
 		static Matrix4 view(const Vector3& position, const Quaternion& orientation);
 
 
         /**
         /**

+ 70 - 44
Source/BansheeUtility/Source/BsConvexVolume.cpp

@@ -8,58 +8,84 @@
 
 
 namespace bs
 namespace bs
 {
 {
-	/**	Clip planes that form the camera frustum (visible area). */
-	enum FrustumPlane
-	{
-		FRUSTUM_PLANE_NEAR = 0,
-		FRUSTUM_PLANE_FAR = 1,
-		FRUSTUM_PLANE_LEFT = 2,
-		FRUSTUM_PLANE_RIGHT = 3,
-		FRUSTUM_PLANE_TOP = 4,
-		FRUSTUM_PLANE_BOTTOM = 5
-	};
-
 	ConvexVolume::ConvexVolume(const Vector<Plane>& planes)
 	ConvexVolume::ConvexVolume(const Vector<Plane>& planes)
 		:mPlanes(planes)
 		:mPlanes(planes)
 	{ }
 	{ }
 
 
-	ConvexVolume::ConvexVolume(const Matrix4& projectionMatrix)
+	ConvexVolume::ConvexVolume(const Matrix4& projectionMatrix, bool useNearPlane)
 	{
 	{
-		mPlanes.resize(6);
+		mPlanes.reserve(6);
 
 
 		const Matrix4& proj = projectionMatrix;
 		const Matrix4& proj = projectionMatrix;
 
 
-		mPlanes[FRUSTUM_PLANE_LEFT].normal.x = proj[3][0] + proj[0][0];
-		mPlanes[FRUSTUM_PLANE_LEFT].normal.y = proj[3][1] + proj[0][1];
-		mPlanes[FRUSTUM_PLANE_LEFT].normal.z = proj[3][2] + proj[0][2];
-		mPlanes[FRUSTUM_PLANE_LEFT].d = proj[3][3] + proj[0][3];
-
-		mPlanes[FRUSTUM_PLANE_RIGHT].normal.x = proj[3][0] - proj[0][0];
-		mPlanes[FRUSTUM_PLANE_RIGHT].normal.y = proj[3][1] - proj[0][1];
-		mPlanes[FRUSTUM_PLANE_RIGHT].normal.z = proj[3][2] - proj[0][2];
-		mPlanes[FRUSTUM_PLANE_RIGHT].d = proj[3][3] - proj[0][3];
-
-		mPlanes[FRUSTUM_PLANE_TOP].normal.x = proj[3][0] - proj[1][0];
-		mPlanes[FRUSTUM_PLANE_TOP].normal.y = proj[3][1] - proj[1][1];
-		mPlanes[FRUSTUM_PLANE_TOP].normal.z = proj[3][2] - proj[1][2];
-		mPlanes[FRUSTUM_PLANE_TOP].d = proj[3][3] - proj[1][3];
-
-		mPlanes[FRUSTUM_PLANE_BOTTOM].normal.x = proj[3][0] + proj[1][0];
-		mPlanes[FRUSTUM_PLANE_BOTTOM].normal.y = proj[3][1] + proj[1][1];
-		mPlanes[FRUSTUM_PLANE_BOTTOM].normal.z = proj[3][2] + proj[1][2];
-		mPlanes[FRUSTUM_PLANE_BOTTOM].d = proj[3][3] + proj[1][3];
-
-		mPlanes[FRUSTUM_PLANE_NEAR].normal.x = proj[3][0] + proj[2][0];
-		mPlanes[FRUSTUM_PLANE_NEAR].normal.y = proj[3][1] + proj[2][1];
-		mPlanes[FRUSTUM_PLANE_NEAR].normal.z = proj[3][2] + proj[2][2];
-		mPlanes[FRUSTUM_PLANE_NEAR].d = proj[3][3] + proj[2][3];
-
-		mPlanes[FRUSTUM_PLANE_FAR].normal.x = proj[3][0] - proj[2][0];
-		mPlanes[FRUSTUM_PLANE_FAR].normal.y = proj[3][1] - proj[2][1];
-		mPlanes[FRUSTUM_PLANE_FAR].normal.z = proj[3][2] - proj[2][2];
-		mPlanes[FRUSTUM_PLANE_FAR].d = proj[3][3] - proj[2][3];
-
-		for (UINT32 i = 0; i < 6; i++)
+		// Left
+		{
+			Plane plane;
+			plane.normal.x = proj[3][0] + proj[0][0];
+			plane.normal.y = proj[3][1] + proj[0][1];
+			plane.normal.z = proj[3][2] + proj[0][2];
+			plane.d = proj[3][3] + proj[0][3];
+
+			mPlanes.push_back(plane);
+		}
+
+		// Right
+		{
+			Plane plane;
+			plane.normal.x = proj[3][0] - proj[0][0];
+			plane.normal.y = proj[3][1] - proj[0][1];
+			plane.normal.z = proj[3][2] - proj[0][2];
+			plane.d = proj[3][3] - proj[0][3];
+
+			mPlanes.push_back(plane);
+		}
+
+		// Top
+		{
+			Plane plane;
+			plane.normal.x = proj[3][0] - proj[1][0];
+			plane.normal.y = proj[3][1] - proj[1][1];
+			plane.normal.z = proj[3][2] - proj[1][2];
+			plane.d = proj[3][3] - proj[1][3];
+
+			mPlanes.push_back(plane);
+		}
+
+		// Bottom
+		{
+			Plane plane;
+			plane.normal.x = proj[3][0] + proj[1][0];
+			plane.normal.y = proj[3][1] + proj[1][1];
+			plane.normal.z = proj[3][2] + proj[1][2];
+			plane.d = proj[3][3] + proj[1][3];
+
+			mPlanes.push_back(plane);
+		}
+
+		// Near
+		if(useNearPlane)
+		{
+			Plane plane;
+			plane.normal.x = proj[3][0] + proj[2][0];
+			plane.normal.y = proj[3][1] + proj[2][1];
+			plane.normal.z = proj[3][2] + proj[2][2];
+			plane.d = proj[3][3] + proj[2][3];
+
+			mPlanes.push_back(plane);
+		}
+
+		// Far
+		{
+			Plane plane;
+			plane.normal.x = proj[3][0] - proj[2][0];
+			plane.normal.y = proj[3][1] - proj[2][1];
+			plane.normal.z = proj[3][2] - proj[2][2];
+			plane.d = proj[3][3] - proj[2][3];
+
+			mPlanes.push_back(plane);
+		}
+
+		for (UINT32 i = 0; i < (UINT32)mPlanes.size(); i++)
 		{
 		{
 			float length = mPlanes[i].normal.normalize();
 			float length = mPlanes[i].normal.normalize();
 			mPlanes[i].d /= -length;
 			mPlanes[i].d /= -length;

+ 11 - 3
Source/BansheeUtility/Source/BsMatrix4.cpp

@@ -376,15 +376,23 @@ namespace bs
 		mat[3][0] = 0.0f;	mat[3][1] = 0.0f;	mat[3][2] = -1;	mat[3][3] = 0.0f;
 		mat[3][0] = 0.0f;	mat[3][1] = 0.0f;	mat[3][2] = -1;	mat[3][3] = 0.0f;
 
 
 		return mat;
 		return mat;
-    }
+	}
+
+	Matrix4 Matrix4::projectionOrthographic(float left, float right, float top, float bottom, float near, float far)
+	{
+		Matrix4 output;
+		output.makeProjectionOrtho(left, right, top, bottom, near, far);
+
+		return output;
+	}
 
 
 	Matrix4 Matrix4::view(const Vector3& position, const Quaternion& orientation)
 	Matrix4 Matrix4::view(const Vector3& position, const Quaternion& orientation)
-    {
+	{
 		Matrix4 mat;
 		Matrix4 mat;
 		mat.makeView(position, orientation);
 		mat.makeView(position, orientation);
 
 
 		return mat;
 		return mat;
-    }
+	}
 
 
 	Matrix4 Matrix4::TRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale)
 	Matrix4 Matrix4::TRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale)
 	{
 	{

+ 2 - 0
Source/RenderBeast/CMakeSources.cmake

@@ -13,6 +13,7 @@ set(BS_RENDERBEAST_INC_NOFILTER
 	"Include/BsRendererObject.h"
 	"Include/BsRendererObject.h"
 	"Include/BsLightGrid.h"
 	"Include/BsLightGrid.h"
 	"Include/BsImageBasedLighting.h"
 	"Include/BsImageBasedLighting.h"
+	"Include/BsShadowRendering.h"
 )
 )
 
 
 set(BS_RENDERBEAST_SRC_NOFILTER
 set(BS_RENDERBEAST_SRC_NOFILTER
@@ -29,6 +30,7 @@ set(BS_RENDERBEAST_SRC_NOFILTER
 	"Source/BsRendererObject.cpp"
 	"Source/BsRendererObject.cpp"
 	"Source/BsLightGrid.cpp"
 	"Source/BsLightGrid.cpp"
 	"Source/BsImageBasedLighting.cpp"
 	"Source/BsImageBasedLighting.cpp"
+	"Source/BsShadowRendering.cpp"
 )
 )
 
 
 source_group("Header Files" FILES ${BS_RENDERBEAST_INC_NOFILTER})
 source_group("Header Files" FILES ${BS_RENDERBEAST_INC_NOFILTER})

+ 52 - 66
Source/RenderBeast/Include/BsRendererCamera.h

@@ -60,8 +60,31 @@ namespace bs { namespace ct
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 	};
 	};
 
 
-	/** Set of properties describing the output render target used by a renderer view. */
-	struct RENDERER_VIEW_TARGET_DESC
+	/** Data shared between RENDERER_VIEW_DESC and RendererViewProperties */
+	struct RendererViewData
+	{
+		Matrix4 viewTransform;
+		Matrix4 projTransform;
+		Vector3 viewDirection;
+		Vector3 viewOrigin;
+		bool flipView;
+		float nearPlane;
+		float farPlane;
+		ProjectionType projType;
+
+		bool isOverlay : 1;
+		bool isHDR : 1;
+		bool noLighting : 1;
+		bool triggerCallbacks : 1;
+		bool runPostProcessing : 1;
+		bool renderingReflections : 1;
+
+		UINT64 visibleLayers;
+		ConvexVolume cullFrustum;
+	};
+
+	/** Data shared between RENDERER_VIEW_TARGET_DESC and RendererViewTargetProperties */
+	struct RendererViewTargetData
 	{
 	{
 		SPtr<RenderTarget> target;
 		SPtr<RenderTarget> target;
 
 
@@ -77,32 +100,35 @@ namespace bs { namespace ct
 		UINT16 clearStencilValue;
 		UINT16 clearStencilValue;
 	};
 	};
 
 
+	/** Set of properties describing the output render target used by a renderer view. */
+	struct RENDERER_VIEW_TARGET_DESC : RendererViewTargetData
+	{ };
+
 	/** Set of properties used describing a specific view that the renderer can render. */
 	/** Set of properties used describing a specific view that the renderer can render. */
-	struct RENDERER_VIEW_DESC
+	struct RENDERER_VIEW_DESC : RendererViewData
 	{
 	{
 		RENDERER_VIEW_TARGET_DESC target;
 		RENDERER_VIEW_TARGET_DESC target;
 
 
-		Matrix4 viewTransform;
-		Matrix4 projTransform;
-		Vector3 viewDirection;
-		Vector3 viewOrigin;
-		bool flipView;
-		float nearPlane;
-		float farPlane;
+		StateReduction stateReduction;
+		const Camera* sceneCamera;
+	};
 
 
-		bool isOverlay : 1;
-		bool isHDR : 1;
-		bool noLighting : 1;
-		bool triggerCallbacks : 1;
-		bool runPostProcessing : 1;
-		bool renderingReflections : 1;
+	/** Set of properties used describing a specific view that the renderer can render. */
+	struct RendererViewProperties : RendererViewData
+	{
+		RendererViewProperties() {}
+		RendererViewProperties(const RENDERER_VIEW_DESC& src);
 
 
-		UINT64 visibleLayers;
-		ConvexVolume cullFrustum;
+		Matrix4 viewProjTransform;
 
 
-		StateReduction stateReduction;
+		SPtr<RenderTarget> target;
+		Rect2 nrmViewRect;
+		UINT32 numSamples;
 
 
-		const Camera* sceneCamera;
+		UINT32 clearFlags;
+		Color clearColor;
+		float clearDepthValue;
+		UINT16 clearStencilValue;
 	};
 	};
 
 
 	/** Information whether certain scene objects are visible in a view, per object type. */
 	/** Information whether certain scene objects are visible in a view, per object type. */
@@ -142,53 +168,11 @@ namespace bs { namespace ct
 		/** Updates all internal information with new view information. */
 		/** Updates all internal information with new view information. */
 		void setView(const RENDERER_VIEW_DESC& desc);
 		void setView(const RENDERER_VIEW_DESC& desc);
 
 
-		/** Returns the world position of the view. */
-		Vector3 getViewOrigin() const { return mViewDesc.viewOrigin; }
-
-		/** Returns a matrix that contains combined projection and view transforms. */
-		Matrix4 getViewProjMatrix() const { return mViewDesc.projTransform * mViewDesc.viewTransform; }
-
-		/** Returns the distance to the near clipping plane. */
-		float getNearPlane() const { return mViewDesc.nearPlane; }
-
-		/** Returns the distance to the far clipping plane. */
-		float getFarPlane() const { return mViewDesc.farPlane; }
-
-		/** Returns true if the view requires high dynamic range rendering. */
-		bool isHDR() const { return mViewDesc.isHDR; }
-
-		/** Returns true if this view only renders overlay, and not scene objects. */
-		bool isOverlay() const { return mViewDesc.isOverlay; }
-
-		/** Returns true if the view should be rendered with no lighting. */
-		bool renderWithNoLighting() const { return mViewDesc.noLighting; }
-
-		/** Returns the final render target the rendered contents should be output to. */
-		SPtr<RenderTarget> getFinalTarget() const { return mViewDesc.target.target; }
-
-		/** Returns normalized coordinates of the viewport area this view renders to. */
-		Rect2 getViewportRect() const { return mViewDesc.target.nrmViewRect; }
-
-		/** Returns true if the resulting render target should be flipped vertically. */
-		bool getFlipView() const { return mViewDesc.flipView; }
-
-		/** Returns the color to clear the non-rendered areas of the scene color target to. */
-		Color getClearColor() const { return mViewDesc.target.clearColor; }
-
-		/** Returns the number of samples per pixel to render. */
-		UINT32 getNumSamples() const { return mViewDesc.target.numSamples; }
-
-		/** Returns true if the current view is being used to render reflection probes. */
-		bool isRenderingReflections() const { return mViewDesc.renderingReflections; }
+		/** Returns a structure describing the view. */
+		const RendererViewProperties& getProperties() const { return mProperties; }
 
 
 		/** Returns the scene camera this object is based of. This can be null for manually constructed renderer cameras. */
 		/** Returns the scene camera this object is based of. This can be null for manually constructed renderer cameras. */
-		const Camera* getSceneCamera() const { return mViewDesc.sceneCamera; }
-
-		/** Returns true if external render callbacks should trigger for this view. */
-		bool checkTriggerCallbacks() const { return mViewDesc.triggerCallbacks; }
-
-		/** Returns true if post-processing effects should be triggered for this view. */
-		bool checkRunPostProcessing() const { return mViewDesc.runPostProcessing; }
+		const Camera* getSceneCamera() const { return mCamera; }
 
 
 		/** 
 		/** 
 		 * Prepares render targets for rendering. When done call endRendering().
 		 * Prepares render targets for rendering. When done call endRendering().
@@ -281,7 +265,9 @@ namespace bs { namespace ct
 		 */
 		 */
 		Vector2 getNDCZTransform(const Matrix4& projMatrix) const;
 		Vector2 getNDCZTransform(const Matrix4& projMatrix) const;
 
 
-		RENDERER_VIEW_DESC mViewDesc;
+		RendererViewProperties mProperties;
+		RENDERER_VIEW_TARGET_DESC mTargetDesc;
+		const Camera* mCamera;
 
 
 		SPtr<RenderQueue> mOpaqueQueue;
 		SPtr<RenderQueue> mOpaqueQueue;
 		SPtr<RenderQueue> mTransparentQueue;
 		SPtr<RenderQueue> mTransparentQueue;

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

@@ -0,0 +1,52 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsRenderBeastPrerequisites.h"
+#include "BsModule.h"
+#include "BsMatrix4.h"
+#include "BsConvexVolume.h"
+
+namespace bs { namespace ct
+{
+	/** @addtogroup RenderBeast
+	 *  @{
+	 */
+
+	// TODO - Define normal and omni vertex shaders and their params
+	// TODO - Move renderable objects from RenderBeast into a separate object so I can pass them here?
+	//  - SceneInfo?
+
+	/** Provides functionality for rendering shadow maps. */
+	class ShadowRendering : public Module<ShadowRendering>
+	{
+	public:
+		/**
+		 * Generates a frustum for a single cascade of a cascaded shadow map. Also outputs spherical bounds of the
+		 * split view frustum.
+		 * 
+		 * @param[in]	view		View whose frustum to split.
+		 * @param[in]	lightDir	Direction of the light for which we're generating the shadow map.
+		 * @param[in]	cascade		Index of the cascade to generate the frustum for.
+		 * @param[in]	numCascades	Maximum number of cascades in the cascaded shadow map. Must be greater than zero.
+		 * @param[out]	outBounds	Spherical bounds of the split view frustum.
+		 * @return					Convex volume covering the area of the split view frustum visible from the light.
+		 */
+		static ConvexVolume getCSMSplitFrustum(const RendererCamera& view, const Vector3& lightDir, UINT32 cascade, 
+			UINT32 numCascades, Sphere& outBounds);
+
+		/**
+		 * Finds the distance (along the view direction) of the frustum split for the specified index. Used for cascaded
+		 * shadow maps.
+		 * 
+		 * @param[in]	view			View whose frustum to split.
+		 * @param[in]	index			Index of the split. 0 = near plane.
+		 * @param[in]	numCascades		Maximum number of cascades in the cascaded shadow map. Must be greater than zero
+		 *								and greater or equal to @p index.
+		 * @return						Distance to the split position along the view direction.
+		 */
+		static float getCSMSplitDistance(const RendererCamera& view, UINT32 index, UINT32 numCascades);
+	};
+
+	/* @} */
+}}

+ 5 - 3
Source/RenderBeast/Source/BsPostProcessing.cpp

@@ -428,13 +428,15 @@ namespace bs { namespace ct
 
 
 	void PostProcessing::postProcess(RendererCamera* viewInfo, const SPtr<Texture>& sceneColor, float frameDelta)
 	void PostProcessing::postProcess(RendererCamera* viewInfo, const SPtr<Texture>& sceneColor, float frameDelta)
 	{
 	{
+		auto& viewProps = viewInfo->getProperties();
+
 		PostProcessInfo& ppInfo = viewInfo->getPPInfo();
 		PostProcessInfo& ppInfo = viewInfo->getPPInfo();
 		const StandardPostProcessSettings& settings = *ppInfo.settings;
 		const StandardPostProcessSettings& settings = *ppInfo.settings;
 
 
-		SPtr<RenderTarget> finalRT = viewInfo->getFinalTarget();
-		Rect2 viewportRect = viewInfo->getViewportRect();
+		SPtr<RenderTarget> finalRT = viewProps.target;
+		Rect2 viewportRect = viewProps.nrmViewRect;
 
 
-		bool hdr = viewInfo->isHDR();
+		bool hdr = viewProps.isHDR;
 
 
 		if(hdr && settings.enableAutoExposure)
 		if(hdr && settings.enableAutoExposure)
 		{
 		{

+ 24 - 17
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -37,6 +37,7 @@
 #include "BsMeshData.h"
 #include "BsMeshData.h"
 #include "BsLightGrid.h"
 #include "BsLightGrid.h"
 #include "BsSkybox.h"
 #include "BsSkybox.h"
+#include "BsShadowRendering.h"
 
 
 using namespace std::placeholders;
 using namespace std::placeholders;
 
 
@@ -93,6 +94,7 @@ namespace bs { namespace ct
 
 
 		GpuResourcePool::startUp();
 		GpuResourcePool::startUp();
 		PostProcessing::startUp();
 		PostProcessing::startUp();
+		ShadowRendering::startUp();
 	}
 	}
 
 
 	void RenderBeast::destroyCore()
 	void RenderBeast::destroyCore()
@@ -116,6 +118,7 @@ namespace bs { namespace ct
 		mSkyboxFilteredReflections = nullptr;
 		mSkyboxFilteredReflections = nullptr;
 		mSkyboxIrradiance = nullptr;
 		mSkyboxIrradiance = nullptr;
 
 
+		ShadowRendering::shutDown();
 		PostProcessing::shutDown();
 		PostProcessing::shutDown();
 		GpuResourcePool::shutDown();
 		GpuResourcePool::shutDown();
 
 
@@ -645,6 +648,7 @@ namespace bs { namespace ct
 			viewDesc.viewDirection = camera->getForward();
 			viewDesc.viewDirection = camera->getForward();
 			viewDesc.projTransform = camera->getProjectionMatrixRS();
 			viewDesc.projTransform = camera->getProjectionMatrixRS();
 			viewDesc.viewTransform = camera->getViewMatrix();
 			viewDesc.viewTransform = camera->getViewMatrix();
+			viewDesc.projType = camera->getProjectionType();
 
 
 			viewDesc.stateReduction = mCoreOptions->stateReductionMode;
 			viewDesc.stateReduction = mCoreOptions->stateReductionMode;
 			viewDesc.sceneCamera = camera;
 			viewDesc.sceneCamera = camera;
@@ -928,7 +932,7 @@ namespace bs { namespace ct
 
 
 		for (UINT32 i = 0; i < numViews; i++)
 		for (UINT32 i = 0; i < numViews; i++)
 		{
 		{
-			if (views[i]->isOverlay())
+			if (views[i]->getProperties().isOverlay)
 				renderOverlay(views[i]);
 				renderOverlay(views[i]);
 			else
 			else
 				renderView(views[i], frameInfo.timeDelta);
 				renderView(views[i], frameInfo.timeDelta);
@@ -939,18 +943,19 @@ namespace bs { namespace ct
 	{
 	{
 		gProfilerCPU().beginSample("Render");
 		gProfilerCPU().beginSample("Render");
 
 
+		auto& viewProps = viewInfo->getProperties();
 		const Camera* sceneCamera = viewInfo->getSceneCamera();
 		const Camera* sceneCamera = viewInfo->getSceneCamera();
 
 
 		SPtr<GpuParamBlockBuffer> perCameraBuffer = viewInfo->getPerViewBuffer();
 		SPtr<GpuParamBlockBuffer> perCameraBuffer = viewInfo->getPerViewBuffer();
 		perCameraBuffer->flushToGPU();
 		perCameraBuffer->flushToGPU();
 
 
-		Matrix4 viewProj = viewInfo->getViewProjMatrix();
-		UINT32 numSamples = viewInfo->getNumSamples();
+		Matrix4 viewProj = viewProps.viewProjTransform;
+		UINT32 numSamples = viewProps.numSamples;
 
 
 		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, viewInfo->renderWithNoLighting());
+		mLightGrid->updateGrid(*viewInfo, *mGPULightData, *mGPUReflProbeData, viewProps.noLighting);
 
 
 		SPtr<GpuParamBlockBuffer> gridParams;
 		SPtr<GpuParamBlockBuffer> gridParams;
 		SPtr<GpuBuffer> gridLightOffsetsAndSize, gridLightIndices;
 		SPtr<GpuBuffer> gridLightOffsetsAndSize, gridLightIndices;
@@ -962,7 +967,7 @@ namespace bs { namespace ct
 		ITiledDeferredImageBasedLightingMat* imageBasedLightingMat =
 		ITiledDeferredImageBasedLightingMat* imageBasedLightingMat =
 			mTileDeferredImageBasedLightingMats->get(numSamples);
 			mTileDeferredImageBasedLightingMats->get(numSamples);
 
 
-		imageBasedLightingMat->setReflectionProbes(*mGPUReflProbeData, mReflCubemapArrayTex, viewInfo->isRenderingReflections());
+		imageBasedLightingMat->setReflectionProbes(*mGPUReflProbeData, mReflCubemapArrayTex, viewProps.renderingReflections);
 
 
 		float skyBrightness = 1.0f;
 		float skyBrightness = 1.0f;
 		if (mSkybox != nullptr)
 		if (mSkybox != nullptr)
@@ -1027,7 +1032,7 @@ namespace bs { namespace ct
 		// Trigger pre-base-pass callbacks
 		// Trigger pre-base-pass callbacks
 		auto iterRenderCallback = mCallbacks.begin();
 		auto iterRenderCallback = mCallbacks.begin();
 
 
-		if (viewInfo->checkTriggerCallbacks())
+		if (viewProps.triggerCallbacks)
 		{
 		{
 			while (iterRenderCallback != mCallbacks.end())
 			while (iterRenderCallback != mCallbacks.end())
 			{
 			{
@@ -1051,7 +1056,7 @@ namespace bs { namespace ct
 		}
 		}
 
 
 		// Trigger post-base-pass callbacks
 		// Trigger post-base-pass callbacks
-		if (viewInfo->checkTriggerCallbacks())
+		if (viewProps.triggerCallbacks)
 		{
 		{
 			while (iterRenderCallback != mCallbacks.end())
 			while (iterRenderCallback != mCallbacks.end())
 			{
 			{
@@ -1075,7 +1080,7 @@ namespace bs { namespace ct
 		renderTargets->allocate(RTT_LightAccumulation);
 		renderTargets->allocate(RTT_LightAccumulation);
 
 
 		lightingMat->setLights(*mGPULightData);
 		lightingMat->setLights(*mGPULightData);
-		lightingMat->execute(renderTargets, perCameraBuffer, viewInfo->renderWithNoLighting());
+		lightingMat->execute(renderTargets, perCameraBuffer, viewProps.noLighting);
 
 
 		renderTargets->allocate(RTT_SceneColor);
 		renderTargets->allocate(RTT_SceneColor);
 
 
@@ -1108,7 +1113,7 @@ namespace bs { namespace ct
 		}
 		}
 		else
 		else
 		{
 		{
-			Color clearColor = viewInfo->getClearColor();
+			Color clearColor = viewProps.clearColor;
 
 
 			mSkyboxSolidColorMat->bind(perCameraBuffer);
 			mSkyboxSolidColorMat->bind(perCameraBuffer);
 			mSkyboxSolidColorMat->setParams(nullptr, clearColor);
 			mSkyboxSolidColorMat->setParams(nullptr, clearColor);
@@ -1128,7 +1133,7 @@ namespace bs { namespace ct
 		}
 		}
 
 
 		// Trigger post-light-pass callbacks
 		// Trigger post-light-pass callbacks
-		if (viewInfo->checkTriggerCallbacks())
+		if (viewProps.triggerCallbacks)
 		{
 		{
 			while (iterRenderCallback != mCallbacks.end())
 			while (iterRenderCallback != mCallbacks.end())
 			{
 			{
@@ -1144,9 +1149,9 @@ namespace bs { namespace ct
 		}
 		}
 
 
 		// Post-processing and final resolve
 		// Post-processing and final resolve
-		Rect2 viewportArea = viewInfo->getViewportRect();
+		Rect2 viewportArea = viewProps.nrmViewRect;
 
 
-		if (viewInfo->checkRunPostProcessing())
+		if (viewProps.runPostProcessing)
 		{
 		{
 			// If using MSAA, resolve into non-MSAA texture before post-processing
 			// If using MSAA, resolve into non-MSAA texture before post-processing
 			if(numSamples > 1)
 			if(numSamples > 1)
@@ -1155,7 +1160,7 @@ namespace bs { namespace ct
 				rapi.setViewport(viewportArea);
 				rapi.setViewport(viewportArea);
 
 
 				SPtr<Texture> sceneColor = renderTargets->getSceneColor();
 				SPtr<Texture> sceneColor = renderTargets->getSceneColor();
-				gRendererUtility().blit(sceneColor, Rect2I::EMPTY, viewInfo->getFlipView());
+				gRendererUtility().blit(sceneColor, Rect2I::EMPTY, viewProps.flipView);
 			}
 			}
 
 
 			// Post-processing code also takes care of writting to the final output target
 			// Post-processing code also takes care of writting to the final output target
@@ -1164,19 +1169,19 @@ namespace bs { namespace ct
 		else
 		else
 		{
 		{
 			// Just copy from scene color to output if no post-processing
 			// Just copy from scene color to output if no post-processing
-			SPtr<RenderTarget> target = viewInfo->getFinalTarget();
+			SPtr<RenderTarget> target = viewProps.target;
 
 
 			rapi.setRenderTarget(target);
 			rapi.setRenderTarget(target);
 			rapi.setViewport(viewportArea);
 			rapi.setViewport(viewportArea);
 
 
 			SPtr<Texture> sceneColor = renderTargets->getSceneColor();
 			SPtr<Texture> sceneColor = renderTargets->getSceneColor();
-			gRendererUtility().blit(sceneColor, Rect2I::EMPTY, viewInfo->getFlipView());
+			gRendererUtility().blit(sceneColor, Rect2I::EMPTY, viewProps.flipView);
 		}
 		}
 
 
 		renderTargets->release(RTT_SceneColor);
 		renderTargets->release(RTT_SceneColor);
 
 
 		// Trigger overlay callbacks
 		// Trigger overlay callbacks
-		if (viewInfo->checkTriggerCallbacks())
+		if (viewProps.triggerCallbacks)
 		{
 		{
 			while (iterRenderCallback != mCallbacks.end())
 			while (iterRenderCallback != mCallbacks.end())
 			{
 			{
@@ -1203,8 +1208,9 @@ namespace bs { namespace ct
 		viewInfo->getPerViewBuffer()->flushToGPU();
 		viewInfo->getPerViewBuffer()->flushToGPU();
 		viewInfo->beginRendering(false);
 		viewInfo->beginRendering(false);
 
 
+		auto& viewProps = viewInfo->getProperties();
 		const Camera* camera = viewInfo->getSceneCamera();
 		const Camera* camera = viewInfo->getSceneCamera();
-		SPtr<RenderTarget> target = viewInfo->getFinalTarget();
+		SPtr<RenderTarget> target = viewProps.target;
 		SPtr<Viewport> viewport = camera->getViewport();
 		SPtr<Viewport> viewport = camera->getViewport();
 
 
 		UINT32 clearBuffers = 0;
 		UINT32 clearBuffers = 0;
@@ -1455,6 +1461,7 @@ namespace bs { namespace ct
 
 
 		viewDesc.viewOrigin = position;
 		viewDesc.viewOrigin = position;
 		viewDesc.projTransform = projTransform;
 		viewDesc.projTransform = projTransform;
+		viewDesc.projType = PT_PERSPECTIVE;
 
 
 		viewDesc.stateReduction = mCoreOptions->stateReductionMode;
 		viewDesc.stateReduction = mCoreOptions->stateReductionMode;
 		viewDesc.sceneCamera = nullptr;
 		viewDesc.sceneCamera = nullptr;

+ 51 - 33
Source/RenderBeast/Source/BsRendererCamera.cpp

@@ -54,6 +54,21 @@ namespace bs { namespace ct
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().setPassParams(mParamsSet);
 	}
 	}
 
 
+	RendererViewProperties::RendererViewProperties(const RENDERER_VIEW_DESC& src)
+		:RendererViewData(src)
+	{
+		viewProjTransform = src.projTransform * src.viewTransform;
+
+		target = src.target.target;
+		nrmViewRect = src.target.nrmViewRect;
+		numSamples = src.target.numSamples;
+
+		clearFlags = src.target.clearFlags;
+		clearColor = src.target.clearColor;
+		clearDepthValue = src.target.clearDepthValue;
+		clearStencilValue = src.target.clearStencilValue;
+	}
+
 	RendererCamera::RendererCamera()
 	RendererCamera::RendererCamera()
 		: mUsingGBuffer(false)
 		: mUsingGBuffer(false)
 	{
 	{
@@ -61,7 +76,7 @@ namespace bs { namespace ct
 	}
 	}
 
 
 	RendererCamera::RendererCamera(const RENDERER_VIEW_DESC& desc)
 	RendererCamera::RendererCamera(const RENDERER_VIEW_DESC& desc)
-		: mViewDesc(desc), mUsingGBuffer(false)
+		: mProperties(desc), mTargetDesc(desc.target), mCamera(desc.sceneCamera), mUsingGBuffer(false)
 	{
 	{
 		mParamBuffer = gPerCameraParamDef.createBuffer();
 		mParamBuffer = gPerCameraParamDef.createBuffer();
 
 
@@ -96,20 +111,23 @@ namespace bs { namespace ct
 	void RendererCamera::setTransform(const Vector3& origin, const Vector3& direction, const Matrix4& view, 
 	void RendererCamera::setTransform(const Vector3& origin, const Vector3& direction, const Matrix4& view, 
 									  const Matrix4& proj, const ConvexVolume& worldFrustum)
 									  const Matrix4& proj, const ConvexVolume& worldFrustum)
 	{
 	{
-		mViewDesc.viewOrigin = origin;
-		mViewDesc.viewDirection = direction;
-		mViewDesc.viewTransform = view;
-		mViewDesc.projTransform = proj;
-		mViewDesc.cullFrustum = worldFrustum;
+		mProperties.viewOrigin = origin;
+		mProperties.viewDirection = direction;
+		mProperties.viewTransform = view;
+		mProperties.projTransform = proj;
+		mProperties.cullFrustum = worldFrustum;
+		mProperties.viewProjTransform = proj * view;
 	}
 	}
 
 
 	void RendererCamera::setView(const RENDERER_VIEW_DESC& desc)
 	void RendererCamera::setView(const RENDERER_VIEW_DESC& desc)
 	{
 	{
-		if (mViewDesc.target.targetWidth != desc.target.targetWidth ||
-			mViewDesc.target.targetHeight != desc.target.targetHeight)
+		if (mTargetDesc.targetWidth != desc.target.targetWidth ||
+			mTargetDesc.targetHeight != desc.target.targetHeight)
 			mRenderTargets = nullptr;
 			mRenderTargets = nullptr;
 
 
-		mViewDesc = desc;
+		mCamera = desc.sceneCamera;
+		mProperties = desc;
+		mTargetDesc = desc.target;
 
 
 		setStateReductionMode(desc.stateReduction);
 		setStateReductionMode(desc.stateReduction);
 	}
 	}
@@ -120,11 +138,11 @@ namespace bs { namespace ct
 		{
 		{
 			// Render scene objects to g-buffer
 			// Render scene objects to g-buffer
 			bool createGBuffer = mRenderTargets == nullptr ||
 			bool createGBuffer = mRenderTargets == nullptr ||
-				mRenderTargets->getHDR() != mViewDesc.isHDR ||
-				mRenderTargets->getNumSamples() != mViewDesc.target.numSamples;
+				mRenderTargets->getHDR() != mProperties.isHDR ||
+				mRenderTargets->getNumSamples() != mTargetDesc.numSamples;
 
 
 			if (createGBuffer)
 			if (createGBuffer)
-				mRenderTargets = RenderTargets::create(mViewDesc.target, mViewDesc.isHDR);
+				mRenderTargets = RenderTargets::create(mTargetDesc, mProperties.isHDR);
 
 
 			mRenderTargets->prepare();
 			mRenderTargets->prepare();
 			mUsingGBuffer = true;
 			mUsingGBuffer = true;
@@ -149,7 +167,7 @@ namespace bs { namespace ct
 		mVisibility.renderables.clear();
 		mVisibility.renderables.clear();
 		mVisibility.renderables.resize(renderables.size(), false);
 		mVisibility.renderables.resize(renderables.size(), false);
 
 
-		if (mViewDesc.isOverlay)
+		if (mProperties.isOverlay)
 			return;
 			return;
 
 
 		calculateVisibility(cullInfos, mVisibility.renderables);
 		calculateVisibility(cullInfos, mVisibility.renderables);
@@ -161,7 +179,7 @@ namespace bs { namespace ct
 				continue;
 				continue;
 
 
 			const AABox& boundingBox = cullInfos[i].bounds.getBox();
 			const AABox& boundingBox = cullInfos[i].bounds.getBox();
-			float distanceToCamera = (mViewDesc.viewOrigin - boundingBox.getCenter()).length();
+			float distanceToCamera = (mProperties.viewOrigin - boundingBox.getCenter()).length();
 
 
 			for (auto& renderElem : renderables[i]->elements)
 			for (auto& renderElem : renderables[i]->elements)
 			{
 			{
@@ -192,8 +210,8 @@ namespace bs { namespace ct
 
 
 	void RendererCamera::calculateVisibility(const Vector<CullInfo>& cullInfos, Vector<bool>& visibility) const
 	void RendererCamera::calculateVisibility(const Vector<CullInfo>& cullInfos, Vector<bool>& visibility) const
 	{
 	{
-		UINT64 cameraLayers = mViewDesc.visibleLayers;
-		const ConvexVolume& worldFrustum = mViewDesc.cullFrustum;
+		UINT64 cameraLayers = mProperties.visibleLayers;
+		const ConvexVolume& worldFrustum = mProperties.cullFrustum;
 
 
 		for (UINT32 i = 0; i < (UINT32)cullInfos.size(); i++)
 		for (UINT32 i = 0; i < (UINT32)cullInfos.size(); i++)
 		{
 		{
@@ -217,7 +235,7 @@ namespace bs { namespace ct
 
 
 	void RendererCamera::calculateVisibility(const Vector<Sphere>& bounds, Vector<bool>& visibility) const
 	void RendererCamera::calculateVisibility(const Vector<Sphere>& bounds, Vector<bool>& visibility) const
 	{
 	{
-		const ConvexVolume& worldFrustum = mViewDesc.cullFrustum;
+		const ConvexVolume& worldFrustum = mProperties.cullFrustum;
 
 
 		for (UINT32 i = 0; i < (UINT32)bounds.size(); i++)
 		for (UINT32 i = 0; i < (UINT32)bounds.size(); i++)
 		{
 		{
@@ -314,14 +332,14 @@ namespace bs { namespace ct
 
 
 	void RendererCamera::updatePerViewBuffer()
 	void RendererCamera::updatePerViewBuffer()
 	{
 	{
-		Matrix4 viewProj = mViewDesc.projTransform * mViewDesc.viewTransform;
+		Matrix4 viewProj = mProperties.projTransform * mProperties.viewTransform;
 		Matrix4 invViewProj = viewProj.inverse();
 		Matrix4 invViewProj = viewProj.inverse();
 
 
-		gPerCameraParamDef.gMatProj.set(mParamBuffer, mViewDesc.projTransform);
-		gPerCameraParamDef.gMatView.set(mParamBuffer, mViewDesc.viewTransform);
+		gPerCameraParamDef.gMatProj.set(mParamBuffer, mProperties.projTransform);
+		gPerCameraParamDef.gMatView.set(mParamBuffer, mProperties.viewTransform);
 		gPerCameraParamDef.gMatViewProj.set(mParamBuffer, viewProj);
 		gPerCameraParamDef.gMatViewProj.set(mParamBuffer, viewProj);
 		gPerCameraParamDef.gMatInvViewProj.set(mParamBuffer, invViewProj); // Note: Calculate inverses separately (better precision possibly)
 		gPerCameraParamDef.gMatInvViewProj.set(mParamBuffer, invViewProj); // Note: Calculate inverses separately (better precision possibly)
-		gPerCameraParamDef.gMatInvProj.set(mParamBuffer, mViewDesc.projTransform.inverse());
+		gPerCameraParamDef.gMatInvProj.set(mParamBuffer, mProperties.projTransform.inverse());
 
 
 		// Construct a special inverse view-projection matrix that had projection entries that affect z and w eliminated.
 		// Construct a special inverse view-projection matrix that had projection entries that affect z and w eliminated.
 		// Used to transform a vector(clip_x, clip_y, view_z, view_w), where clip_x/clip_y are in clip space, and 
 		// Used to transform a vector(clip_x, clip_y, view_z, view_w), where clip_x/clip_y are in clip space, and 
@@ -329,21 +347,21 @@ namespace bs { namespace ct
 
 
 		// Only projects z/w coordinates
 		// Only projects z/w coordinates
 		Matrix4 projZ = Matrix4::IDENTITY;
 		Matrix4 projZ = Matrix4::IDENTITY;
-		projZ[2][2] = mViewDesc.projTransform[2][2];
-		projZ[2][3] = mViewDesc.projTransform[2][3];
-		projZ[3][2] = mViewDesc.projTransform[3][2];
+		projZ[2][2] = mProperties.projTransform[2][2];
+		projZ[2][3] = mProperties.projTransform[2][3];
+		projZ[3][2] = mProperties.projTransform[3][2];
 		projZ[3][3] = 0.0f;
 		projZ[3][3] = 0.0f;
 		
 		
 		gPerCameraParamDef.gMatScreenToWorld.set(mParamBuffer, invViewProj * projZ);
 		gPerCameraParamDef.gMatScreenToWorld.set(mParamBuffer, invViewProj * projZ);
-		gPerCameraParamDef.gViewDir.set(mParamBuffer, mViewDesc.viewDirection);
-		gPerCameraParamDef.gViewOrigin.set(mParamBuffer, mViewDesc.viewOrigin);
-		gPerCameraParamDef.gDeviceZToWorldZ.set(mParamBuffer, getDeviceZTransform(mViewDesc.projTransform));
-		gPerCameraParamDef.gNDCZToWorldZ.set(mParamBuffer, getNDCZTransform(mViewDesc.projTransform));
+		gPerCameraParamDef.gViewDir.set(mParamBuffer, mProperties.viewDirection);
+		gPerCameraParamDef.gViewOrigin.set(mParamBuffer, mProperties.viewOrigin);
+		gPerCameraParamDef.gDeviceZToWorldZ.set(mParamBuffer, getDeviceZTransform(mProperties.projTransform));
+		gPerCameraParamDef.gNDCZToWorldZ.set(mParamBuffer, getNDCZTransform(mProperties.projTransform));
 
 
-		Vector2 nearFar(mViewDesc.nearPlane, mViewDesc.farPlane);
+		Vector2 nearFar(mProperties.nearPlane, mProperties.farPlane);
 		gPerCameraParamDef.gNearFar.set(mParamBuffer, nearFar);
 		gPerCameraParamDef.gNearFar.set(mParamBuffer, nearFar);
 
 
-		const Rect2I& viewRect = mViewDesc.target.viewRect;
+		const Rect2I& viewRect = mTargetDesc.viewRect;
 
 
 		Vector4I viewportRect;
 		Vector4I viewportRect;
 		viewportRect[0] = viewRect.x;
 		viewportRect[0] = viewRect.x;
@@ -356,8 +374,8 @@ namespace bs { namespace ct
 		float halfWidth = viewRect.width * 0.5f;
 		float halfWidth = viewRect.width * 0.5f;
 		float halfHeight = viewRect.height * 0.5f;
 		float halfHeight = viewRect.height * 0.5f;
 
 
-		float rtWidth = mViewDesc.target.targetWidth != 0 ? (float)mViewDesc.target.targetWidth : 20.0f;
-		float rtHeight = mViewDesc.target.targetHeight != 0 ? (float)mViewDesc.target.targetHeight : 20.0f;
+		float rtWidth = mTargetDesc.targetWidth != 0 ? (float)mTargetDesc.targetWidth : 20.0f;
+		float rtHeight = mTargetDesc.targetHeight != 0 ? (float)mTargetDesc.targetHeight : 20.0f;
 
 
 		RenderAPI& rapi = RenderAPI::instance();
 		RenderAPI& rapi = RenderAPI::instance();
 		const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
 		const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
@@ -374,7 +392,7 @@ namespace bs { namespace ct
 
 
 		gPerCameraParamDef.gClipToUVScaleOffset.set(mParamBuffer, clipToUVScaleOffset);
 		gPerCameraParamDef.gClipToUVScaleOffset.set(mParamBuffer, clipToUVScaleOffset);
 
 
-		if (mViewDesc.noLighting)
+		if (mProperties.noLighting)
 			gPerCameraParamDef.gAmbientFactor.set(mParamBuffer, 100.0f);
 			gPerCameraParamDef.gAmbientFactor.set(mParamBuffer, 100.0f);
 		else
 		else
 			gPerCameraParamDef.gAmbientFactor.set(mParamBuffer, 0.0f);
 			gPerCameraParamDef.gAmbientFactor.set(mParamBuffer, 0.0f);

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

@@ -0,0 +1,183 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsShadowRendering.h"
+#include "BsRendererCamera.h"
+
+namespace bs { namespace ct
+{
+	ConvexVolume ShadowRendering::getCSMSplitFrustum(const RendererCamera& view, const Vector3& lightDir, UINT32 cascade, 
+		UINT32 numCascades, Sphere& outBounds)
+	{
+		// Determine split range
+		float splitNear = getCSMSplitDistance(view, cascade, numCascades);
+		float splitFar = getCSMSplitDistance(view, cascade + 1, numCascades);
+
+		// Calculate the eight vertices of the split frustum
+		auto& viewProps = view.getProperties();
+
+		const Matrix4& projMat = viewProps.projTransform;
+
+		float aspect;
+		float nearHalfWidth, nearHalfHeight;
+		float farHalfWidth, farHalfHeight;
+		if(viewProps.projType == PT_PERSPECTIVE)
+		{
+			aspect = projMat[0][0] / projMat[1][1];
+			float tanHalfFOV = 1.0f / projMat[0][0];
+
+			nearHalfWidth = splitNear * tanHalfFOV;
+			nearHalfHeight = nearHalfWidth * aspect;
+
+			farHalfWidth = splitFar * tanHalfFOV;
+			farHalfHeight = farHalfWidth * aspect;
+		}
+		else
+		{
+			aspect = projMat[0][0] / projMat[1][1];
+
+			nearHalfWidth = farHalfWidth = projMat[0][0] / 4.0f;
+			nearHalfHeight = farHalfHeight = projMat[1][1] / 4.0f;
+		}
+
+		const Matrix4& viewMat = viewProps.viewTransform;
+		Vector3 cameraRight = Vector3(viewMat[0]);
+		Vector3 cameraUp = Vector3(viewMat[1]);
+
+		const Vector3& viewOrigin = viewProps.viewOrigin;
+		const Vector3& viewDir = viewProps.viewDirection;
+
+		Vector3 frustumVerts[] =
+		{
+			viewOrigin + viewDir * splitNear - cameraRight * nearHalfWidth + cameraUp * nearHalfHeight, // Near, left, top
+			viewOrigin + viewDir * splitNear + cameraRight * nearHalfWidth + cameraUp * nearHalfHeight, // Near, right, top
+			viewOrigin + viewDir * splitNear + cameraRight * nearHalfWidth - cameraUp * nearHalfHeight, // Near, right, bottom
+			viewOrigin + viewDir * splitNear - cameraRight * nearHalfWidth - cameraUp * nearHalfHeight, // Near, left, bottom
+			viewOrigin + viewDir * splitFar - cameraRight * farHalfWidth + cameraUp * farHalfHeight, // Far, left, top
+			viewOrigin + viewDir * splitFar + cameraRight * farHalfWidth + cameraUp * farHalfHeight, // Far, right, top
+			viewOrigin + viewDir * splitFar + cameraRight * farHalfWidth - cameraUp * farHalfHeight, // Far, right, bottom
+			viewOrigin + viewDir * splitFar - cameraRight * farHalfWidth - cameraUp * farHalfHeight, // Far, left, bottom
+		};
+
+		// Calculate the bounding sphere of the frustum
+		float diagonalNearSq = nearHalfWidth * nearHalfWidth + nearHalfHeight * nearHalfHeight;
+		float diagonalFarSq = farHalfWidth * farHalfWidth + farHalfHeight * farHalfHeight;
+
+		float length = splitFar - splitNear;
+		float offset = (diagonalNearSq - diagonalFarSq) / 2 * length + length * 0.5f;
+		float distToCenter = Math::clamp(splitFar - offset, splitNear, splitFar);
+
+		Vector3 center = viewOrigin + viewDir * distToCenter;
+
+		float radius = 0.0f;
+		for (auto& entry : frustumVerts)
+			radius = std::max(radius, center.squaredDistance(entry));
+
+		radius = std::max(sqrt(radius), 1.0f);
+		outBounds = Sphere(center, radius);
+
+		// Generate light frustum planes
+		Plane viewPlanes[6];
+		viewPlanes[FRUSTUM_PLANE_NEAR] = Plane(frustumVerts[0], frustumVerts[1], frustumVerts[2]);
+		viewPlanes[FRUSTUM_PLANE_FAR] = Plane(frustumVerts[5], frustumVerts[4], frustumVerts[7]);
+		viewPlanes[FRUSTUM_PLANE_LEFT] = Plane(frustumVerts[4], frustumVerts[0], frustumVerts[3]);
+		viewPlanes[FRUSTUM_PLANE_RIGHT] = Plane(frustumVerts[1], frustumVerts[5], frustumVerts[6]);
+		viewPlanes[FRUSTUM_PLANE_TOP] = Plane(frustumVerts[4], frustumVerts[5], frustumVerts[1]);
+		viewPlanes[FRUSTUM_PLANE_BOTTOM] = Plane(frustumVerts[3], frustumVerts[2], frustumVerts[6]);
+
+		Vector<Plane> lightVolume;
+
+		//// Add camera's planes facing towards the lights (forming the back of the volume)
+		for(auto& entry : viewPlanes)
+		{
+			if (entry.normal.dot(lightDir) < 0.0f)
+				lightVolume.push_back(entry);
+		}
+
+		//// Determine edge planes by testing adjacent planes with different facing
+		////// Pairs of frustum planes that share an edge
+		UINT32 adjacentPlanes[][2] =
+		{
+			{ FRUSTUM_PLANE_NEAR, FRUSTUM_PLANE_LEFT },
+			{ FRUSTUM_PLANE_NEAR, FRUSTUM_PLANE_RIGHT },
+			{ FRUSTUM_PLANE_NEAR, FRUSTUM_PLANE_TOP },
+			{ FRUSTUM_PLANE_NEAR, FRUSTUM_PLANE_BOTTOM },
+
+			{ FRUSTUM_PLANE_FAR, FRUSTUM_PLANE_LEFT },
+			{ FRUSTUM_PLANE_FAR, FRUSTUM_PLANE_RIGHT },
+			{ FRUSTUM_PLANE_FAR, FRUSTUM_PLANE_TOP },
+			{ FRUSTUM_PLANE_FAR, FRUSTUM_PLANE_BOTTOM },
+
+			{ FRUSTUM_PLANE_LEFT, FRUSTUM_PLANE_TOP },
+			{ FRUSTUM_PLANE_TOP, FRUSTUM_PLANE_RIGHT },
+			{ FRUSTUM_PLANE_RIGHT, FRUSTUM_PLANE_BOTTOM },
+			{ FRUSTUM_PLANE_BOTTOM, FRUSTUM_PLANE_LEFT },
+		};
+
+		////// Vertex indices of edges on the boundary between two planes
+		UINT32 sharedEdges[][2] =
+		{
+			{ 3, 0 },{ 1, 2 },{ 0, 1 },{ 2, 3 },
+			{ 4, 7 },{ 6, 5 },{ 5, 4 },{ 7, 6 },
+			{ 4, 0 },{ 5, 1 },{ 6, 2 },{ 7, 3 }
+		};
+
+		for(UINT32 i = 0; i < 12; i++)
+		{
+			const Plane& planeA = viewPlanes[adjacentPlanes[i][0]];
+			const Plane& planeB = viewPlanes[adjacentPlanes[i][1]];
+
+			float dotA = planeA.normal.dot(lightDir);
+			float dotB = planeB.normal.dot(lightDir);
+
+			if((dotA * dotB) < 0.0f)
+			{
+				const Vector3& vertA = frustumVerts[sharedEdges[i][0]];
+				const Vector3& vertB = frustumVerts[sharedEdges[i][1]];
+				Vector3 vertC = vertA + lightDir;
+
+				if (dotA >= 0.0f)
+					lightVolume.push_back(Plane(vertA, vertB, vertC));
+				else
+					lightVolume.push_back(Plane(vertB, vertA, vertC));
+			}
+		}
+
+		return ConvexVolume(lightVolume);
+	}
+
+	float ShadowRendering::getCSMSplitDistance(const RendererCamera& view, UINT32 index, UINT32 numCascades)
+	{
+		// Determines the size of each subsequent cascade split. Value of 1 means the cascades will be linearly split.
+		// Value of 2 means each subsequent split will be twice the size of the previous one. Valid range is roughly
+		// [1, 4].
+		// Note: Make this an adjustable property?
+		const static float DISTRIBUTON_EXPONENT = 1.0f;
+
+		// First determine the scale of the split, relative to the entire range
+		float scaleModifier = 1.0f;
+		float scale = 0.0f;
+		float totalScale = 0.0f;
+
+		//// Split 0 corresponds to near plane
+		if (index > 0)
+		{
+			for (UINT32 i = 0; i < numCascades; i++)
+			{
+				if (i < index)
+					scale += scaleModifier;
+
+				totalScale += scaleModifier;
+				scaleModifier *= DISTRIBUTON_EXPONENT;
+			}
+		}
+
+		scale = scale / totalScale;
+
+		// Calculate split distance in Z
+		auto& viewProps = view.getProperties();
+		float near = viewProps.nearPlane;
+		float far = viewProps.farPlane;
+
+		return near + (far - near) * scale;
+	}
+}}