public ShadowRenderer(Renderer renderer)
 {
     //create the render targets
     for (int i = 0; i < NUM_SPOT_SHADOWS; i++)
     {
         SpotShadowMapEntry entry = new SpotShadowMapEntry();
         //we store the linear depth, in a float render target. We need also the HW zbuffer
         entry.Texture = new RenderTarget2D(renderer.GraphicsDevice, SPOT_SHADOW_RESOLUTION,
                                            SPOT_SHADOW_RESOLUTION, false, SurfaceFormat.Single,
                                            DepthFormat.Depth24Stencil8, 0, RenderTargetUsage.DiscardContents);
         entry.LightViewProjection = Matrix.Identity;
         _spotShadowMaps.Add(entry);
     }
     for (int i = 0; i < NUM_CSM_SHADOWS; i++)
     {
         CascadeShadowMapEntry entry = new CascadeShadowMapEntry();
         entry.Texture = new RenderTarget2D(renderer.GraphicsDevice, CASCADE_SHADOW_RESOLUTION * NUM_CSM_SPLITS,
                                            CASCADE_SHADOW_RESOLUTION, false, SurfaceFormat.Single,
                                            DepthFormat.Depth24Stencil8, 0, RenderTargetUsage.DiscardContents);
         _cascadeShadowMaps.Add(entry);
     }
 }
        public void GenerateShadowTextureDirectionalLight(Renderer renderer, object[] meshes, object[] InstancedMeshes, Light light, CascadeShadowMapEntry cascadeShadowMap, Camera.Camera camera)
        {
            //bind the render target
            renderer.GraphicsDevice.SetRenderTarget(cascadeShadowMap.Texture);
            //clear it to white, ie, far far away
            renderer.GraphicsDevice.Clear(Color.White);
            renderer.GraphicsDevice.BlendState = BlendState.Opaque;
            renderer.GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            // Get the corners of the frustum
            camera.Frustum.GetCorners(frustumCornersWS);
            Matrix eyeTransform = camera.View;
            Vector3.Transform(frustumCornersWS, ref eyeTransform, frustumCornersVS);

            float near = camera.NearPlane, far = MathHelper.Min(camera.FarPlane, light.ShadowDistance);

            splitDepthsTmp[0] = near;
            splitDepthsTmp[NUM_CSM_SPLITS] = far;

            //compute each distance the way you like...
            for (int i = 1; i < splitDepthsTmp.Length - 1; i++)
                splitDepthsTmp[i] = near + (far - near) * (float)Math.Pow((i / (float)NUM_CSM_SPLITS), 3);

            Viewport splitViewport = new Viewport();
            Vector3 lightDir = -Vector3.Normalize(light.Transform.Forward);

            BoundingFrustum frustum = new BoundingFrustum(Matrix.Identity);

            for (int i = 0; i < NUM_CSM_SPLITS; i++)
            {
                cascadeShadowMap.LightClipPlanes[i].X = -splitDepthsTmp[i];
                cascadeShadowMap.LightClipPlanes[i].Y = -splitDepthsTmp[i + 1];

                cascadeShadowMap.LightViewProjectionMatrices[i] = CreateLightViewProjectionMatrix(lightDir, far, camera, splitDepthsTmp[i], splitDepthsTmp[i + 1], i);
                Matrix viewProj = cascadeShadowMap.LightViewProjectionMatrices[i];

                // Set the viewport for the current split
                splitViewport.MinDepth = 0;
                splitViewport.MaxDepth = 1;
                splitViewport.Width = CASCADE_SHADOW_RESOLUTION;
                splitViewport.Height = CASCADE_SHADOW_RESOLUTION;
                splitViewport.X = i * CASCADE_SHADOW_RESOLUTION;
                splitViewport.Y = 0;
                renderer.GraphicsDevice.Viewport = splitViewport;

                frustum.Matrix = viewProj;

                foreach (object mesh in meshes)
                {
                    if (mesh is List<Models>)
                        for (int index = 0; index < ((List<Models>)mesh).Count; index++)
                        {
                            Models m = ((List<Models>)mesh)[index];
                            //cull meshes outside the light volume
                         //   if (!frustum.Intersects(m.BoundingSphere))
                         //       continue;

                            //render it
                            m.RenderShadowMap(ref viewProj, renderer.GraphicsDevice);
                        }
                    if (mesh is Models)
                    {
                        //cull meshes outside the light volume
                       // if (!frustum.Intersects(((Models)mesh).BoundingSphere))
                        //    continue;

                        //render it
                        ((Models)mesh).RenderShadowMap(ref viewProj, renderer.GraphicsDevice);
                    }
                    if (mesh is CarPlayer)
                    {
                        ((CarPlayer)mesh).RenderShadowMap(ref viewProj, renderer.GraphicsDevice);
                    }
                    if (mesh is Terrain.Terrain)
                    {
                        for (int index = 0; index < ((Terrain.Terrain)mesh).QuadTrees.Count; index++)
                        {
                            //cull meshes outside the light volume
                          //  if (!frustum.Intersects(((Terrain.Terrain)mesh).QuadTrees[index].BoundingSphere))
                          //      continue;

                            //render it
                            ((Terrain.Terrain)mesh).QuadTrees[index].RenderShadowMap(ref viewProj, renderer.GraphicsDevice);
                        }

                    }
                }
                foreach (object mesh in InstancedMeshes)
                {
                    if (mesh is Billboards.Billboard)
                    {
                        ((Billboards.Billboard)mesh).TreePreDraw();

                        for (int lod = 0; lod < ((Billboards.Billboard)mesh).LOD; lod++)
                            if (((Billboards.Billboard)mesh).instanceTransforms[lod].Length != 0)
                                ((Billboards.Billboard)mesh).trunck[lod][0].RenderShadowMap(ref viewProj, renderer.GraphicsDevice);

                        if (((Billboards.Billboard)mesh).Leaves)
                            for (int tree = 0; tree < ((Billboards.Billboard)mesh).NoTrees; tree++)
                            {
                                if (((Billboards.Billboard)mesh).LeavesAreVisible[tree])
                                    for (int j = 0; j < ((Billboards.Billboard)mesh).NoLeaves; j++)
                                    {
                                        ((Billboards.Billboard)mesh).leaves[tree][j].UpdateTransformationMatrix(((Billboards.Billboard)mesh).instanceTransforms1[tree]);
                                        if (j == 0)
                                            ((Billboards.Billboard)mesh).leaves[tree][j].RenderShadowMap(ref viewProj, renderer.GraphicsDevice);
                                    }
                            }
                    }
                }
            }
        }