Esempio n. 1
0
    public OcclusionCullingScreen(IServiceLocator services)
      : base(services)
    {
      _sceneNodes = new List<SceneNode>();

      // Create new occlusion buffer with default settings.
      OcclusionBuffer = new OcclusionBuffer(GraphicsService);
      OcclusionBuffer.ProgressiveShadowCasterCulling = true;

      EnableCulling = true;

      // Create a second camera for rendering a top-down view of the scene.
      var topDownPerspective = new PerspectiveProjection();
      topDownPerspective.SetFieldOfView(MathHelper.ToRadians(90), 1, 1, 512);
      _topDownCameraNode = new CameraNode(new Camera(topDownPerspective));
      _topDownCameraNode.PoseWorld = new Pose(new Vector3F(-10, 120, -10));
      _topDownCameraNode.LookAt(new Vector3F(-10, 0, -10), Vector3F.UnitZ);

      _sceneQuery = new CustomSceneQuery();
      _debugRenderer = new DebugRenderer(GraphicsService, null);

      // The DigitalRune Profiler is used to measure execution times.
      Profiler.SetFormat("Occlusion.Render", 1e3f, "[ms]");
      Profiler.SetFormat("Occlusion.Query", 1e3f, "[ms]");
    }
Esempio n. 2
0
        public OcclusionCullingScreen(IServiceLocator services)
            : base(services)
        {
            _sceneNodes = new List <SceneNode>();

            // Create new occlusion buffer with default settings.
            OcclusionBuffer = new OcclusionBuffer(GraphicsService);
            OcclusionBuffer.ProgressiveShadowCasterCulling = true;

            EnableCulling = true;

            // Create a second camera for rendering a top-down view of the scene.
            var topDownPerspective = new PerspectiveProjection();

            topDownPerspective.SetFieldOfView(MathHelper.ToRadians(90), 1, 1, 512);
            _topDownCameraNode           = new CameraNode(new Camera(topDownPerspective));
            _topDownCameraNode.PoseWorld = new Pose(new Vector3(-10, 120, -10));
            _topDownCameraNode.LookAt(new Vector3(-10, 0, -10), Vector3.UnitZ);

            _sceneQuery    = new CustomSceneQuery();
            _debugRenderer = new DebugRenderer(GraphicsService, null);

            // The DigitalRune Profiler is used to measure execution times.
            Profiler.SetFormat("Occlusion.Render", 1e3f, "[ms]");
            Profiler.SetFormat("Occlusion.Query", 1e3f, "[ms]");
        }
        private static bool IsCameraUnderwater(CustomSceneQuery query, CameraNode cameraNode)
        {
            var cameraPosition = cameraNode.PoseWorld.Position;

            foreach (var node in query.RenderableNodes)
            {
                var waterNode = node as WaterNode;
                if (waterNode != null && waterNode.IsUnderwater(cameraPosition))
                {
                    return(true);
                }
            }

            return(false);
        }
        protected internal void RenderScene(CustomSceneQuery sceneQuery, RenderContext context,
                                            bool doPostProcessing, bool renderLensFlares, bool renderDebugOutput, bool renderReticle)
        {
            var renderTargetPool      = GraphicsService.RenderTargetPool;
            var graphicsDevice        = GraphicsService.GraphicsDevice;
            var originalRenderTarget  = context.RenderTarget;
            var originalViewport      = context.Viewport;
            var originalSourceTexture = context.SourceTexture;

            // All intermediate render targets have the size of the target viewport.
            int width  = context.Viewport.Width;
            int height = context.Viewport.Height;

            context.Viewport = new Viewport(0, 0, width, height);

            // The render context can be used to share any data, for example:
            // Store a shared RebuildZBufferRenderer in the context.
            context.Data[RenderContextKeys.RebuildZBufferRenderer] = _rebuildZBufferRenderer;

            // ----- G-Buffer Pass
            // The GBufferRenderer creates context.GBuffer0 and context.GBuffer1.
            _gBufferRenderer.Render(sceneQuery.RenderableNodes, sceneQuery.DecalNodes, context);

            // ----- Shadow Pass
            // The ShadowMapRenderer renders the shadow maps which are stored in the light nodes.
            context.RenderPass = "******";
            ShadowMapRenderer.Render(sceneQuery.Lights, context);
            context.RenderPass = null;

            // The ShadowMaskRenderer renders the shadows and stores them in one or more render
            // targets ("shadows masks").
            ShadowMaskRenderer.Render(sceneQuery.Lights, context);

            RecycleShadowMaps(sceneQuery.Lights);

            // ----- Light Buffer Pass
            // The LightBufferRenderer creates context.LightBuffer0 (diffuse light) and
            // context.LightBuffer1 (specular light).
            LightBufferRenderer.Render(sceneQuery.Lights, context);

            // Normally, we do not need the shadow masks anymore - except if we want to
            // display them for debugging.
            if (!VisualizeIntermediateRenderTargets)
            {
                ShadowMaskRenderer.RecycleShadowMasks();
            }

            // ----- Material Pass
            if (DebugMode == DeferredGraphicsDebugMode.None)
            {
                // In the material pass we render all meshes and decals into a single full-screen
                // render target. The shaders combine the material properties (diffuse texture, etc.)
                // with the light buffer info.
                context.RenderTarget =
                    renderTargetPool.Obtain2D(new RenderTargetFormat(width, height, false, SurfaceFormat.HdrBlendable,
                                                                     DepthFormat.Depth24Stencil8));
                graphicsDevice.SetRenderTarget(context.RenderTarget);
                context.Viewport = graphicsDevice.Viewport;
                graphicsDevice.Clear(new Color(3, 3, 3, 255));
                graphicsDevice.DepthStencilState = DepthStencilState.Default;
                graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;
                graphicsDevice.BlendState        = BlendState.Opaque;
                context.RenderPass = "******";
                _opaqueMeshSceneRenderer.Render(sceneQuery.RenderableNodes, context);
                _decalRenderer.Render(sceneQuery.DecalNodes, context);
                context.RenderPass = null;
            }
            else
            {
                // For debugging:
                // Ignore the material pass. Keep rendering into one of the light buffers
                // to visualize only the lighting results.
                if (DebugMode == DeferredGraphicsDebugMode.VisualizeDiffuseLightBuffer)
                {
                    context.RenderTarget = context.LightBuffer0;
                }
                else
                {
                    context.RenderTarget = context.LightBuffer1;
                }
            }

            // The meshes rendered in the last step might use additional floating-point
            // textures (e.g. the light buffers) in the different graphics texture stages.
            // We reset the texture stages (setting all GraphicsDevice.Textures to null),
            // otherwise XNA might throw exceptions.
            graphicsDevice.ResetTextures();

            // ----- Occlusion Queries
            if (renderLensFlares)
            {
                _lensFlareRenderer.UpdateOcclusion(sceneQuery.LensFlareNodes, context);
            }

            // ----- Sky
            _skyRenderer.Render(sceneQuery.SkyNodes, context);

            // ----- Fog
            _fogRenderer.Render(sceneQuery.FogNodes, context);

            // ----- Forward Rendering of Alpha-Blended Meshes and Particles
            graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
            graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;
            graphicsDevice.BlendState        = BlendState.AlphaBlend;
            context.RenderPass = "******";
            AlphaBlendSceneRenderer.Render(sceneQuery.RenderableNodes, context, RenderOrder.BackToFront);
            context.RenderPass = null;
            graphicsDevice.ResetTextures();

            renderTargetPool.Recycle(context.SourceTexture);
            context.SourceTexture = null;

            _underwaterPostProcessor.Enabled = IsCameraUnderwater(sceneQuery, context.CameraNode);

            // ----- Post Processors
            context.SourceTexture = context.RenderTarget;
            context.RenderTarget  = originalRenderTarget;
            context.Viewport      = originalViewport;
            if (doPostProcessing)
            {
                // The post-processors modify the scene image and the result is written into
                // the final render target - which is usually the back  buffer (but this could
                // also be another off-screen render target used in another graphics screen).
                PostProcessors.Process(context);
            }
            else
            {
                // Only copy the current render target to the final render target without post-processing.
                graphicsDevice.SetRenderTarget(originalRenderTarget);
                graphicsDevice.Viewport = originalViewport;
                SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone);
                SpriteBatch.Draw(context.SourceTexture, new Rectangle(0, 0, originalViewport.Width, originalViewport.Height), Color.White);
                SpriteBatch.End();
            }
            renderTargetPool.Recycle((RenderTarget2D)context.SourceTexture);
            context.SourceTexture = null;

            // ----- Lens Flares
            if (renderLensFlares)
            {
                _lensFlareRenderer.Render(sceneQuery.LensFlareNodes, context);
            }

            // ----- Debug Output
            if (renderDebugOutput)
            {
                // ----- Optional: Restore the Z-Buffer
                // Currently, the hardware depth buffer is not initialized with useful data because
                // every time we change the render target, XNA deletes the depth buffer. If we want
                // the debug rendering to use correct depth buffer, we can restore the depth buffer
                // using the RebuildZBufferRenderer. If we remove this step, then the DebugRenderer
                // graphics will overlay the whole 3D scene.
                _rebuildZBufferRenderer.Render(context, true);

                // Render debug info added by game objects.
                DebugRenderer.Render(context);

                // Render intermediate render targets for debugging.
                // We do not use the public DebugRenderer here because the public DebugRenderer
                // might not be cleared every frame (the game logic can choose how it wants to
                // use the public renderer).
                if (VisualizeIntermediateRenderTargets)
                {
                    _internalDebugRenderer.DrawTexture(context.GBuffer0, new Rectangle(0, 0, 200, 200));
                    _internalDebugRenderer.DrawTexture(context.GBuffer1, new Rectangle(200, 0, 200, 200));
                    _internalDebugRenderer.DrawTexture(context.LightBuffer0, new Rectangle(400, 0, 200, 200));
                    _internalDebugRenderer.DrawTexture(context.LightBuffer1, new Rectangle(600, 0, 200, 200));
                    for (int i = 0; i < ShadowMaskRenderer.ShadowMasks.Count; i++)
                    {
                        var shadowMask = ShadowMaskRenderer.ShadowMasks[i];
                        if (shadowMask != null)
                        {
                            _internalDebugRenderer.DrawTexture(shadowMask, new Rectangle((i) * 200, 200, 200, 200));
                        }
                    }

                    _internalDebugRenderer.Render(context);
                    _internalDebugRenderer.Clear();
                }
            }

            // ----- Draw Reticle
            if (renderReticle && _sampleFramework.IsGuiVisible)
            {
                SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                SpriteBatch.Draw(
                    _reticle,
                    new Vector2(originalViewport.Width / 2 - _reticle.Width / 2, originalViewport.Height / 2 - _reticle.Height / 2),
                    Color.Black);
                SpriteBatch.End();
            }

            // ----- Clean-up
            // It is very important to give every intermediate render target back to the
            // render target pool!
            renderTargetPool.Recycle(context.GBuffer0);
            context.GBuffer0 = null;
            renderTargetPool.Recycle(context.GBuffer1);
            context.GBuffer1 = null;
            renderTargetPool.Recycle((RenderTarget2D)context.Data[RenderContextKeys.DepthBufferHalf]);
            context.Data.Remove(RenderContextKeys.DepthBufferHalf);
            if (DebugMode != DeferredGraphicsDebugMode.VisualizeDiffuseLightBuffer)
            {
                renderTargetPool.Recycle(context.LightBuffer0);
            }
            context.LightBuffer0 = null;
            if (DebugMode != DeferredGraphicsDebugMode.VisualizeSpecularLightBuffer)
            {
                renderTargetPool.Recycle(context.LightBuffer1);
            }
            context.LightBuffer1 = null;
            ShadowMaskRenderer.RecycleShadowMasks();
            context.Data.Remove(RenderContextKeys.RebuildZBufferRenderer);
            context.SourceTexture = originalSourceTexture;
        }
        // Renders the graphics screen. - This method is called in GraphicsManager.Render().
        protected override void OnRender(RenderContext context)
        {
            if (ActiveCameraNode == null)
            {
                return;
            }

            // Our scene and the camera must be set in the render context. This info is
            // required by many renderers.
            context.Scene      = Scene;
            context.CameraNode = ActiveCameraNode;

            // LOD (level of detail) settings are also specified in the context.
            context.LodCameraNode      = ActiveCameraNode;
            context.LodHysteresis      = 0.5f;
            context.LodBias            = EnableLod ? 1.0f : 0.0f;
            context.LodBlendingEnabled = false;

            // ----- Preprocessing
            // For some scene nodes we have to update some off-screen render targets before the
            // actual scene is rendered.
            //
            // We only have to do this for the scene nodes which are visible
            // by the camera frustum:
            var preprocessingQuery = Scene.Query <PreprocessingSceneQuery>(context.CameraNode, context);

#if !XBOX360
            // TODO:
            _terrainClipmapRenderer.Render(preprocessingQuery.TerrainNodes, context);
#endif

            // Generate cloud maps.
            // Only necessary if LayeredCloudMaps are used. If the cloud maps are static
            // and the settings do not change, it is not necessary to generate the
            // cloud maps in every frame. But in the SkySample we use animated cloud maps.
            // The CloudMapRenderer can be called several times per frame, it will only
            // do the work once per frame.
            // See also SkySample.
            _cloudMapRenderer.Render(preprocessingQuery.CloudLayerNodes, context);

            // Compute ocean waves.
            // Only necessary if WaterNodes with OceanWaves are used.
            _waterWavesRenderer.Render(preprocessingQuery.WaterNodes, context);

            // Perform render-to-texture operations.
            // Only necessary if SceneCaptureNodes are used.
            // See also SceneCapture2DSample.
            SceneCaptureRenderer.Render(preprocessingQuery.SceneCaptureNodes, context);

            // Render reflections.
            // Only necessary if PlanarReflectionNodes are used.
            // See also PlanarReflectionSample.
            _planarReflectionRenderer.Render(preprocessingQuery.PlanarReflectionNodes, context);

            // ----- Scene Rendering
            // Get all scene nodes which overlap the camera frustum.
            CustomSceneQuery sceneQuery = Scene.Query <CustomSceneQuery>(context.CameraNode, context);

            // Render the scene nodes of the sceneQuery.
            RenderScene(sceneQuery, context, true, true, true, DrawReticle);

            // ----- Clean-up
            context.Scene         = null;
            context.CameraNode    = null;
            context.LodCameraNode = null;
            context.LodHysteresis = 0;
        }
        //--------------------------------------------------------------
        #region Creation & Cleanup
        //--------------------------------------------------------------

        public DeferredGraphicsScreen(IServiceLocator services)
            : base(services.GetInstance <IGraphicsService>())
        {
            _sampleFramework = services.GetInstance <SampleFramework>();
            var contentManager = services.GetInstance <ContentManager>();

            SpriteBatch = GraphicsService.GetSpriteBatch();

            // Let's create the necessary scene node renderers:
#if !XBOX360
            TerrainRenderer = new TerrainRenderer(GraphicsService);
#endif
            MeshRenderer = new MeshRenderer();

            // The _opaqueMeshSceneRenderer combines all renderers for opaque
            // (= not alpha blended) meshes.
            _opaqueMeshSceneRenderer = new SceneRenderer();
#if !XBOX360
            _opaqueMeshSceneRenderer.Renderers.Add(TerrainRenderer);
#endif
            _opaqueMeshSceneRenderer.Renderers.Add(MeshRenderer);

            _decalRenderer     = new DecalRenderer(GraphicsService);
            _billboardRenderer = new BillboardRenderer(GraphicsService, 2048)
            {
                EnableSoftParticles = true,

                // If you have an extreme amount of particles that cover the entire screen,
                // you can turn on offscreen rendering to improve performance.
                //EnableOffscreenRendering = true,
            };

            // The AlphaBlendSceneRenderer combines all renderers for transparent
            // (= alpha blended) objects.
            AlphaBlendSceneRenderer = new SceneRenderer();
            AlphaBlendSceneRenderer.Renderers.Add(MeshRenderer);
            AlphaBlendSceneRenderer.Renderers.Add(_billboardRenderer);
            AlphaBlendSceneRenderer.Renderers.Add(new WaterRenderer(GraphicsService));
            AlphaBlendSceneRenderer.Renderers.Add(new FogSphereRenderer(GraphicsService));
            AlphaBlendSceneRenderer.Renderers.Add(new VolumetricLightRenderer(GraphicsService));

#if !XBOX360
            // Update terrain clipmaps. (Only necessary if TerrainNodes are used.)
            _terrainClipmapRenderer = new TerrainClipmapRenderer(GraphicsService);
#endif

            // Renderer for cloud maps. (Only necessary if LayeredCloudMaps are used.)
            _cloudMapRenderer = new CloudMapRenderer(GraphicsService);

            // Renderer for SceneCaptureNodes. See also SceneCapture2DSample.
            // In the constructor we specify a method which is called in SceneCaptureRenderer.Render()
            // when the scene must be rendered for the SceneCaptureNodes.
            SceneCaptureRenderer = new SceneCaptureRenderer(context =>
            {
                // Get scene nodes which are visible by the current camera.
                CustomSceneQuery sceneQuery = Scene.Query <CustomSceneQuery>(context.CameraNode, context);
                // Render scene (with post-processing, with lens flares, no debug rendering, no reticle).
                RenderScene(sceneQuery, context, true, true, false, false);
            });

            // Renderer for PlanarReflectionNodes. See also PlanarReflectionSample.
            // In the constructor we specify a method which is called in PlanarReflectionRenderer.Render()
            // to create the reflection images.
            _planarReflectionRenderer = new PlanarReflectionRenderer(context =>
            {
                // Get scene nodes which are visible by the current camera.
                CustomSceneQuery sceneQuery = Scene.Query <CustomSceneQuery>(context.CameraNode, context);

                var planarReflectionNode = (PlanarReflectionNode)context.ReferenceNode;

                // Planar reflections are often for WaterNodes. These nodes should not be rendered
                // into their own reflection map because when the water surface is displaced by waves,
                // some waves could be visible in the reflection.
                // --> Remove the water node from the renderable nodes. (In our samples, the water
                // node is the parent of the reflection node.)
                if (planarReflectionNode.Parent is WaterNode)
                {
                    var index = sceneQuery.RenderableNodes.IndexOf(planarReflectionNode.Parent);
                    if (index >= 0)
                    {
                        sceneQuery.RenderableNodes[index] = null;
                    }
                }

                // Render scene (no post-processing, no lens flares, no debug rendering, no reticle).
                RenderScene(sceneQuery, context, false, false, false, false);
            });

            _waterWavesRenderer = new WaterWavesRenderer(GraphicsService);

            // The shadow map renderer renders a depth image from the viewpoint of the light and
            // stores it in LightNode.Shadow.ShadowMap.
            ShadowMapRenderer = new ShadowMapRenderer(context =>
            {
                var query = context.Scene.Query <ShadowCasterQuery>(context.CameraNode, context);
                if (query.ShadowCasters.Count == 0)
                {
                    return(false);
                }

                _opaqueMeshSceneRenderer.Render(query.ShadowCasters, context);
                return(true);
            });

            // The shadow mask renderer evaluates the shadow maps, does shadow filtering
            // and stores the resulting shadow factor in a screen space image
            //(see LightNode.Shadow.ShadowMask/ShadowMaskChannel).
            ShadowMaskRenderer = new ShadowMaskRenderer(GraphicsService, 2);

            // Optionally, we can blur the shadow mask to make the shadows smoother.
            var blur = new Blur(GraphicsService)
            {
                IsAnisotropic = false,
                IsBilateral   = true,
                EdgeSoftness  = 0.05f,
                Scale         = 1f,
                Enabled       = false, // Disable blur by default.
            };
            blur.InitializeGaussianBlur(11, 3, true);
            ShadowMaskRenderer.Filter = blur;

            // Renderers which create the intermediate render targets:
            // Those 2 renderers are implemented in this sample. Those functions could
            // be implemented directly in this class but we have created separate classes
            // to make the code more readable.
            _gBufferRenderer    = new GBufferRenderer(GraphicsService, _opaqueMeshSceneRenderer, _decalRenderer);
            LightBufferRenderer = new LightBufferRenderer(GraphicsService);

            // Other specialized renderers:
            _lensFlareRenderer      = new LensFlareRenderer(GraphicsService);
            _skyRenderer            = new SkyRenderer(GraphicsService);
            _fogRenderer            = new FogRenderer(GraphicsService);
            _internalDebugRenderer  = new DebugRenderer(GraphicsService, null);
            _rebuildZBufferRenderer = new RebuildZBufferRenderer(GraphicsService);

            Scene = new Scene();

            // This screen needs a HDR filter to map high dynamic range values back to
            // low dynamic range (LDR).
            PostProcessors = new PostProcessorChain(GraphicsService);
            PostProcessors.Add(new HdrFilter(GraphicsService)
            {
                EnableBlueShift = true,
                BlueShiftCenter = 0.0004f,
                BlueShiftRange  = 0.5f,
                //BlueShiftColor = new Vector3F(1.05f / 4f, 0.97f / 4f, 1.27f / 4f),  // Default physically-based blue-shift
                BlueShiftColor = new Vector3F(0.25f, 0.25f, 0.7f), // More dramatic blue-shift
                MinExposure    = 0,
                MaxExposure    = 10,
                BloomIntensity = 1,
                BloomThreshold = 0.6f,
            });
            _underwaterPostProcessor = new UnderwaterPostProcessor(GraphicsService, contentManager);
            PostProcessors.Add(_underwaterPostProcessor);

            // Use 2D texture for reticle.
            _reticle = contentManager.Load <Texture2D>("Reticle");

            // Use the sprite font of the GUI.
            var uiContentManager = services.GetInstance <ContentManager>("UIContent");
            var spriteFont       = uiContentManager.Load <SpriteFont>("UI Themes/BlendBlue/Default");
            DebugRenderer = new DebugRenderer(GraphicsService, spriteFont)
            {
                DefaultColor        = new Color(0, 0, 0),
                DefaultTextPosition = new Vector2F(10),
            };

            EnableLod = true;
        }
