/// <summary>
        /// Creates a basic deferred rendering pipeline.
        /// </summary>
        /// <param name="serviceRegistry">The IServiceRegistry.</param>
        /// <param name="effectName">The name of the main effect.</param>
        /// <param name="prepassEffectName">The name of the light prepass effect.</param>
        /// <param name="clearColor">The clear color of the final frame buffer.</param>
        /// <param name="useShadows">A flag stating if shadows are available in this pipeline.</param>
        /// <param name="ui">A flag stating if a UI renderer should be added to the pipeline.</param>
        /// <param name="backgroundName">The name of the background texture.</param>
        public static void CreateDefaultDeferred(IServiceRegistry serviceRegistry, string effectName, string prepassEffectName, Color clearColor, bool useShadows, bool ui, string backgroundName)
        {
            if (serviceRegistry == null)
            {
                throw new ArgumentNullException("serviceRegistry");
            }
            if (effectName == null)
            {
                throw new ArgumentNullException("effectName");
            }

            var renderSystem    = serviceRegistry.GetSafeServiceAs <RenderSystem>();
            var graphicsService = serviceRegistry.GetSafeServiceAs <IGraphicsDeviceService>();

            // Adds a light processor that will track all the entities that have a light component.
            // This will also handle the shadows (allocation, activation etc.).
            AddLightProcessor(serviceRegistry, graphicsService.GraphicsDevice, useShadows);

            // Create Main pass
            var mainPipeline = renderSystem.Pipeline;

            // Adds a camera setter that will automatically fill the parameters from the camera (matrices, fov etc.).
            mainPipeline.Renderers.Add(new CameraSetter(serviceRegistry));

            // Adds a recursive pass to render the shadow maps
            // This will render all the meshes with a different effect for shadow casting.
            if (useShadows)
            {
                AddShadowMap(serviceRegistry, mainPipeline, effectName);
            }

            // Create G-buffer pass
            var gbufferPipeline = new RenderPipeline("GBuffer");

            // Renders the G-buffer for opaque geometry.
            gbufferPipeline.Renderers.Add(new ModelRenderer(serviceRegistry, effectName + ".ParadoxGBufferShaderPass").AddOpaqueFilter());
            var gbufferProcessor = new GBufferRenderProcessor(serviceRegistry, gbufferPipeline, graphicsService.GraphicsDevice.DepthStencilBuffer, false);

            // Add sthe G-buffer pass to the pipeline.
            mainPipeline.Renderers.Add(gbufferProcessor);

            // Performs the light prepass on opaque geometry.
            // Adds this pass to the pipeline.
            var lightDeferredProcessor = new LightingPrepassRenderer(serviceRegistry, prepassEffectName, graphicsService.GraphicsDevice.DepthStencilBuffer.Texture, gbufferProcessor.GBufferTexture);

            mainPipeline.Renderers.Add(lightDeferredProcessor);

            // Sets the render targets and clear them. Also sets the viewport.
            mainPipeline.Renderers.Add(new RenderTargetSetter(serviceRegistry)
            {
                ClearColor       = clearColor,
                EnableClearDepth = false,
                RenderTarget     = graphicsService.GraphicsDevice.BackBuffer,
                DepthStencil     = graphicsService.GraphicsDevice.DepthStencilBuffer,
                Viewport         = new Viewport(0, 0, graphicsService.GraphicsDevice.BackBuffer.Width, graphicsService.GraphicsDevice.BackBuffer.Height)
            });

            // Draws a background from a texture.
            if (backgroundName != null)
            {
                mainPipeline.Renderers.Add(new BackgroundRenderer(serviceRegistry, backgroundName));
            }

            // Prevents depth write since depth was already computed in G-buffer pas.
            mainPipeline.Renderers.Add(new RenderStateSetter(serviceRegistry)
            {
                DepthStencilState = graphicsService.GraphicsDevice.DepthStencilStates.DepthRead
            });
            mainPipeline.Renderers.Add(new ModelRenderer(serviceRegistry, effectName).AddOpaqueFilter());
            mainPipeline.Renderers.Add(new RenderTargetSetter(serviceRegistry)
            {
                EnableClearDepth  = false,
                EnableClearTarget = false,
                RenderTarget      = graphicsService.GraphicsDevice.BackBuffer,
                DepthStencil      = graphicsService.GraphicsDevice.DepthStencilBuffer,
                Viewport          = new Viewport(0, 0, graphicsService.GraphicsDevice.BackBuffer.Width, graphicsService.GraphicsDevice.BackBuffer.Height)
            });

            // Renders transparent geometry. Depth stencil state is determined by the object to draw.
            //mainPipeline.Renderers.Add(new RenderStateSetter(serviceRegistry) { DepthStencilState = graphicsService.GraphicsDevice.DepthStencilStates.DepthRead });
            mainPipeline.Renderers.Add(new ModelRenderer(serviceRegistry, effectName).AddTransparentFilter());

            // Renders the UI.
            if (ui)
            {
                mainPipeline.Renderers.Add(new UIRenderer(serviceRegistry));
            }

            graphicsService.GraphicsDevice.Parameters.Set(RenderingParameters.UseDeferred, true);
        }
        /// <summary>
        /// Creates the rendering pipeline
        /// </summary>
        private void CreatePipeline()
        {
            var renderers         = RenderSystem.Pipeline.Renderers;
            var width             = GraphicsDevice.BackBuffer.Width;
            var height            = GraphicsDevice.BackBuffer.Height;
            var viewport          = new Viewport(0, 0, width, height);
            var clearColor        = Color.Black;
            var effectName        = "ParadoxCraftEffectMain";
            var fowardEffectName  = "ParadoxCraftEffectForward";
            var prepassEffectName = "ParadoxCraftPrepassEffect";

            // Adds a light processor that will track all the entities that have a light component.
            // This will also handle the shadows (allocation, activation etc.).
            var lightProcessor = Entities.GetProcessor <LightShadowProcessor>();

            if (lightProcessor == null)
            {
                Entities.Processors.Add(new DynamicLightShadowProcessor(GraphicsDevice, false));
            }

            // Camera
            renderers.Add(new CameraSetter(Services));

            // Create G-buffer pass
            var gbufferPipeline = new RenderPipeline("GBuffer");

            // Renders the G-buffer for opaque geometry.
            gbufferPipeline.Renderers.Add(new ModelRenderer(Services, effectName + ".ParadoxGBufferShaderPass").AddOpaqueFilter());
            var gbufferProcessor = new GBufferRenderProcessor(Services, gbufferPipeline, GraphicsDevice.DepthStencilBuffer, false);

            // Add sthe G-buffer pass to the pipeline.
            renderers.Add(gbufferProcessor);

            // Performs the light prepass on opaque geometry.
            // Adds this pass to the pipeline.
            var lightDeferredProcessor = new LightingPrepassRenderer(Services, prepassEffectName, GraphicsDevice.DepthStencilBuffer, gbufferProcessor.GBufferTexture);

            renderers.Add(lightDeferredProcessor);

            renderers.Add(new RenderTargetSetter(Services)
            {
                ClearColor       = clearColor,
                EnableClearDepth = false,
                RenderTarget     = GraphicsDevice.BackBuffer,
                DepthStencil     = GraphicsDevice.DepthStencilBuffer,
                Viewport         = viewport
            });

            renderers.Add(new RenderStateSetter(Services)
            {
                DepthStencilState = GraphicsDevice.DepthStencilStates.Default, RasterizerState = GraphicsDevice.RasterizerStates.CullBack
            });

            // Renders all the meshes with the correct lighting.
            renderers.Add(new ModelRenderer(Services, fowardEffectName).AddLightForwardSupport());

            // Blend atmoshpere inscatter on top
            renderers.Add(new AtmosphereRenderer(Services, Atmosphere, Sunlight));

            // Wireframe mode
            if (isWireframe)
            {
                GraphicsDevice.Parameters.Set(Effect.RasterizerStateKey, RasterizerState.New(GraphicsDevice, new RasterizerStateDescription(CullMode.None)
                {
                    FillMode = FillMode.Wireframe
                }));
            }

            GraphicsDevice.Parameters.Set(RenderingParameters.UseDeferred, true);
        }
        /// <summary>
        /// Creates a basic deferred rendering pipeline.
        /// </summary>
        /// <param name="serviceRegistry">The IServiceRegistry.</param>
        /// <param name="effectName">The name of the main effect.</param>
        /// <param name="prepassEffectName">The name of the light prepass effect.</param>
        /// <param name="clearColor">The clear color of the final frame buffer.</param>
        /// <param name="useShadows">A flag stating if shadows are available in this pipeline.</param>
        /// <param name="ui">A flag stating if a UI renderer should be added to the pipeline.</param>
        /// <param name="backgroundName">The name of the background texture.</param>
        public static void CreateDefaultDeferred(IServiceRegistry serviceRegistry, string effectName, string prepassEffectName, Color clearColor, bool useShadows, bool ui, string backgroundName)
        {
            if (serviceRegistry == null)
            {
                throw new ArgumentNullException("serviceRegistry");
            }
            if (effectName == null)
            {
                throw new ArgumentNullException("effectName");
            }

            var renderSystem    = serviceRegistry.GetSafeServiceAs <RenderSystem>();
            var graphicsService = serviceRegistry.GetSafeServiceAs <IGraphicsDeviceService>();

#if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGL
            var width  = graphicsService.GraphicsDevice.DepthStencilBuffer.Width;
            var height = graphicsService.GraphicsDevice.DepthStencilBuffer.Height;

            // On OpenGL, intermediate texture are flipped and we cannot create a framebuffer with a user-generated attachment and a default one.
            // So we will render everything into a intermediate texture and draw it on screen at the end.
            var finalRenderTexture = Texture.New2D(graphicsService.GraphicsDevice, width, height, PixelFormat.R8G8B8A8_UNorm, TextureFlags.RenderTarget | TextureFlags.ShaderResource);
            var finalDepthBuffer   = Texture.New2D(graphicsService.GraphicsDevice, width, height, PixelFormat.D32_Float, TextureFlags.DepthStencil | TextureFlags.ShaderResource);
#else
            var finalRenderTexture = graphicsService.GraphicsDevice.BackBuffer;
            var finalDepthBuffer   = graphicsService.GraphicsDevice.DepthStencilBuffer;
#endif

            var readOnlyDepthBuffer = finalDepthBuffer.ToDepthStencilReadOnlyTexture();

            // Adds a light processor that will track all the entities that have a light component.
            // This will also handle the shadows (allocation, activation etc.).
            AddLightProcessor(serviceRegistry, graphicsService.GraphicsDevice, useShadows);

            // Create Main pass
            var mainPipeline = renderSystem.Pipeline;

            // Adds a camera setter that will automatically fill the parameters from the camera (matrices, fov etc.).
            mainPipeline.Renderers.Add(new CameraSetter(serviceRegistry));

            // Adds a recursive pass to render the shadow maps
            // This will render all the meshes with a different effect for shadow casting.
            if (useShadows)
            {
                AddShadowMap(serviceRegistry, mainPipeline, effectName);
            }

            // Create G-buffer pass
            var gbufferPipeline = new RenderPipeline("GBuffer");

            // Renders the G-buffer for opaque geometry.
            gbufferPipeline.Renderers.Add(new ModelRenderer(serviceRegistry, effectName + ".ParadoxGBufferShaderPass").AddOpaqueFilter());
            var gbufferProcessor = new GBufferRenderProcessor(serviceRegistry, gbufferPipeline, finalDepthBuffer, false);

            // Add sthe G-buffer pass to the pipeline.
            mainPipeline.Renderers.Add(gbufferProcessor);

            // Performs the light prepass on opaque geometry.
            // Adds this pass to the pipeline.
            var lightDeferredProcessor = new LightingPrepassRenderer(serviceRegistry, prepassEffectName, finalDepthBuffer, gbufferProcessor.GBufferTexture);
            mainPipeline.Renderers.Add(lightDeferredProcessor);

            // Sets the render targets and clear them. Also sets the viewport.
            mainPipeline.Renderers.Add(new RenderTargetSetter(serviceRegistry)
            {
                ClearColor       = clearColor,
                EnableClearDepth = false,
                RenderTarget     = finalRenderTexture,
                DepthStencil     = finalDepthBuffer,
                Viewport         = new Viewport(0, 0, finalRenderTexture.ViewWidth, finalRenderTexture.ViewHeight)
            });

            // Draws a background from a texture.
            if (backgroundName != null)
            {
                mainPipeline.Renderers.Add(new BackgroundRenderer(serviceRegistry, backgroundName));
            }

            // Prevents depth write since depth was already computed in G-buffer pas.
            mainPipeline.Renderers.Add(new RenderStateSetter(serviceRegistry)
            {
                DepthStencilState = graphicsService.GraphicsDevice.DepthStencilStates.DepthRead
            });
            mainPipeline.Renderers.Add(new ModelRenderer(serviceRegistry, effectName).AddOpaqueFilter());
            mainPipeline.Renderers.Add(new RenderTargetSetter(serviceRegistry)
            {
                EnableClearDepth  = false,
                EnableClearTarget = false,
                RenderTarget      = finalRenderTexture,
                DepthStencil      = finalDepthBuffer,
                Viewport          = new Viewport(0, 0, finalRenderTexture.ViewWidth, finalRenderTexture.ViewHeight)
            });

            // Renders transparent geometry. Depth stencil state is determined by the object to draw.
            mainPipeline.Renderers.Add(new RenderStateSetter(serviceRegistry)
            {
                DepthStencilState = graphicsService.GraphicsDevice.DepthStencilStates.DepthRead
            });
            mainPipeline.Renderers.Add(new ModelRenderer(serviceRegistry, effectName).AddTransparentFilter());

#if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGL
            // on OpenGL, draw the final texture to the framebuffer
            mainPipeline.Renderers.Add(new RenderStateSetter(serviceRegistry)
            {
                DepthStencilState = graphicsService.GraphicsDevice.DepthStencilStates.None,
                BlendState        = graphicsService.GraphicsDevice.BlendStates.Opaque
            });
            mainPipeline.Renderers.Add(new RenderTargetSetter(serviceRegistry)
            {
                ClearColor         = clearColor,
                EnableClearDepth   = false,
                EnableClearStencil = false,
                EnableClearTarget  = false,
                RenderTarget       = graphicsService.GraphicsDevice.BackBuffer,
                DepthStencil       = null,
                Viewport           = new Viewport(0, 0, graphicsService.GraphicsDevice.BackBuffer.ViewWidth, graphicsService.GraphicsDevice.BackBuffer.ViewHeight)
            });
            mainPipeline.Renderers.Add(new DelegateRenderer(serviceRegistry)
            {
                Render = (context => graphicsService.GraphicsDevice.DrawTexture(finalRenderTexture, true))
            });
#endif
            // Renders the UI.
            if (ui)
            {
                mainPipeline.Renderers.Add(new UIRenderer(serviceRegistry));
            }

            graphicsService.GraphicsDevice.Parameters.Set(RenderingParameters.UseDeferred, true);
        }