Quellcode durchsuchen

Shadow mapping feature parity between DX11 and OpenGL backends

BearishSun vor 8 Jahren
Ursprung
Commit
7c066db8bb

+ 22 - 21
Source/BansheeGLRenderAPI/Include/BsGLFrameBufferObject.h

@@ -13,11 +13,11 @@ namespace bs { namespace ct
 	 *  @{
 	 */
 
-	/**	Describes OpenGL frame buffer surface. */
-    struct GLSurfaceDesc
-    {
-    public:
-		GLSurfaceDesc() 
+	 /**	Describes OpenGL frame buffer surface. */
+	struct GLSurfaceDesc
+	{
+	public:
+		GLSurfaceDesc()
 			:zoffset(0), numSamples(0), allLayers(false)
 		{ }
 
@@ -25,17 +25,17 @@ namespace bs { namespace ct
 		UINT32 zoffset;
 		UINT32 numSamples;
 		bool allLayers;
-    };
+	};
 
 	/**
 	 * Manages an OpenGL frame-buffer object. Frame buffer object is used as a rendering destination in the render system
 	 * pipeline, and it may consist out of one or multiple color surfaces and an optional depth/stencil surface.
 	 */
-    class GLFrameBufferObject
-    {
-    public:
-        GLFrameBufferObject();
-        ~GLFrameBufferObject();
+	class GLFrameBufferObject
+	{
+	public:
+		GLFrameBufferObject();
+		~GLFrameBufferObject();
 
 		/**
 		 * Binds a color surface to the specific attachment point. Call rebuild() to apply changes.
@@ -43,36 +43,36 @@ namespace bs { namespace ct
 		 * @param[in]	attachment	Attachment point index in the range [0, BS_MAX_MULTIPLE_RENDER_TARGETS).
 		 * @param[in]	target		Description of the color surface to attach.
 		 *
-		 * @note	
+		 * @note
 		 * Multisample counts of all surfaces must match.
 		 * 0th attachment must be bound in order for the object to be usable, rest are optional.
 		 */
-        void bindSurface(UINT32 attachment, const GLSurfaceDesc& target);
+		void bindSurface(UINT32 attachment, const GLSurfaceDesc& target);
 
 		/**
 		 * Unbinds the attachment at the specified attachment index. Call rebuild() to apply changes.
 		 *
 		 * @param[in]	attachment	Attachment point index in the range [0, BS_MAX_MULTIPLE_RENDER_TARGETS).
 		 */
-        void unbindSurface(UINT32 attachment);
+		void unbindSurface(UINT32 attachment);
 
 		/**
 		 * Binds a depth/stencil buffer. Call rebuild() to apply changes.
 		 *
-		 * @note	
+		 * @note
 		 * Multisample counts of depth/stencil and color surfaces must match.
 		 * Binding a depth/stencil buffer is optional.
 		 */
-		void bindDepthStencil(SPtr<GLPixelBuffer> depthStencilBuffer);
+		void bindDepthStencil(SPtr<GLPixelBuffer> depthStencilBuffer, bool allLayers);
 
 		/**	Unbinds a depth stencil buffer. Call rebuild() to apply changes. */
 		void unbindDepthStencil();
-        
+
 		/**	Rebuilds internal frame buffer object. Should be called whenever surfaces changes or is bound/unbound. */
 		void rebuild();
 
 		/** Binds the frame buffer object to the OpenGL pipeline, making it used for any further rendering operations. */
-        void bind();
+		void bind();
 
 		/** Checks is the color buffer at the specified index bound. */
 		bool hasColorBuffer(UINT32 idx) const { return mColor[idx].buffer != nullptr; }
@@ -81,11 +81,12 @@ namespace bs { namespace ct
 		GLuint getGLFBOID() const { return mFB; }
 
 	private:
-        GLuint mFB;
+		GLuint mFB;
 
-        GLSurfaceDesc mColor[BS_MAX_MULTIPLE_RENDER_TARGETS];
+		GLSurfaceDesc mColor[BS_MAX_MULTIPLE_RENDER_TARGETS];
 		SPtr<GLPixelBuffer> mDepthStencilBuffer;
-    };
+		bool mDepthStencilAllLayers;
+	};
 
 	/** @} */
 }}

+ 14 - 9
Source/BansheeGLRenderAPI/Include/BsGLTexture.h

@@ -12,24 +12,24 @@ namespace bs { namespace ct
 	 *  @{
 	 */
 
-	/**	OpenGL implementation of a texture. */
-    class GLTexture : public Texture
-    {
-    public:
+	 /**	OpenGL implementation of a texture. */
+	class GLTexture : public Texture
+	{
+	public:
 		virtual ~GLTexture();
 
 		/**	Returns OpenGL texture target type. */
-        GLenum getGLTextureTarget() const;
+		GLenum getGLTextureTarget() const;
 
 		/**	Returns internal OpenGL texture handle. */
-        GLuint getGLID() const;
+		GLuint getGLID() const;
 
 		/**	Returns the internal OpenGL format used by the texture. */
 		GLenum getGLFormat() const { return mGLFormat; }
-		
+
 		/**
 		 * Returns a hardware pixel buffer for a certain face and level of the texture.
-		 * 
+		 *
 		 * @param[in]	face	Index of the texture face, if texture has more than one. Array index for texture arrays and
 		 *						a cube face for cube textures.
 		 * @param[in]	mipmap	Index of the mip level. 0 being the largest mip level.
@@ -38,7 +38,12 @@ namespace bs { namespace ct
 		 */
 		SPtr<GLPixelBuffer> getBuffer(UINT32 face, UINT32 mipmap);
 
-    protected:
+		/** 
+		 * Generates an OpenGL texture target based on the texture type, number of samples per pixel, and number of faces.
+		 */
+		static GLenum getGLTextureTarget(TextureType type, UINT32 numSamples, UINT32 numFaces);
+
+	protected:
 		friend class GLTextureManager;
 
 		GLTexture(GLSupport& support, const TEXTURE_DESC& desc, const SPtr<PixelData>& initialData, 

+ 4 - 0
Source/BansheeGLRenderAPI/Include/BsGLTextureView.h

@@ -20,12 +20,16 @@ namespace bs { namespace ct
 		/**	Returns internal OpenGL texture view handle. */
 		GLuint getGLID() const { return mViewID; }
 
+		/**	Returns OpenGL texture target type. */
+		GLuint getGLTextureTarget() const { return mTarget; }
+
 	protected:
 		friend class GLTexture;
 
 		GLTextureView(const GLTexture* texture, const TEXTURE_VIEW_DESC& desc);
 	private:
 		GLuint mViewID;
+		GLuint mTarget;
 	};
 
 	/** @} */

+ 64 - 65
Source/BansheeGLRenderAPI/Source/BsGLFrameBufferObject.cpp

@@ -8,37 +8,39 @@
 
 namespace bs { namespace ct
 {
-    GLFrameBufferObject::GLFrameBufferObject()
-    {
-        glGenFramebuffers(1, &mFB);
+	GLFrameBufferObject::GLFrameBufferObject()
+		: mDepthStencilAllLayers(false)
+	{
+		glGenFramebuffers(1, &mFB);
 
-        for(UINT32 x = 0; x < BS_MAX_MULTIPLE_RENDER_TARGETS; ++x)
-            mColor[x].buffer = nullptr;
+		for (UINT32 x = 0; x < BS_MAX_MULTIPLE_RENDER_TARGETS; ++x)
+			mColor[x].buffer = nullptr;
 
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_FrameBufferObject);
-    }
+	}
 
-    GLFrameBufferObject::~GLFrameBufferObject()
-    {
-        glDeleteFramebuffers(1, &mFB);    
+	GLFrameBufferObject::~GLFrameBufferObject()
+	{
+		glDeleteFramebuffers(1, &mFB);
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_FrameBufferObject);
-    }
+	}
 
-    void GLFrameBufferObject::bindSurface(UINT32 attachment, const GLSurfaceDesc &target)
-    {
-        assert(attachment < BS_MAX_MULTIPLE_RENDER_TARGETS);
-        mColor[attachment] = target;
-    }
+	void GLFrameBufferObject::bindSurface(UINT32 attachment, const GLSurfaceDesc &target)
+	{
+		assert(attachment < BS_MAX_MULTIPLE_RENDER_TARGETS);
+		mColor[attachment] = target;
+	}
 
-    void GLFrameBufferObject::unbindSurface(UINT32 attachment)
-    {
-        assert(attachment < BS_MAX_MULTIPLE_RENDER_TARGETS);
-        mColor[attachment].buffer = nullptr;
-    }
+	void GLFrameBufferObject::unbindSurface(UINT32 attachment)
+	{
+		assert(attachment < BS_MAX_MULTIPLE_RENDER_TARGETS);
+		mColor[attachment].buffer = nullptr;
+	}
 
-	void GLFrameBufferObject::bindDepthStencil(SPtr<GLPixelBuffer> depthStencilBuffer)
+	void GLFrameBufferObject::bindDepthStencil(SPtr<GLPixelBuffer> depthStencilBuffer, bool allLayers)
 	{
 		mDepthStencilBuffer = depthStencilBuffer;
+		mDepthStencilAllLayers = allLayers;
 	}
 
 	void GLFrameBufferObject::unbindDepthStencil()
@@ -46,33 +48,30 @@ namespace bs { namespace ct
 		mDepthStencilBuffer = nullptr;
 	}
 
-    void GLFrameBufferObject::rebuild()
-    {
-        // Store basic stats
-        UINT16 maxSupportedMRTs = RenderAPI::instancePtr()->getCapabilities(0).getNumMultiRenderTargets();
+	void GLFrameBufferObject::rebuild()
+	{
+		// Store basic stats
+		UINT16 maxSupportedMRTs = RenderAPI::instancePtr()->getCapabilities(0).getNumMultiRenderTargets();
 
 		// Bind simple buffer to add color attachments
 		glBindFramebuffer(GL_FRAMEBUFFER, mFB);
 
-		bool bindAllLayers = false;
-
-        // Bind all attachment points to frame buffer
-        for(UINT16 x = 0; x < maxSupportedMRTs; ++x)
-        {
-            if(mColor[x].buffer)
-            {
+		// Bind all attachment points to frame buffer
+		for (UINT16 x = 0; x < maxSupportedMRTs; ++x)
+		{
+			if (mColor[x].buffer)
+			{
 				// Note: I'm attaching textures to FBO while renderbuffers might yield better performance if I
 				// don't need to read from them
 
-	            mColor[x].buffer->bindToFramebuffer(GL_COLOR_ATTACHMENT0 + x, mColor[x].zoffset, mColor[x].allLayers);
-				bindAllLayers |= mColor[x].allLayers;
-            }
-            else
-            {
-                // Detach
-                glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + x, 0, 0);
-            }
-        }
+				mColor[x].buffer->bindToFramebuffer(GL_COLOR_ATTACHMENT0 + x, mColor[x].zoffset, mColor[x].allLayers);
+			}
+			else
+			{
+				// Detach
+				glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + x, 0, 0);
+			}
+		}
 
 		if (mDepthStencilBuffer != nullptr)
 		{
@@ -84,20 +83,20 @@ namespace bs { namespace ct
 			else // Depth only
 				attachmentPoint = GL_DEPTH_ATTACHMENT;
 
-			mDepthStencilBuffer->bindToFramebuffer(attachmentPoint, 0, true);
+			mDepthStencilBuffer->bindToFramebuffer(attachmentPoint, 0, mDepthStencilAllLayers);
 		}
 
 		// Do glDrawBuffer calls
 		GLenum bufs[BS_MAX_MULTIPLE_RENDER_TARGETS];
 		GLsizei n = 0;
-		for(UINT32 x = 0; x < BS_MAX_MULTIPLE_RENDER_TARGETS; ++x)
+		for (UINT32 x = 0; x < BS_MAX_MULTIPLE_RENDER_TARGETS; ++x)
 		{
 			// Fill attached colour buffers
-			if(mColor[x].buffer)
+			if (mColor[x].buffer)
 			{
 				bufs[x] = GL_COLOR_ATTACHMENT0 + x;
 				// Keep highest used buffer + 1
-				n = x+1;
+				n = x + 1;
 			}
 			else
 			{
@@ -110,27 +109,27 @@ namespace bs { namespace ct
 		// No read buffer, by default, if we want to read anyway we must not forget to set this.
 		glReadBuffer(GL_NONE);
 
-        // Check status
-        GLuint status;
-        status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-        
-        // Bind main buffer
-        glBindFramebuffer(GL_FRAMEBUFFER, 0);
-        
-        switch(status)
-        {
-        case GL_FRAMEBUFFER_COMPLETE:
-            break;
-        case GL_FRAMEBUFFER_UNSUPPORTED:
-            LOGERR("All framebuffer formats with this texture internal format unsupported");
+		// Check status
+		GLuint status;
+		status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+		// Bind main buffer
+		glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+		switch (status)
+		{
+		case GL_FRAMEBUFFER_COMPLETE:
+			break;
+		case GL_FRAMEBUFFER_UNSUPPORTED:
+			LOGERR("All framebuffer formats with this texture internal format unsupported");
 			break;
-        default:
-            LOGERR("Framebuffer incomplete or other FBO status error");
-        }
-    }
+		default:
+			LOGERR("Framebuffer incomplete or other FBO status error");
+		}
+	}
 
-    void GLFrameBufferObject::bind()
-    {
+	void GLFrameBufferObject::bind()
+	{
 		glBindFramebuffer(GL_FRAMEBUFFER, mFB);
-    }
+	}
 }}

+ 7 - 22
Source/BansheeGLRenderAPI/Source/BsGLRenderAPI.cpp

@@ -458,15 +458,15 @@ namespace bs { namespace ct
 
 						if (glTex != nullptr)
 						{
-							GLenum newTextureType = glTex->getGLTextureTarget();
+							SPtr<TextureView> texView = glTex->requestView(surface.mipLevel, surface.numMipLevels, 
+								surface.arraySlice, surface.numArraySlices, GVU_DEFAULT);
+
+							GLTextureView* glTexView = static_cast<GLTextureView*>(texView.get());
+							GLenum newTextureType = glTexView->getGLTextureTarget();
 
 							if (mTextureInfos[unit].type != newTextureType)
 								glBindTexture(mTextureInfos[unit].type, 0);
 
-							SPtr<TextureView> texView = glTex->requestView(surface.mipLevel, surface.numMipLevels, 
-																surface.arraySlice, surface.numArraySlices, GVU_DEFAULT);
-
-							GLTextureView* glTexView = static_cast<GLTextureView*>(texView.get());
 							glBindTexture(newTextureType, glTexView->getGLID());
 							mTextureInfos[unit].type = newTextureType;
 
@@ -1495,24 +1495,15 @@ namespace bs { namespace ct
 
 		const RenderTargetProperties& rtProps = mActiveRenderTarget->getProperties();
 
-		// If request texture flipping, use "upper-left", otherwise use "lower-left"
-		bool flipping = rtProps.requiresTextureFlipping();
-		//  GL measures from the bottom, not the top
-		UINT32 targetHeight = rtProps.getHeight();
 		// Calculate the "lower-left" corner of the viewport
 		GLsizei x = 0, y = 0, w = 0, h = 0;
 
 		if (enable)
 		{
 			glEnable(GL_SCISSOR_TEST);
-			// GL uses width / height rather than right / bottom
-			x = mScissorLeft;
-
-			if (flipping)
-				y = targetHeight - mScissorBottom;
-			else
-				y = mScissorTop;
 
+			x = mScissorLeft;
+			y = mScissorTop;
 			w = mScissorRight - mScissorLeft;
 			h = mScissorBottom - mScissorTop;
 
@@ -2285,12 +2276,6 @@ namespace bs { namespace ct
 		mViewportWidth = (UINT32)(rtProps.getWidth() * mViewportNorm.width);
 		mViewportHeight = (UINT32)(rtProps.getHeight() * mViewportNorm.height);
 
-		if (rtProps.requiresTextureFlipping())
-		{
-			// Convert "upper-left" corner to "lower-left"
-			mViewportTop = rtProps.getHeight() - (mViewportTop + mViewportHeight);
-		}
-
 		glViewport(mViewportLeft, mViewportTop, mViewportWidth, mViewportHeight);
 
 		// Configure the viewport clipping

+ 10 - 2
Source/BansheeGLRenderAPI/Source/BsGLRenderTexture.cpp

@@ -105,13 +105,21 @@ namespace bs
 			GLTexture* glDepthStencilTexture = static_cast<GLTexture*>(mDesc.depthStencilSurface.texture.get());
 			SPtr<GLPixelBuffer> depthStencilBuffer = nullptr;
 
+			bool allLayers = false;
+			if (mDepthStencilSurface->getNumArraySlices() == 1) // Binding a single texture layer
+				allLayers = glDepthStencilTexture->getProperties().getNumFaces() == 1;
+
 			if (glDepthStencilTexture->getProperties().getTextureType() != TEX_TYPE_3D)
 			{
-				depthStencilBuffer = glDepthStencilTexture->getBuffer(mDepthStencilSurface->getFirstArraySlice(),
+				UINT32 firstSlice = 0;
+				if (!allLayers)
+					firstSlice = mDepthStencilSurface->getFirstArraySlice();
+
+				depthStencilBuffer = glDepthStencilTexture->getBuffer(firstSlice, 
 					mDepthStencilSurface->getMostDetailedMip());
 			}
 
-			mFB->bindDepthStencil(depthStencilBuffer);
+			mFB->bindDepthStencil(depthStencilBuffer, allLayers);
 		}
 
 		mFB->rebuild();

+ 40 - 35
Source/BansheeGLRenderAPI/Source/BsGLTexture.cpp

@@ -132,41 +132,10 @@ namespace bs { namespace ct
 		Texture::initialize();
 	}
 
-    GLenum GLTexture::getGLTextureTarget() const
-    {
-		switch (mProperties.getTextureType())
-        {
-            case TEX_TYPE_1D:
-				if(mProperties.getNumFaces() <= 1)
-					return GL_TEXTURE_1D;
-				else
-					return GL_TEXTURE_1D_ARRAY;
-            case TEX_TYPE_2D:
-				if (mProperties.getNumSamples() > 1)
-				{
-					if (mProperties.getNumFaces() <= 1)
-						return GL_TEXTURE_2D_MULTISAMPLE;
-					else
-						return GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
-				}
-				else
-				{
-					if (mProperties.getNumFaces() <= 1)
-						return GL_TEXTURE_2D;
-					else
-						return GL_TEXTURE_2D_ARRAY;
-				}
-            case TEX_TYPE_3D:
-                return GL_TEXTURE_3D;
-            case TEX_TYPE_CUBE_MAP:
-				if (mProperties.getNumFaces() <= 6)
-					return GL_TEXTURE_CUBE_MAP;
-				else
-					return GL_TEXTURE_CUBE_MAP_ARRAY;
-            default:
-                return 0;
-        };
-    }
+	GLenum GLTexture::getGLTextureTarget() const
+	{
+		return getGLTextureTarget(mProperties.getTextureType(), mProperties.getNumSamples(), mProperties.getNumFaces());
+	}
 
 	GLuint GLTexture::getGLID() const
 	{
@@ -175,6 +144,42 @@ namespace bs { namespace ct
 		return mTextureID;
 	}
 
+	GLenum GLTexture::getGLTextureTarget(TextureType type, UINT32 numSamples, UINT32 numFaces)
+	{
+		switch (type)
+		{
+		case TEX_TYPE_1D:
+			if (numFaces <= 1)
+				return GL_TEXTURE_1D;
+			else
+				return GL_TEXTURE_1D_ARRAY;
+		case TEX_TYPE_2D:
+			if (numSamples > 1)
+			{
+				if (numFaces <= 1)
+					return GL_TEXTURE_2D_MULTISAMPLE;
+				else
+					return GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
+			}
+			else
+			{
+				if (numFaces <= 1)
+					return GL_TEXTURE_2D;
+				else
+					return GL_TEXTURE_2D_ARRAY;
+			}
+		case TEX_TYPE_3D:
+			return GL_TEXTURE_3D;
+		case TEX_TYPE_CUBE_MAP:
+			if (numFaces <= 6)
+				return GL_TEXTURE_CUBE_MAP;
+			else
+				return GL_TEXTURE_CUBE_MAP_ARRAY;
+		default:
+			return 0;
+		};
+	}
+
 	PixelData GLTexture::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx,
 									  UINT32 queueIdx)
 	{

+ 3 - 1
Source/BansheeGLRenderAPI/Source/BsGLTextureView.cpp

@@ -66,7 +66,9 @@ namespace bs { namespace ct {
 
 		glGenTextures(1, &mViewID);
 		glTextureView(mViewID, target, originalTexture, texture->getGLFormat(), desc.mostDetailMip, desc.numMips,
-					  desc.firstArraySlice, desc.numArraySlices);
+			desc.firstArraySlice, desc.numArraySlices);
+
+		mTarget = GLTexture::getGLTextureTarget(props.getTextureType(), props.getNumSamples(), desc.numArraySlices);
 	}
 
 	GLTextureView::~GLTextureView()

+ 283 - 279
Source/BansheeUtility/Include/BsMatrix4.h

@@ -16,18 +16,18 @@ namespace bs
 	 */
 
 	 /** Class representing a 4x4 matrix. */
-    class BS_UTILITY_EXPORT Matrix4
-    {
-    private:
-        union 
+	class BS_UTILITY_EXPORT Matrix4
+	{
+	private:
+		union
 		{
-            float m[4][4];
-            float _m[16];
-        };
+			float m[4][4];
+			float _m[16];
+		};
 
-    public:
-        Matrix4()
-        { }
+	public:
+		Matrix4()
+		{ }
 
 		Matrix4(BS_ZERO zero)
 			:Matrix4(Matrix3::ZERO)
@@ -37,43 +37,43 @@ namespace bs
 			:Matrix4(Matrix3::IDENTITY)
 		{ }
 
-        Matrix4(
-            float m00, float m01, float m02, float m03,
-            float m10, float m11, float m12, float m13,
-            float m20, float m21, float m22, float m23,
-            float m30, float m31, float m32, float m33)
-        {
-            m[0][0] = m00;
-            m[0][1] = m01;
-            m[0][2] = m02;
-            m[0][3] = m03;
-            m[1][0] = m10;
-            m[1][1] = m11;
-            m[1][2] = m12;
-            m[1][3] = m13;
-            m[2][0] = m20;
-            m[2][1] = m21;
-            m[2][2] = m22;
-            m[2][3] = m23;
-            m[3][0] = m30;
-            m[3][1] = m31;
-            m[3][2] = m32;
-            m[3][3] = m33;
-        }
+		Matrix4(
+			float m00, float m01, float m02, float m03,
+			float m10, float m11, float m12, float m13,
+			float m20, float m21, float m22, float m23,
+			float m30, float m31, float m32, float m33)
+		{
+			m[0][0] = m00;
+			m[0][1] = m01;
+			m[0][2] = m02;
+			m[0][3] = m03;
+			m[1][0] = m10;
+			m[1][1] = m11;
+			m[1][2] = m12;
+			m[1][3] = m13;
+			m[2][0] = m20;
+			m[2][1] = m21;
+			m[2][2] = m22;
+			m[2][3] = m23;
+			m[3][0] = m30;
+			m[3][1] = m31;
+			m[3][2] = m32;
+			m[3][3] = m33;
+		}
 
 		Matrix4(const Matrix4& mat)
 		{
-			memcpy(_m, mat._m, 16*sizeof(float));
+			memcpy(_m, mat._m, 16 * sizeof(float));
 		}
 
-        /** Creates a 4x4 transformation matrix with a zero translation part from a rotation/scaling 3x3 matrix. */
-        explicit Matrix4(const Matrix3& mat3)
-        {
+		/** Creates a 4x4 transformation matrix with a zero translation part from a rotation/scaling 3x3 matrix. */
+		explicit Matrix4(const Matrix3& mat3)
+		{
 			m[0][0] = mat3.m[0][0]; m[0][1] = mat3.m[0][1]; m[0][2] = mat3.m[0][2]; m[0][3] = 0.0f;
 			m[1][0] = mat3.m[1][0]; m[1][1] = mat3.m[1][1]; m[1][2] = mat3.m[1][2]; m[1][3] = 0.0f;
 			m[2][0] = mat3.m[2][0]; m[2][1] = mat3.m[2][1]; m[2][2] = mat3.m[2][2]; m[2][3] = 0.0f;
 			m[3][0] = 0.0f; m[3][1] = 0.0f; m[3][2] = 0.0f; m[3][3] = 1.0f;
-        }
+		}
 
 		/** Swaps the contents of this matrix with another. */
 		void swap(Matrix4& other)
@@ -137,95 +137,95 @@ namespace bs
 			r.m[3][3] = m[3][0] * rhs.m[0][3] + m[3][1] * rhs.m[1][3] + m[3][2] * rhs.m[2][3] + m[3][3] * rhs.m[3][3];
 
 			return r;
-        }
-
-        Matrix4 operator+ (const Matrix4 &rhs) const
-        {
-            Matrix4 r;
-
-            r.m[0][0] = m[0][0] + rhs.m[0][0];
-            r.m[0][1] = m[0][1] + rhs.m[0][1];
-            r.m[0][2] = m[0][2] + rhs.m[0][2];
-            r.m[0][3] = m[0][3] + rhs.m[0][3];
-
-            r.m[1][0] = m[1][0] + rhs.m[1][0];
-            r.m[1][1] = m[1][1] + rhs.m[1][1];
-            r.m[1][2] = m[1][2] + rhs.m[1][2];
-            r.m[1][3] = m[1][3] + rhs.m[1][3];
-
-            r.m[2][0] = m[2][0] + rhs.m[2][0];
-            r.m[2][1] = m[2][1] + rhs.m[2][1];
-            r.m[2][2] = m[2][2] + rhs.m[2][2];
-            r.m[2][3] = m[2][3] + rhs.m[2][3];
-
-            r.m[3][0] = m[3][0] + rhs.m[3][0];
-            r.m[3][1] = m[3][1] + rhs.m[3][1];
-            r.m[3][2] = m[3][2] + rhs.m[3][2];
-            r.m[3][3] = m[3][3] + rhs.m[3][3];
-
-            return r;
-        }
-
-        Matrix4 operator- (const Matrix4 &rhs) const
-        {
-            Matrix4 r;
-            r.m[0][0] = m[0][0] - rhs.m[0][0];
-            r.m[0][1] = m[0][1] - rhs.m[0][1];
-            r.m[0][2] = m[0][2] - rhs.m[0][2];
-            r.m[0][3] = m[0][3] - rhs.m[0][3];
-
-            r.m[1][0] = m[1][0] - rhs.m[1][0];
-            r.m[1][1] = m[1][1] - rhs.m[1][1];
-            r.m[1][2] = m[1][2] - rhs.m[1][2];
-            r.m[1][3] = m[1][3] - rhs.m[1][3];
-
-            r.m[2][0] = m[2][0] - rhs.m[2][0];
-            r.m[2][1] = m[2][1] - rhs.m[2][1];
-            r.m[2][2] = m[2][2] - rhs.m[2][2];
-            r.m[2][3] = m[2][3] - rhs.m[2][3];
-
-            r.m[3][0] = m[3][0] - rhs.m[3][0];
-            r.m[3][1] = m[3][1] - rhs.m[3][1];
-            r.m[3][2] = m[3][2] - rhs.m[3][2];
-            r.m[3][3] = m[3][3] - rhs.m[3][3];
-
-            return r;
-        }
-
-        inline bool operator== (const Matrix4& rhs ) const
-        {
-            if(m[0][0] != rhs.m[0][0] || m[0][1] != rhs.m[0][1] || m[0][2] != rhs.m[0][2] || m[0][3] != rhs.m[0][3] ||
-               m[1][0] != rhs.m[1][0] || m[1][1] != rhs.m[1][1] || m[1][2] != rhs.m[1][2] || m[1][3] != rhs.m[1][3] ||
-               m[2][0] != rhs.m[2][0] || m[2][1] != rhs.m[2][1] || m[2][2] != rhs.m[2][2] || m[2][3] != rhs.m[2][3] ||
-               m[3][0] != rhs.m[3][0] || m[3][1] != rhs.m[3][1] || m[3][2] != rhs.m[3][2] || m[3][3] != rhs.m[3][3] )
+		}
+
+		Matrix4 operator+ (const Matrix4 &rhs) const
+		{
+			Matrix4 r;
+
+			r.m[0][0] = m[0][0] + rhs.m[0][0];
+			r.m[0][1] = m[0][1] + rhs.m[0][1];
+			r.m[0][2] = m[0][2] + rhs.m[0][2];
+			r.m[0][3] = m[0][3] + rhs.m[0][3];
+
+			r.m[1][0] = m[1][0] + rhs.m[1][0];
+			r.m[1][1] = m[1][1] + rhs.m[1][1];
+			r.m[1][2] = m[1][2] + rhs.m[1][2];
+			r.m[1][3] = m[1][3] + rhs.m[1][3];
+
+			r.m[2][0] = m[2][0] + rhs.m[2][0];
+			r.m[2][1] = m[2][1] + rhs.m[2][1];
+			r.m[2][2] = m[2][2] + rhs.m[2][2];
+			r.m[2][3] = m[2][3] + rhs.m[2][3];
+
+			r.m[3][0] = m[3][0] + rhs.m[3][0];
+			r.m[3][1] = m[3][1] + rhs.m[3][1];
+			r.m[3][2] = m[3][2] + rhs.m[3][2];
+			r.m[3][3] = m[3][3] + rhs.m[3][3];
+
+			return r;
+		}
+
+		Matrix4 operator- (const Matrix4 &rhs) const
+		{
+			Matrix4 r;
+			r.m[0][0] = m[0][0] - rhs.m[0][0];
+			r.m[0][1] = m[0][1] - rhs.m[0][1];
+			r.m[0][2] = m[0][2] - rhs.m[0][2];
+			r.m[0][3] = m[0][3] - rhs.m[0][3];
+
+			r.m[1][0] = m[1][0] - rhs.m[1][0];
+			r.m[1][1] = m[1][1] - rhs.m[1][1];
+			r.m[1][2] = m[1][2] - rhs.m[1][2];
+			r.m[1][3] = m[1][3] - rhs.m[1][3];
+
+			r.m[2][0] = m[2][0] - rhs.m[2][0];
+			r.m[2][1] = m[2][1] - rhs.m[2][1];
+			r.m[2][2] = m[2][2] - rhs.m[2][2];
+			r.m[2][3] = m[2][3] - rhs.m[2][3];
+
+			r.m[3][0] = m[3][0] - rhs.m[3][0];
+			r.m[3][1] = m[3][1] - rhs.m[3][1];
+			r.m[3][2] = m[3][2] - rhs.m[3][2];
+			r.m[3][3] = m[3][3] - rhs.m[3][3];
+
+			return r;
+		}
+
+		inline bool operator== (const Matrix4& rhs) const
+		{
+			if (m[0][0] != rhs.m[0][0] || m[0][1] != rhs.m[0][1] || m[0][2] != rhs.m[0][2] || m[0][3] != rhs.m[0][3] ||
+				m[1][0] != rhs.m[1][0] || m[1][1] != rhs.m[1][1] || m[1][2] != rhs.m[1][2] || m[1][3] != rhs.m[1][3] ||
+				m[2][0] != rhs.m[2][0] || m[2][1] != rhs.m[2][1] || m[2][2] != rhs.m[2][2] || m[2][3] != rhs.m[2][3] ||
+				m[3][0] != rhs.m[3][0] || m[3][1] != rhs.m[3][1] || m[3][2] != rhs.m[3][2] || m[3][3] != rhs.m[3][3])
 			{
-                return false;
+				return false;
 			}
 
-            return true;
-        }
+			return true;
+		}
 
-        inline bool operator!= (const Matrix4& rhs) const
-        {
-            return !operator==(rhs);
-        }
+		inline bool operator!= (const Matrix4& rhs) const
+		{
+			return !operator==(rhs);
+		}
 
 		Matrix4 operator*(float rhs) const
 		{
 			return Matrix4(rhs*m[0][0], rhs*m[0][1], rhs*m[0][2], rhs*m[0][3],
-						   rhs*m[1][0], rhs*m[1][1], rhs*m[1][2], rhs*m[1][3],
-						   rhs*m[2][0], rhs*m[2][1], rhs*m[2][2], rhs*m[2][3],
-						   rhs*m[3][0], rhs*m[3][1], rhs*m[3][2], rhs*m[3][3]);
+				rhs*m[1][0], rhs*m[1][1], rhs*m[1][2], rhs*m[1][3],
+				rhs*m[2][0], rhs*m[2][1], rhs*m[2][2], rhs*m[2][3],
+				rhs*m[3][0], rhs*m[3][1], rhs*m[3][2], rhs*m[3][3]);
 		}
 
-        /** Returns a transpose of the matrix (switched columns and rows). */
-        Matrix4 transpose() const
-        {
-            return Matrix4(m[0][0], m[1][0], m[2][0], m[3][0],
-                           m[0][1], m[1][1], m[2][1], m[3][1],
-                           m[0][2], m[1][2], m[2][2], m[3][2],
-                           m[0][3], m[1][3], m[2][3], m[3][3]);
-        }
+		/** Returns a transpose of the matrix (switched columns and rows). */
+		Matrix4 transpose() const
+		{
+			return Matrix4(m[0][0], m[1][0], m[2][0], m[3][0],
+				m[0][1], m[1][1], m[2][1], m[3][1],
+				m[0][2], m[1][2], m[2][2], m[3][2],
+				m[0][3], m[1][3], m[2][3], m[3][3]);
+		}
 
 		/** Assigns the vector to a column of the matrix. */
 		void setColumn(UINT32 idx, const Vector4& column)
@@ -245,19 +245,19 @@ namespace bs
 			m[idx][3] = column.w;
 		}
 
-        /** Extracts the rotation/scaling part of the matrix as a 3x3 matrix. */
-        void extract3x3Matrix(Matrix3& m3x3) const
-        {
-            m3x3.m[0][0] = m[0][0];
-            m3x3.m[0][1] = m[0][1];
-            m3x3.m[0][2] = m[0][2];
-            m3x3.m[1][0] = m[1][0];
-            m3x3.m[1][1] = m[1][1];
-            m3x3.m[1][2] = m[1][2];
-            m3x3.m[2][0] = m[2][0];
-            m3x3.m[2][1] = m[2][1];
-            m3x3.m[2][2] = m[2][2];
-        }
+		/** Extracts the rotation/scaling part of the matrix as a 3x3 matrix. */
+		void extract3x3Matrix(Matrix3& m3x3) const
+		{
+			m3x3.m[0][0] = m[0][0];
+			m3x3.m[0][1] = m[0][1];
+			m3x3.m[0][2] = m[0][2];
+			m3x3.m[1][0] = m[1][0];
+			m3x3.m[1][1] = m[1][1];
+			m3x3.m[1][2] = m[1][2];
+			m3x3.m[2][0] = m[2][0];
+			m3x3.m[2][1] = m[2][1];
+			m3x3.m[2][2] = m[2][2];
+		}
 
 		/** Calculates the adjoint of the matrix. */
 		Matrix4 adjoint() const;
@@ -270,86 +270,86 @@ namespace bs
 
 		/** Calculates the inverse of the matrix. */
 		Matrix4 inverse() const;
-        
-        /**
-         * Creates a matrix from translation, rotation and scale. 
-         * 			
+
+		/**
+		 * Creates a matrix from translation, rotation and scale.
+		 *
 		 * @note	The transformation are applied in scale->rotation->translation order.
-         */
-        void setTRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale);
+		 */
+		void setTRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale);
 
-        /**
-         * Creates a matrix from inverse translation, rotation and scale. 
-         * 			
+		/**
+		 * Creates a matrix from inverse translation, rotation and scale.
+		 *
 		 * @note	This is cheaper than setTRS() and then performing inverse().
-         */
-        void setInverseTRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale);
+		 */
+		void setInverseTRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale);
 
-        /**
-         * Decompose a Matrix4 to translation, rotation and scale.
-         *
-         * @note	
+		/**
+		 * Decompose a Matrix4 to translation, rotation and scale.
+		 *
+		 * @note
 		 * Matrix must consist only of translation, rotation and uniform scale transformations,
-         * otherwise accurate results are not guaranteed. Applying non-uniform scale guarantees
-         * results will not be accurate.
-         */
-        void decomposition(Vector3& position, Quaternion& rotation, Vector3& scale) const;
+		 * otherwise accurate results are not guaranteed. Applying non-uniform scale guarantees
+		 * results will not be accurate.
+		 */
+		void decomposition(Vector3& position, Quaternion& rotation, Vector3& scale) const;
 
 		/** Extracts the translation (position) part of the matrix. */
 		Vector3 getTranslation() const { return Vector3(m[0][3], m[1][3], m[2][3]); }
 
-        /**
+		/**
 		 * Check whether or not the matrix is affine matrix.
 		 *
 		 * @note	An affine matrix is a 4x4 matrix with row 3 equal to (0, 0, 0, 1), meaning no projective coefficients.
-         */
-        bool isAffine() const
-        {
-            return m[3][0] == 0 && m[3][1] == 0 && m[3][2] == 0 && m[3][3] == 1;
-        }
-
-        /**
-         * Returns the inverse of the affine matrix.
-         *
-         * @note	Matrix must be affine.
-         */
-        Matrix4 inverseAffine() const;
-
-        /**
-         * Concatenate two affine matrices.
-         *
-         * @note	Both matrices must be affine.
-         */
-        Matrix4 concatenateAffine(const Matrix4 &other) const
-        {
-            BS_ASSERT(isAffine() && other.isAffine());
-
-            return Matrix4(
-                m[0][0] * other.m[0][0] + m[0][1] * other.m[1][0] + m[0][2] * other.m[2][0],
-                m[0][0] * other.m[0][1] + m[0][1] * other.m[1][1] + m[0][2] * other.m[2][1],
-                m[0][0] * other.m[0][2] + m[0][1] * other.m[1][2] + m[0][2] * other.m[2][2],
-                m[0][0] * other.m[0][3] + m[0][1] * other.m[1][3] + m[0][2] * other.m[2][3] + m[0][3],
-
-                m[1][0] * other.m[0][0] + m[1][1] * other.m[1][0] + m[1][2] * other.m[2][0],
-                m[1][0] * other.m[0][1] + m[1][1] * other.m[1][1] + m[1][2] * other.m[2][1],
-                m[1][0] * other.m[0][2] + m[1][1] * other.m[1][2] + m[1][2] * other.m[2][2],
-                m[1][0] * other.m[0][3] + m[1][1] * other.m[1][3] + m[1][2] * other.m[2][3] + m[1][3],
-
-                m[2][0] * other.m[0][0] + m[2][1] * other.m[1][0] + m[2][2] * other.m[2][0],
-                m[2][0] * other.m[0][1] + m[2][1] * other.m[1][1] + m[2][2] * other.m[2][1],
-                m[2][0] * other.m[0][2] + m[2][1] * other.m[1][2] + m[2][2] * other.m[2][2],
-                m[2][0] * other.m[0][3] + m[2][1] * other.m[1][3] + m[2][2] * other.m[2][3] + m[2][3],
-
-                0, 0, 0, 1);
-        }
-
-        /**
-         * Transform a plane by this matrix.
-         * 			
-         * @note	Matrix must be affine.
-         */
-        Plane multiplyAffine(const Plane& p) const
-        {
+		 */
+		bool isAffine() const
+		{
+			return m[3][0] == 0 && m[3][1] == 0 && m[3][2] == 0 && m[3][3] == 1;
+		}
+
+		/**
+		 * Returns the inverse of the affine matrix.
+		 *
+		 * @note	Matrix must be affine.
+		 */
+		Matrix4 inverseAffine() const;
+
+		/**
+		 * Concatenate two affine matrices.
+		 *
+		 * @note	Both matrices must be affine.
+		 */
+		Matrix4 concatenateAffine(const Matrix4 &other) const
+		{
+			BS_ASSERT(isAffine() && other.isAffine());
+
+			return Matrix4(
+				m[0][0] * other.m[0][0] + m[0][1] * other.m[1][0] + m[0][2] * other.m[2][0],
+				m[0][0] * other.m[0][1] + m[0][1] * other.m[1][1] + m[0][2] * other.m[2][1],
+				m[0][0] * other.m[0][2] + m[0][1] * other.m[1][2] + m[0][2] * other.m[2][2],
+				m[0][0] * other.m[0][3] + m[0][1] * other.m[1][3] + m[0][2] * other.m[2][3] + m[0][3],
+
+				m[1][0] * other.m[0][0] + m[1][1] * other.m[1][0] + m[1][2] * other.m[2][0],
+				m[1][0] * other.m[0][1] + m[1][1] * other.m[1][1] + m[1][2] * other.m[2][1],
+				m[1][0] * other.m[0][2] + m[1][1] * other.m[1][2] + m[1][2] * other.m[2][2],
+				m[1][0] * other.m[0][3] + m[1][1] * other.m[1][3] + m[1][2] * other.m[2][3] + m[1][3],
+
+				m[2][0] * other.m[0][0] + m[2][1] * other.m[1][0] + m[2][2] * other.m[2][0],
+				m[2][0] * other.m[0][1] + m[2][1] * other.m[1][1] + m[2][2] * other.m[2][1],
+				m[2][0] * other.m[0][2] + m[2][1] * other.m[1][2] + m[2][2] * other.m[2][2],
+				m[2][0] * other.m[0][3] + m[2][1] * other.m[1][3] + m[2][2] * other.m[2][3] + m[2][3],
+
+				0, 0, 0, 1);
+		}
+
+		/**
+		 * Transform a plane by this matrix.
+		 *
+		 * @note	Matrix must be affine.
+		 */
+		Plane multiplyAffine(const Plane& p) const
+		{
 			Vector4 localNormal(p.normal.x, p.normal.y, p.normal.z, 0.0f);
 			Vector4 localPoint = localNormal * p.d;
 			localPoint.w = 1.0f;
@@ -361,85 +361,89 @@ namespace bs
 			float d = worldNormal.dot(worldPoint);
 
 			return Plane(worldNormal.x, worldNormal.y, worldNormal.z, d);
-        }
-
-        /**
-         * Transform a 3D point by this matrix.
-         * 			
-         * @note	Matrix must be affine, if it is not use multiply() method.
-         */
-        Vector3 multiplyAffine(const Vector3& v) const
-        {
-            return Vector3(
-                    m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3], 
-                    m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3],
-                    m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3]);
-        }
-
-        /**
-         * Transform a 4D vector by this matrix.
-         * 			
-         * @note	Matrix must be affine, if it is not use multiply() method.
-         */
-        Vector4 multiplyAffine(const Vector4& v) const
-        {
-            return Vector4(
-                m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * v.w, 
-                m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * v.w,
-                m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] * v.w,
-                v.w);
-        }
+		}
+
+		/**
+		 * Transform a 3D point by this matrix.
+		 *
+		 * @note	Matrix must be affine, if it is not use multiply() method.
+		 */
+		Vector3 multiplyAffine(const Vector3& v) const
+		{
+			return Vector3(
+				m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3],
+				m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3],
+				m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3]);
+		}
+
+		/**
+		 * Transform a 4D vector by this matrix.
+		 *
+		 * @note	Matrix must be affine, if it is not use multiply() method.
+		 */
+		Vector4 multiplyAffine(const Vector4& v) const
+		{
+			return Vector4(
+				m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * v.w,
+				m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * v.w,
+				m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] * v.w,
+				v.w);
+		}
 
 		/** Transform a 3D direction by this matrix. */