Esempio n. 7
0
    private static bool IsCameraUnderwater(CustomSceneQuery query, CameraNode cameraNode)
    {
      var cameraPosition = cameraNode.PoseWorld.Position;
      foreach (var node in query.RenderableNodes)
      {
        var waterNode = node as WaterNode;
        if (waterNode != null && waterNode.IsUnderwater(cameraPosition))
          return true;
      }

      return false;
    }
Esempio n. 8
0
    protected internal void RenderScene(CustomSceneQuery sceneQuery, RenderContext context,
      bool doPostProcessing, bool renderLensFlares, bool renderDebugOutput, bool renderReticle)
    {
      var renderTargetPool = GraphicsService.RenderTargetPool;
      var graphicsDevice = GraphicsService.GraphicsDevice;
      var originalRenderTarget = context.RenderTarget;
      var originalViewport = context.Viewport;
      var originalSourceTexture = context.SourceTexture;

      // All intermediate render targets have the size of the target viewport.
      int width = context.Viewport.Width;
      int height = context.Viewport.Height;
      context.Viewport = new Viewport(0, 0, width, height);

      // The render context can be used to share any data, for example:
      // Store a shared RebuildZBufferRenderer in the context. 
      context.Data[RenderContextKeys.RebuildZBufferRenderer] = _rebuildZBufferRenderer;

      // ----- G-Buffer Pass
      // The GBufferRenderer creates context.GBuffer0 and context.GBuffer1.
      _gBufferRenderer.Render(sceneQuery.RenderableNodes, sceneQuery.DecalNodes, context);

      // ----- Shadow Pass
      // The ShadowMapRenderer renders the shadow maps which are stored in the light nodes.
      context.RenderPass = "******";
      ShadowMapRenderer.Render(sceneQuery.Lights, context);
      context.RenderPass = null;

      // The ShadowMaskRenderer renders the shadows and stores them in one or more render
      // targets ("shadows masks").
      ShadowMaskRenderer.Render(sceneQuery.Lights, context);

      RecycleShadowMaps(sceneQuery.Lights);

      // ----- Light Buffer Pass
      // The LightBufferRenderer creates context.LightBuffer0 (diffuse light) and
      // context.LightBuffer1 (specular light).
      LightBufferRenderer.Render(sceneQuery.Lights, context);

      // Normally, we do not need the shadow masks anymore - except if we want to 
      // display them for debugging.
      if (!VisualizeIntermediateRenderTargets)
        ShadowMaskRenderer.RecycleShadowMasks();

      // ----- Material Pass
      if (DebugMode == DeferredGraphicsDebugMode.None)
      {
        // In the material pass we render all meshes and decals into a single full-screen
        // render target. The shaders combine the material properties (diffuse texture, etc.)
        // with the light buffer info.
        context.RenderTarget =
          renderTargetPool.Obtain2D(new RenderTargetFormat(width, height, false, SurfaceFormat.HdrBlendable,
            DepthFormat.Depth24Stencil8));
        graphicsDevice.SetRenderTarget(context.RenderTarget);
        context.Viewport = graphicsDevice.Viewport;
        graphicsDevice.Clear(new Color(3, 3, 3, 255));
        graphicsDevice.DepthStencilState = DepthStencilState.Default;
        graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
        graphicsDevice.BlendState = BlendState.Opaque;
        context.RenderPass = "******";
        _opaqueMeshSceneRenderer.Render(sceneQuery.RenderableNodes, context);
        _decalRenderer.Render(sceneQuery.DecalNodes, context);
        context.RenderPass = null;
      }
      else
      {
        // For debugging: 
        // Ignore the material pass. Keep rendering into one of the light buffers
        // to visualize only the lighting results.
        if (DebugMode == DeferredGraphicsDebugMode.VisualizeDiffuseLightBuffer)
          context.RenderTarget = context.LightBuffer0;
        else
          context.RenderTarget = context.LightBuffer1;
      }

      // The meshes rendered in the last step might use additional floating-point
      // textures (e.g. the light buffers) in the different graphics texture stages.
      // We reset the texture stages (setting all GraphicsDevice.Textures to null),
      // otherwise XNA might throw exceptions.
      graphicsDevice.ResetTextures();

      // ----- Occlusion Queries
      if (renderLensFlares)
        _lensFlareRenderer.UpdateOcclusion(sceneQuery.LensFlareNodes, context);

      // ----- Sky
      _skyRenderer.Render(sceneQuery.SkyNodes, context);

      // ----- Fog
      _fogRenderer.Render(sceneQuery.FogNodes, context);

      // ----- Forward Rendering of Alpha-Blended Meshes and Particles
      graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
      graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
      graphicsDevice.BlendState = BlendState.AlphaBlend;
      context.RenderPass = "******";
      AlphaBlendSceneRenderer.Render(sceneQuery.RenderableNodes, context, RenderOrder.BackToFront);
      context.RenderPass = null;
      graphicsDevice.ResetTextures();

      renderTargetPool.Recycle(context.SourceTexture);
      context.SourceTexture = null;

      _underwaterPostProcessor.Enabled = IsCameraUnderwater(sceneQuery, context.CameraNode);

      // ----- Post Processors
      context.SourceTexture = context.RenderTarget;
      context.RenderTarget = originalRenderTarget;
      context.Viewport = originalViewport;
      if (doPostProcessing)
      {
        // The post-processors modify the scene image and the result is written into
        // the final render target - which is usually the back  buffer (but this could
        // also be another off-screen render target used in another graphics screen).
        PostProcessors.Process(context);
      }
      else
      {
        // Only copy the current render target to the final render target without post-processing.
        graphicsDevice.SetRenderTarget(originalRenderTarget);
        graphicsDevice.Viewport = originalViewport;
        SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone);
        SpriteBatch.Draw(context.SourceTexture, new Rectangle(0, 0, originalViewport.Width, originalViewport.Height), Color.White);
        SpriteBatch.End();
      }
      renderTargetPool.Recycle((RenderTarget2D)context.SourceTexture);
      context.SourceTexture = null;

      // ----- Lens Flares
      if (renderLensFlares)
        _lensFlareRenderer.Render(sceneQuery.LensFlareNodes, context);

      // ----- Debug Output
      if (renderDebugOutput)
      {
        // ----- Optional: Restore the Z-Buffer
        // Currently, the hardware depth buffer is not initialized with useful data because
        // every time we change the render target, XNA deletes the depth buffer. If we want
        // the debug rendering to use correct depth buffer, we can restore the depth buffer
        // using the RebuildZBufferRenderer. If we remove this step, then the DebugRenderer
        // graphics will overlay the whole 3D scene.
        _rebuildZBufferRenderer.Render(context, true);

        // Render debug info added by game objects.
        DebugRenderer.Render(context);

        // Render intermediate render targets for debugging.
        // We do not use the public DebugRenderer here because the public DebugRenderer
        // might not be cleared every frame (the game logic can choose how it wants to
        // use the public renderer).
        if (VisualizeIntermediateRenderTargets)
        {
          _internalDebugRenderer.DrawTexture(context.GBuffer0, new Rectangle(0, 0, 200, 200));
          _internalDebugRenderer.DrawTexture(context.GBuffer1, new Rectangle(200, 0, 200, 200));
          _internalDebugRenderer.DrawTexture(context.LightBuffer0, new Rectangle(400, 0, 200, 200));
          _internalDebugRenderer.DrawTexture(context.LightBuffer1, new Rectangle(600, 0, 200, 200));
          for (int i = 0; i < ShadowMaskRenderer.ShadowMasks.Count; i++)
          {
            var shadowMask = ShadowMaskRenderer.ShadowMasks[i];
            if (shadowMask != null)
              _internalDebugRenderer.DrawTexture(shadowMask, new Rectangle((i) * 200, 200, 200, 200));
          }

          _internalDebugRenderer.Render(context);
          _internalDebugRenderer.Clear();
        }
      }

      // ----- Draw Reticle
      if (renderReticle && _sampleFramework.IsGuiVisible)
      {
        SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
        SpriteBatch.Draw(
          _reticle,
          new Vector2(originalViewport.Width / 2 - _reticle.Width / 2, originalViewport.Height / 2 - _reticle.Height / 2),
          Color.Black);
        SpriteBatch.End();
      }

      // ----- Clean-up
      // It is very important to give every intermediate render target back to the
      // render target pool!
      renderTargetPool.Recycle(context.GBuffer0);
      context.GBuffer0 = null;
      renderTargetPool.Recycle(context.GBuffer1);
      context.GBuffer1 = null;
      renderTargetPool.Recycle((RenderTarget2D)context.Data[RenderContextKeys.DepthBufferHalf]);
      context.Data.Remove(RenderContextKeys.DepthBufferHalf);
      if (DebugMode != DeferredGraphicsDebugMode.VisualizeDiffuseLightBuffer)
        renderTargetPool.Recycle(context.LightBuffer0);
      context.LightBuffer0 = null;
      if (DebugMode != DeferredGraphicsDebugMode.VisualizeSpecularLightBuffer)
        renderTargetPool.Recycle(context.LightBuffer1);
      context.LightBuffer1 = null;
      ShadowMaskRenderer.RecycleShadowMasks();
      context.Data.Remove(RenderContextKeys.RebuildZBufferRenderer);
      context.SourceTexture = originalSourceTexture;
    }
