/// <summary>
        /// Determines the size of the frustum needed to cover the viewable area,
        /// then creates an appropriate orthographic projection.
        /// </summary>
        /// <param name="light">The directional light to use</param>
        /// <param name="mainCamera">The camera viewing the scene</param>
        protected MyOrthographicCamera CalculateFrustum(MyOrthographicCamera lightCamera, MyPerspectiveCamera mainCamera, float minZ, float maxZ)
        {
            // Shorten the view frustum according to the shadow view distance
            Matrix cameraMatrix;
            mainCamera.GetWorldMatrix(out cameraMatrix);

            Matrix.CreatePerspectiveFieldOfView(mainCamera.FieldOfView, mainCamera.AspectRatio, minZ, maxZ, out lightCamera.CameraSubfrustum);
            Matrix wma;
            mainCamera.GetViewMatrix(out wma);
            lightCamera.CameraSubfrustum = MyCamera.ViewMatrix * lightCamera.CameraSubfrustum;

            for (int i = 0; i < 4; i++)
                m_splitFrustumCornersVS[i] = m_frustumCornersVS[i + 4] * (minZ / mainCamera.FarClip);

            for (int i = 4; i < 8; i++)
                m_splitFrustumCornersVS[i] = m_frustumCornersVS[i] * (maxZ / mainCamera.FarClip);

            Vector3.Transform(m_splitFrustumCornersVS, ref cameraMatrix, m_frustumCornersWS);

            // Position the shadow-caster camera so that it's looking at the centroid,
            // and backed up in the direction of the sunlight

            //Toto se nemeni per frame!
            Matrix viewMatrix = Matrix.CreateLookAt(Vector3.Zero - (m_sunLightDirection * mainCamera.FarClip), Vector3.Zero, new Vector3(0, 1, 0));

            // Determine the position of the frustum corners in light space
            Vector3.Transform(m_frustumCornersWS, ref viewMatrix, m_frustumCornersLS);

            // Calculate an orthographic projection by sizing a bounding box
            // to the frustum coordinates in light space
            Vector3 mins = m_frustumCornersLS[0];
            Vector3 maxes = m_frustumCornersLS[0];
            for (int i = 0; i < 8; i++)
            {
                if (m_frustumCornersLS[i].X > maxes.X)
                    maxes.X = m_frustumCornersLS[i].X;
                else if (m_frustumCornersLS[i].X < mins.X)
                    mins.X = m_frustumCornersLS[i].X;
                if (m_frustumCornersLS[i].Y > maxes.Y)
                    maxes.Y = m_frustumCornersLS[i].Y;
                else if (m_frustumCornersLS[i].Y < mins.Y)
                    mins.Y = m_frustumCornersLS[i].Y;
                if (m_frustumCornersLS[i].Z > maxes.Z)
                    maxes.Z = m_frustumCornersLS[i].Z;
                else if (m_frustumCornersLS[i].Z < mins.Z)
                    mins.Z = m_frustumCornersLS[i].Z;
            }

            // Update an orthographic camera for collision detection
            lightCamera.UpdateUnscaled(mins.X, maxes.X, mins.Y, maxes.Y, -maxes.Z - SHADOW_MAX_OFFSET, -mins.Z);
            lightCamera.SetViewMatrixUnscaled(ref viewMatrix);

            // We snap the camera to 1 pixel increments so that moving the camera does not cause the shadows to jitter.
            // This is a matter of integer dividing by the world space size of a texel
            float diagonalLength = (m_frustumCornersWS[0] - m_frustumCornersWS[6]).Length();

            //Make bigger box - ensure rotation and movement stabilization
            diagonalLength = MyMath.GetNearestBiggerPowerOfTwo(diagonalLength);

            float worldsUnitsPerTexel = diagonalLength / (float)ShadowMapCascadeSize;

            Vector3 vBorderOffset = (new Vector3(diagonalLength, diagonalLength, diagonalLength) - (maxes - mins)) * 0.5f;
            maxes += vBorderOffset;
            mins -= vBorderOffset;

            mins /= worldsUnitsPerTexel;
            mins.X = (float)Math.Floor(mins.X);
            mins.Y = (float)Math.Floor(mins.Y);
            mins.Z = (float)Math.Floor(mins.Z);
            mins *= worldsUnitsPerTexel;

            maxes /= worldsUnitsPerTexel;
            maxes.X = (float)Math.Floor(maxes.X);
            maxes.Y = (float)Math.Floor(maxes.Y);
            maxes.Z = (float)Math.Floor(maxes.Z);
            maxes *= worldsUnitsPerTexel;


            /*
            Matrix proj;
            Matrix.CreateOrthographicOffCenter(mins.X, maxes.X, mins.Y, maxes.Y, -maxes.Z - SHADOW_MAX_OFFSET, -mins.Z, out proj);
            
            if (MyUtils.IsEqual(lightCamera.ProjectionMatrix, proj))
            {   //cache
                return null;
            } */


            // Update an orthographic camera for use as a shadow caster
            lightCamera.Update(mins.X, maxes.X, mins.Y, maxes.Y, -maxes.Z - SHADOW_MAX_OFFSET, -mins.Z);


            lightCamera.SetViewMatrix(ref viewMatrix);

            return lightCamera;
        }
        /// <summary>
        /// Creates the renderer
        /// </summary>
        /// <param name="graphicsDevice">The GraphicsDevice to use for rendering</param>
        /// <param name="contentManager">The MyCustomContentManager to use for loading content</param>
        public MyShadowRenderer(int shadowMapSize, MyRenderTargets renderTarget, MyRenderTargets depthTarget, bool multiThreaded)
        {
            ShadowMapCascadeSize = shadowMapSize;
            m_shadowRenderTarget = renderTarget;
            m_shadowDepthTarget = depthTarget;

            for (int i = 0; i < NumSplits; i++)
            {
                m_lightCameras[i] = new MyOrthographicCamera(1, 1, 1, 10);
                // Occ queries for shadows are disabled, so save memory by commenting this
                //m_occlusionQueriesLists[i] = new List<MyOcclusionQueryIssue>(1024);
                m_cascadeQueries[i] = new MyOcclusionQueryIssue(null);
                m_visibility[i] = true;
            }

            MultiThreaded = multiThreaded;

            if (MyRenderConstants.RenderQualityProfile.ForwardRender)
                MultiThreaded = false;
        }