-        Vector3 multiplyDirection(const Vector3& v) const
-        {
-            return Vector3(
-                    m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z, 
-                    m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z,
-                    m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z);
-        }
-
-        /**
-         * Transform a 3D point by this matrix.  
-         *
-         * @note	
+		Vector3 multiplyDirection(const Vector3& v) const
+		{
+			return Vector3(
+				m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z,
+				m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z,
+				m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z);
+		}
+
+		/**
+		 * Transform a 3D point by this matrix.
+		 *
+		 * @note
 		 * w component of the vector is assumed to be 1. After transformation all components
-         * are projected back so that w remains 1.
-         * @note
+		 * are projected back so that w remains 1.
+		 * @note
 		 * If your matrix doesn't contain projection components use multiplyAffine() method as it is faster.
-         */
-        Vector3 multiply(const Vector3& v) const
-        {
-            Vector3 r(BsZero);
-
-            float fInvW = 1.0f / (m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3]);
-
-            r.x = (m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3]) * fInvW;
-            r.y = (m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3]) * fInvW;
-            r.z = (m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3]) * fInvW;
-
-            return r;
-        }
-
-        /**
-         * Transform a 4D vector by this matrix.  
-         *
-         * @note	If your matrix doesn't contain projection components use multiplyAffine() method as it is faster.
-         */
-        Vector4 multiply(const Vector4& v) const
-        {
-            return Vector4(
-                m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * v.w, 
-                m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * v.w,
-                m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] * v.w,
-                m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3] * v.w
-                );
-        }
+		 */
+		Vector3 multiply(const Vector3& v) const
+		{
+			Vector3 r(BsZero);
+
+			float fInvW = 1.0f / (m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3]);
+
+			r.x = (m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3]) * fInvW;
+			r.y = (m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3]) * fInvW;
+			r.z = (m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3]) * fInvW;
+
+			return r;
+		}
+
+		/**
+		 * Transform a 4D vector by this matrix.
+		 *
+		 * @note	If your matrix doesn't contain projection components use multiplyAffine() method as it is faster.
+		 */
+		Vector4 multiply(const Vector4& v) const
+		{
+			return Vector4(
+				m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * v.w,
+				m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * v.w,
+				m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] * v.w,
+				m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3] * v.w
+			);
+		}
 
 		/** Creates a view matrix and applies optional reflection. */
 		void makeView(const Vector3& position, const Quaternion& orientation);
 