Esempio n. 9
0
        protected override void OnRender(RenderContext context)
        {
            // This screen expects two cameras.
            if (ActiveCameraNode == null || ActiveCameraNodeB == null)
            {
                return;
            }

            var renderTargetPool     = GraphicsService.RenderTargetPool;
            var graphicsDevice       = GraphicsService.GraphicsDevice;
            var originalRenderTarget = context.RenderTarget;
            var fullViewport         = context.Viewport;

            // Get a render target for the first camera. Use half the width because we split
            // the screen horizontally.
            var format = new RenderTargetFormat(context.RenderTarget)
            {
                Width = fullViewport.Width / 2
            };
            var renderTargetA = renderTargetPool.Obtain2D(format);

            context.Scene              = Scene;
            context.LodHysteresis      = 0.5f;
            context.LodBias            = 1.0f;
            context.LodBlendingEnabled = true;

            for (int i = 0; i < 2; i++)
            {
                if (i == 0)
                {
                    // The first camera renders into renderTargetA.
                    context.CameraNode   = ActiveCameraNode;
                    context.Viewport     = new Viewport(0, 0, fullViewport.Width / 2, fullViewport.Height);
                    context.RenderTarget = renderTargetA;
                }
                else
                {
                    // The second camera renders into the right half of the final render target.
                    context.CameraNode   = ActiveCameraNodeB;
                    context.Viewport     = new Viewport(fullViewport.X + fullViewport.Width / 2, fullViewport.Y, fullViewport.Width / 2, fullViewport.Height);
                    context.RenderTarget = originalRenderTarget;
                }
                context.LodCameraNode = context.CameraNode;

                // Get all scene nodes which overlap the camera frustum.
                CustomSceneQuery sceneQuery = Scene.Query <CustomSceneQuery>(context.CameraNode, context);

                // Render the scene nodes of the sceneQuery.
                RenderScene(sceneQuery, context, true, true, true, true);

                // ----- Copy image of first camera.
                if (i == 1)
                {
                    // Copy the upper screen from the temporary render target back into the back buffer.
                    context.Viewport        = fullViewport;
                    graphicsDevice.Viewport = fullViewport;

                    SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone);
                    SpriteBatch.Draw(
                        renderTargetA,
                        new Rectangle(0, 0, fullViewport.Width / 2, fullViewport.Height),
                        Color.White);
                    SpriteBatch.End();

                    renderTargetPool.Recycle(renderTargetA);
                }
            }

            // Clean-up
            context.Scene         = null;
            context.CameraNode    = null;
            context.LodCameraNode = null;
            context.RenderPass    = null;
        }