-		/** Creates an ortographic projection matrix. */
+		/** 
+		 * Creates an ortographic projection matrix that scales the part of the view bounded by @p left, @p right, 
+		 * @p top and @p bottom into [-1, 1] range. If @p far is non-zero the matrix will also transform the depth into
+		 * [-1, 1] range, otherwise it will leave it as-is.
+		 */
 		void makeProjectionOrtho(float left, float right, float top, float bottom, float near, float far);
 
 		/** Creates a 4x4 transformation matrix that performs translation. */
@@ -457,29 +461,29 @@ namespace bs
 		/** Creates a 4x4 perspective projection matrix. */
 		static Matrix4 projectionPerspective(const Degree& horzFOV, float aspect, float near, float far);
 
-		/** Creates a 4x4 ortographic projection matrix. */
+		/** @copydoc makeProjectionOrtho() */
 		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);
 
-        /**
-         * Creates a matrix from translation, rotation and scale. 
-         * 			
+		/**
+		 * Creates a matrix from translation, rotation and scale.
+		 *
 		 * @note	The transformation are applied in scale->rotation->translation order.
-         */
+		 */
 		static Matrix4 TRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale);
 
-        /**
-         * Creates a matrix from inverse translation, rotation and scale. 
-         * 			
+		/**
+		 * Creates a matrix from inverse translation, rotation and scale.
+		 *
 		 * @note	This is cheaper than setTRS() and then performing inverse().
-         */
+		 */
 		static Matrix4 inverseTRS(const Vector3& translation, const Quaternion& rotation, const Vector3& scale);
 
 		static const Matrix4 ZERO;
 		static const Matrix4 IDENTITY;
-    };
+	};
 
 	/** @} */
 

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

@@ -277,8 +277,17 @@ namespace bs
 
 		m[2][0] = 0.0f;
 		m[2][1] = 0.0f;
-		m[2][2] = -2.0F / deltaZ;
-		m[2][3] = -(far + near) / deltaZ;
+
+		if (far == 0.0f)
+		{
+			m[2][2] = 1.0f;
+			m[2][3] = 0.0f;
+		}
+		else
+		{
+			m[2][2] = -2.0F / deltaZ;
+			m[2][3] = -(far + near) / deltaZ;
+		}
 
 		m[3][0] = 0.0f;
 		m[3][1] = 0.0f;

+ 57 - 46
Source/RenderBeast/Source/BsShadowRendering.cpp

@@ -191,47 +191,6 @@ namespace bs { namespace ct
 		defines.set("MSAA_COUNT", MSAA ? 2 : 1); // Actual count doesn't matter, as long as its >1 if enabled
 	}
 
-	/**
-	 * Converts a point in mixed space (clip_x, clip_y, view_z, view_w) to UV coordinates on a shadow map (x, y),
-	 * and normalized linear depth from the shadow caster's perspective (z).
-	 */
-	Matrix4 createMixedToShadowUVMatrix(const Matrix4& viewP, const Matrix4& viewInvVP, const Rect2& shadowMapArea,
-		float depthRange, const Matrix4& shadowViewProj)
-	{
-		// Projects a point from (clip_x, clip_y, view_z, view_w) into clip space
-		Matrix4 mixedToShadow = Matrix4::IDENTITY;
-		mixedToShadow[2][2] = viewP[2][2];
-		mixedToShadow[2][3] = viewP[2][3];
-		mixedToShadow[3][2] = viewP[3][2];
-		mixedToShadow[3][3] = 0.0f;
-
-		// Projects a point in clip space back to homogeneus world space
-		mixedToShadow = viewInvVP * mixedToShadow;
-
-		// Projects a point in world space to shadow clip space
-		mixedToShadow = shadowViewProj * mixedToShadow;
-		
-		// Convert shadow clip space coordinates to UV coordinates relative to the shadow map rectangle, and normalize
-		// depth
-		RenderAPI& rapi = RenderAPI::instance();
-		const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
-
-		float flipY = -1.0f;
-		// Either of these flips the Y axis, but if they're both true they cancel out
-		if (rapiInfo.isFlagSet(RenderAPIFeatureFlag::UVYAxisUp) ^ rapiInfo.isFlagSet(RenderAPIFeatureFlag::NDCYAxisDown))
-			flipY = -flipY;
-
-		Matrix4 shadowMapTfrm
-		(
-			shadowMapArea.width * 0.5f, 0, 0, shadowMapArea.x + 0.5f * shadowMapArea.width,
-			0, flipY * shadowMapArea.height * 0.5f, 0, shadowMapArea.y + 0.5f * shadowMapArea.height,
-			0, 0, 1.0f / depthRange, 0,
-			0, 0, 0, 1
-		);
-
-		return shadowMapTfrm * mixedToShadow;
-	}
-
 	template <int ShadowQuality, bool Directional, bool MSAA>
 	void ShadowProjectMat<ShadowQuality, Directional, MSAA>::bind(const ShadowProjectParams& params)
 	{
@@ -752,6 +711,47 @@ namespace bs { namespace ct
 		return output;
 	}
 
+	/**
+	 * Converts a point in mixed space (clip_x, clip_y, view_z, view_w) to UV coordinates on a shadow map (x, y),
+	 * and normalized linear depth from the shadow caster's perspective (z).
+	 */
+	Matrix4 createMixedToShadowUVMatrix(const Matrix4& viewP, const Matrix4& viewInvVP, const Rect2& shadowMapArea,
+		float depthScale, float depthOffset, const Matrix4& shadowViewProj)
+	{
+		// Projects a point from (clip_x, clip_y, view_z, view_w) into clip space
+		Matrix4 mixedToShadow = Matrix4::IDENTITY;
+		mixedToShadow[2][2] = viewP[2][2];
+		mixedToShadow[2][3] = viewP[2][3];
+		mixedToShadow[3][2] = viewP[3][2];
+		mixedToShadow[3][3] = 0.0f;
+
+		// Projects a point in clip space back to homogeneus world space
+		mixedToShadow = viewInvVP * mixedToShadow;
+
+		// Projects a point in world space to shadow clip space
+		mixedToShadow = shadowViewProj * mixedToShadow;
+		
+		// Convert shadow clip space coordinates to UV coordinates relative to the shadow map rectangle, and normalize
+		// depth
+		RenderAPI& rapi = RenderAPI::instance();
+		const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
+
+		float flipY = -1.0f;
+		// Either of these flips the Y axis, but if they're both true they cancel out
+		if (rapiInfo.isFlagSet(RenderAPIFeatureFlag::UVYAxisUp) ^ rapiInfo.isFlagSet(RenderAPIFeatureFlag::NDCYAxisDown))
+			flipY = -flipY;
+
+		Matrix4 shadowMapTfrm
+		(
+			shadowMapArea.width * 0.5f, 0, 0, shadowMapArea.x + 0.5f * shadowMapArea.width,
+			0, flipY * shadowMapArea.height * 0.5f, 0, shadowMapArea.y + 0.5f * shadowMapArea.height,
+			0, 0, depthScale, depthOffset,
+			0, 0, 0, 1
+		);
+
+		return shadowMapTfrm * mixedToShadow;
+	}
+
 	void ShadowRendering::renderShadowOcclusion(const RendererScene& scene, UINT32 shadowQuality, 
 		const RendererLight& rendererLight, UINT32 viewIdx)
 	{
@@ -767,6 +767,7 @@ namespace bs { namespace ct
 		SPtr<GpuParamBlockBuffer> perViewBuffer = view->getPerViewBuffer();
 
 		RenderAPI& rapi = RenderAPI::instance();
+		const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
 		// TODO - Calculate and set a scissor rectangle for the light
 
 		SPtr<GpuParamBlockBuffer> shadowParamBuffer = gShadowProjectParamsDef.createBuffer();
@@ -845,14 +846,23 @@ namespace bs { namespace ct
 
 			for(auto& shadowInfo : shadowInfos)
 			{
-				float depthRange = shadowInfo->depthRange;
+				float depthScale, depthOffset;
 
-				// Depth range scale is already baked into the ortho projection matrix, no avoid doing it here
+				// Depth range scale is already baked into the ortho projection matrix, so avoid doing it here
 				if (isCSM)
-					depthRange = 1.0f;
+				{
+					// Need to map from NDC depth to [0, 1]
+					depthScale = 1.0f / (rapiInfo.getMaximumDepthInputValue() - rapiInfo.getMinimumDepthInputValue());
+					depthOffset = -rapiInfo.getMinimumDepthInputValue() * depthScale;
+				}
+				else
+				{
+					depthScale = 1.0f / shadowInfo->depthRange;
+					depthOffset = 0.0f;
+				}
 
 				Matrix4 mixedToShadowUV = createMixedToShadowUVMatrix(viewP, viewInvVP, shadowInfo->normArea, 
-					depthRange, shadowInfo->shadowVPTransform);
+					depthScale, depthOffset, shadowInfo->shadowVPTransform);
 
 				Vector2 shadowMapSize((float)shadowInfo->area.width, (float)shadowInfo->area.height);
 				float transitionScale = getFadeTransition(*light, shadowInfo->subjectBounds.getRadius(), 
@@ -942,7 +952,7 @@ namespace bs { namespace ct
 		Light* light = rendererLight.internal;
 
 		RenderAPI& rapi = RenderAPI::instance();
-	const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
+		const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
 
 		Vector3 lightDir = -light->getRotation().zAxis();
 		SPtr<GpuParamBlockBuffer> shadowParamsBuffer = gShadowParamsDef.createBuffer();
@@ -1001,6 +1011,7 @@ namespace bs { namespace ct
 			float orthoSize = frustumBounds.getRadius() * 0.5f;
 			Matrix4 proj = Matrix4::projectionOrthographic(-orthoSize, orthoSize, orthoSize, -orthoSize, 0.0f, 
 				shadowInfo.depthRange);
+
 			RenderAPI::instance().convertProjectionMatrix(proj, proj);
 
 			shadowInfo.cascadeIdx = i;