Exemplo n.º 1
0
        private void UpdateCubeMap(TimeSpan deltaTime)
        {
            if (_cloudMapRenderer == null)
            {
                // This is the first call of UpdateCubeMap. Create the renderers which
                // we need to render the cube map.

                // The CloudMapRenderer creates and animates the LayeredCloudMaps.
                _cloudMapRenderer = new CloudMapRenderer(_graphicsService);

                // The SkyRenderer renders SkyNodes.
                _skyRenderer = new SkyRenderer(_graphicsService);

                // We use a ColorEncoder to encode a HDR image in a normal Color texture.
                _colorEncoder = new ColorEncoder(_graphicsService)
                {
                    SourceEncoding = ColorEncoding.Rgb,
                    TargetEncoding = SkyboxNode.Encoding,
                };

                // The SceneCaptureRenderer handles SceneCaptureNodes. We need to specify
                // a render callback which is called in SceneCaptureNode.Render().
                _sceneCaptureRenderer = new SceneCaptureRenderer(RenderSky);

                // Normally, the render context is managed by the graphics service.
                // When we call renderer outside of a GraphicsScreen, we have to use our
                // own context instance.
                _context = new RenderContext(_graphicsService);
            }

            // Update render context. For off-screen rendering we must at least update
            // the time properties (e.g. for cloud animations).
            _context.DeltaTime = deltaTime;
            _context.Time     += deltaTime;
            _context.Frame++;

            // Create cloud maps.
            _cloudMapRenderer.Render(_skyGroupNode.Children, _context);

            // Capture sky in cube map.
            _sceneCaptureRenderer.Render(_sceneCaptureNode, _context);
        }
        // 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;
        }
Exemplo n.º 3
0
        // Renders the graphics screen. - This method is called in GraphicsManager.Render().
        protected override void OnRender(RenderContext context)
        {
            // Abort if no active camera is set.
            if (ActiveCameraNode == null)
            {
                return;
            }

            var renderTargetPool   = GraphicsService.RenderTargetPool;
            var graphicsDevice     = GraphicsService.GraphicsDevice;
            var screenRenderTarget = context.RenderTarget;
            var viewport           = context.Viewport;

            // 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);

            // 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;

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

            // Generate cloud maps.
            // (Note: 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 this example we use animated cloud maps.)
            _cloudMapRenderer.Render(sceneQuery.SkyNodes, context);

            // ----- 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);

            // In this render pipeline we do not need most shadow maps anymore and can
            // recycle them. The exception is the DirectionalLight shadow map which
            // might still be needed for forward rendering of alpha-blended objects.
            foreach (var node in sceneQuery.Lights)
            {
                var lightNode = (LightNode)node;
                if (lightNode.Shadow != null && !(lightNode.Light is DirectionalLight))
                {
                    renderTargetPool.Recycle(lightNode.Shadow.ShadowMap);
                    lightNode.Shadow.ShadowMap = null;
                }
            }

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

            // ----- Material Pass
            // 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(Color.Black);
            graphicsDevice.DepthStencilState = DepthStencilState.Default;
            graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;
            graphicsDevice.BlendState        = BlendState.Opaque;
            context.RenderPass = "******";
            _meshRenderer.Render(sceneQuery.RenderableNodes, context);
            _decalRenderer.Render(sceneQuery.DecalNodes, context);
            context.RenderPass = null;

            // 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
            _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();

            // The shadow maps could be used by some shaders of the alpha-blended
            // objects - but now, we can recycle all shadow maps.
            foreach (var node in sceneQuery.Lights)
            {
                var lightNode = (LightNode)node;
                if (lightNode.Shadow != null)
                {
                    renderTargetPool.Recycle(lightNode.Shadow.ShadowMap);
                    lightNode.Shadow.ShadowMap = null;
                }
            }

            // ----- Post Processors
            // 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).
            context.SourceTexture = context.RenderTarget;
            context.RenderTarget  = screenRenderTarget;
            context.Viewport      = viewport;
            PostProcessors.Process(context);

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

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

            // ----- 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);

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

            // ----- Draw Reticle
            if (DrawReticle)
            {
                _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                _spriteBatch.Draw(
                    _reticle,
                    new Vector2(viewport.Width / 2 - _reticle.Width / 2, viewport.Height / 2 - _reticle.Height / 2),
                    Color.Black);
                _spriteBatch.End();
            }

            // 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();
            }

            // ----- 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);
            renderTargetPool.Recycle(context.LightBuffer0);
            context.LightBuffer0 = null;
            renderTargetPool.Recycle(context.LightBuffer1);
            context.LightBuffer1 = null;
            _shadowMaskRenderer.RecycleShadowMasks();
            context.Scene         = null;
            context.CameraNode    = null;
            context.LodHysteresis = 0;
            context.LodCameraNode = null;
            context.RenderPass    = null;
        }
Exemplo n.º 4
0
        private void Render(RenderContext context)
        {
            var originalRenderTarget = context.RenderTarget;
            var originalViewport     = context.Viewport;

            var graphicsDevice = context.GraphicsService.GraphicsDevice;

            if (_updateCubeMap)
            {
                _updateCubeMap = false;

                _cloudMapRenderer.Render(_skyNodes, context);

                // Create a camera with 45° FOV for a single cube map face.
                var perspectiveProjection = new PerspectiveProjection();
                perspectiveProjection.SetFieldOfView(ConstantsF.PiOver2, 1, 1, 100);
                context.CameraNode = new CameraNode(new Camera(perspectiveProjection));

                var size      = _skybox.Texture.Size;
                var hdrFormat = new RenderTargetFormat(size, size, false, SurfaceFormat.HdrBlendable, DepthFormat.None);
                var hdrTarget = context.GraphicsService.RenderTargetPool.Obtain2D(hdrFormat);
                var ldrFormat = new RenderTargetFormat(size, size, false, SurfaceFormat.Color, DepthFormat.None);
                var ldrTarget = context.GraphicsService.RenderTargetPool.Obtain2D(ldrFormat);

                var spriteBatch = GraphicsService.GetSpriteBatch();
                for (int side = 0; side < 6; side++)
                {
                    // Rotate camera to face the current cube map face.
                    var cubeMapFace = (CubeMapFace)side;
                    context.CameraNode.View = Matrix44F.CreateLookAt(
                        new Vector3F(),
                        GraphicsHelper.GetCubeMapForwardDirection(cubeMapFace),
                        GraphicsHelper.GetCubeMapUpDirection(cubeMapFace));

                    // Render sky into HDR render target.
                    graphicsDevice.SetRenderTarget(hdrTarget);
                    context.RenderTarget = hdrTarget;
                    context.Viewport     = graphicsDevice.Viewport;
                    graphicsDevice.Clear(Color.Black);
                    _skyRenderer.Render(_skyNodes, context);

                    graphicsDevice.BlendState = BlendState.Opaque;

                    // Convert HDR to RGBM.
                    context.SourceTexture = hdrTarget;
                    context.RenderTarget  = ldrTarget;
                    _colorEncoder.Process(context);
                    context.SourceTexture = null;

                    // Copy RGBM texture into cube map face.
                    graphicsDevice.SetRenderTarget((RenderTargetCube)_skybox.Texture, cubeMapFace);
                    spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, null, null, null);
                    spriteBatch.Draw(ldrTarget, new Vector2(0, 0), Color.White);
                    spriteBatch.End();
                }

                context.GraphicsService.RenderTargetPool.Recycle(ldrTarget);
                context.GraphicsService.RenderTargetPool.Recycle(hdrTarget);
            }

            graphicsDevice.BlendState        = BlendState.Opaque;
            graphicsDevice.DepthStencilState = DepthStencilState.Default;
            graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;

            context.CameraNode = _cameraObject.CameraNode;

            var tempFormat = new RenderTargetFormat(originalRenderTarget);

            tempFormat.SurfaceFormat = SurfaceFormat.HdrBlendable;
            var tempTarget = context.GraphicsService.RenderTargetPool.Obtain2D(tempFormat);

            graphicsDevice.SetRenderTarget(tempTarget);
            graphicsDevice.Viewport = originalViewport;
            context.RenderTarget    = tempTarget;
            context.Viewport        = originalViewport;

            _skyRenderer.Render(_skybox, context);

            context.SourceTexture = tempTarget;
            context.RenderTarget  = originalRenderTarget;
            _hdrFilter.Process(context);
            context.SourceTexture = null;

            context.GraphicsService.RenderTargetPool.Recycle(tempTarget);

            RenderDebugInfo(context);

            context.CameraNode = null;
        }
Exemplo n.º 5
0
        protected override void OnRender(RenderContext context)
        {
            // This screen expects two cameras.
            if (ActiveCameraNodeA == 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++)
            {
                Viewport       halfViewport;
                RenderTarget2D currentRenderTarget;
                if (i == 0)
                {
                    // The first camera renders into renderTargetA.
                    context.CameraNode  = ActiveCameraNodeA;
                    halfViewport        = new Viewport(0, 0, fullViewport.Width / 2, fullViewport.Height);
                    currentRenderTarget = renderTargetA;
                }
                else
                {
                    // The second camera renders into the right half of the final render target.
                    context.CameraNode  = ActiveCameraNodeB;
                    halfViewport        = new Viewport(fullViewport.X + fullViewport.Width / 2, fullViewport.Y, fullViewport.Width / 2, fullViewport.Height);
                    currentRenderTarget = originalRenderTarget;
                }
                context.LodCameraNode = context.CameraNode;

                CustomSceneQuery sceneQuery = Scene.Query <CustomSceneQuery>(context.CameraNode, context);

                // Cloud maps need to be updated only once.
                if (i == 0)
                {
                    _cloudMapRenderer.Render(sceneQuery.SkyNodes, context);
                }

                // ----- G-Buffer Pass
                _gBufferRenderer.Render(sceneQuery.RenderableNodes, sceneQuery.DecalNodes, context);

                // ----- Shadow Pass
                context.RenderPass = "******";
                _shadowMapRenderer.Render(sceneQuery.Lights, context);
                context.RenderPass = null;

                context.Viewport = halfViewport;
                _shadowMaskRenderer.Render(sceneQuery.Lights, context);

                // Recycle shadow maps.
                foreach (var node in sceneQuery.Lights)
                {
                    var lightNode = (LightNode)node;
                    if (lightNode.Shadow != null)
                    {
                        renderTargetPool.Recycle(lightNode.Shadow.ShadowMap);
                        lightNode.Shadow.ShadowMap = null;
                    }
                }

                // ----- Light Buffer Pass
                _lightBufferRenderer.Render(sceneQuery.Lights, context);

                // ----- Material Pass
                context.RenderTarget = renderTargetPool.Obtain2D(new RenderTargetFormat(
                                                                     context.Viewport.Width,
                                                                     context.Viewport.Height,
                                                                     false,
                                                                     SurfaceFormat.HdrBlendable,
                                                                     DepthFormat.Depth24Stencil8));
                graphicsDevice.SetRenderTarget(context.RenderTarget);
                context.Viewport = graphicsDevice.Viewport;
                graphicsDevice.Clear(Color.Black);
                graphicsDevice.DepthStencilState = DepthStencilState.Default;
                graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;
                graphicsDevice.BlendState        = BlendState.Opaque;
                context.RenderPass = "******";
                _meshRenderer.Render(sceneQuery.RenderableNodes, context);
                _decalRenderer.Render(sceneQuery.DecalNodes, context);
                context.RenderPass = null;
                graphicsDevice.ResetTextures();

                // ----- Occlusion Queries
                _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 = "******";
                _transparentSceneRenderer.Render(sceneQuery.RenderableNodes, context, RenderOrder.BackToFront);
                context.RenderPass = null;
                graphicsDevice.ResetTextures();

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

                // ----- Post Processors
                context.SourceTexture = context.RenderTarget;
                context.RenderTarget  = currentRenderTarget;
                context.Viewport      = halfViewport;
                PostProcessors.Process(context);

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

                // ----- Optional: Restore the Z-Buffer
                _rebuildZBufferRenderer.Render(context, true);

                // ----- Debug Output
                DebugRenderer.Render(context);

                // ----- Draw Reticle
                if (DrawReticle)
                {
                    _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                    _spriteBatch.Draw(
                        _reticle,
                        new Vector2(halfViewport.Width / 2 - _reticle.Width / 2, halfViewport.Height / 2 - _reticle.Height / 2),
                        Color.Black);
                    _spriteBatch.End();
                }

                // ----- Clean-up
                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);
                renderTargetPool.Recycle(context.LightBuffer0);
                context.LightBuffer0 = null;
                renderTargetPool.Recycle(context.LightBuffer1);
                context.LightBuffer1 = null;
                _shadowMaskRenderer.RecycleShadowMasks();

                // ----- 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);
                }
            }

            context.Scene         = null;
            context.CameraNode    = null;
            context.LodCameraNode = null;
            context.RenderPass    = null;
        }
Exemplo n.º 6
0
        private void UpdateCubeMap(TimeSpan deltaTime)
        {
            if (_cloudMapRenderer == null)
            {
                // This is the first call of UpdateCubeMap. Create the renderers which
                // we need to render the cube map.

                // The CloudMapRenderer creates and animates the LayeredCloudMaps.
                _cloudMapRenderer = new CloudMapRenderer(_graphicsService);

                // The SkyRenderer renders SkyNodes.
                _skyRenderer = new SkyRenderer(_graphicsService);

                // We use a ColorEncoder to encode a HDR image in a normal Color texture.
                _colorEncoder = new ColorEncoder(_graphicsService)
                {
                    SourceEncoding = ColorEncoding.Rgb,
                    TargetEncoding = SkyboxNode.Encoding,
                };

                // The SceneCaptureRenderer handles SceneCaptureNodes. We need to specify
                // a delegate which is called in SceneCaptureNode.Render().
                _sceneCaptureRenderer = new SceneCaptureRenderer(context =>
                {
                    var graphicsDevice   = _graphicsService.GraphicsDevice;
                    var renderTargetPool = _graphicsService.RenderTargetPool;

                    // We have to render into this render target.
                    var ldrTarget = context.RenderTarget;

                    // Reset render states.
                    graphicsDevice.BlendState        = BlendState.Opaque;
                    graphicsDevice.DepthStencilState = DepthStencilState.Default;
                    graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;

                    // Use an intermediate HDR render target with the same resolution as the final target.
                    var format = new RenderTargetFormat(ldrTarget)
                    {
                        SurfaceFormat      = SurfaceFormat.HdrBlendable,
                        DepthStencilFormat = DepthFormat.Depth24Stencil8
                    };
                    var hdrTarget = renderTargetPool.Obtain2D(format);

                    graphicsDevice.SetRenderTarget(hdrTarget);
                    context.RenderTarget = hdrTarget;

                    graphicsDevice.Clear(Color.Black);

                    // Render the sky.
                    _skyRenderer.Render(_skyGroupNode.Children, context);

                    // Convert the HDR image to RGBM image.
                    context.SourceTexture = hdrTarget;
                    context.RenderTarget  = ldrTarget;
                    _colorEncoder.Process(context);
                    context.SourceTexture = null;

                    // Clean up.
                    renderTargetPool.Recycle(hdrTarget);
                    context.RenderTarget = ldrTarget;
                });

                // Normally, the render context is managed by the graphics service.
                // When we call renderer outside of a GraphicsScreen, we have to use our
                // own context instance.
                _context = new RenderContext(_graphicsService);
            }

            // Update render context.
            // Frame needs to be updated to tell the renderers that this is a new "frame".
            // (Otherwise, they might abort early to avoid duplicate work in the same frame.)
            _context.Frame++;

            // DeltaTime is relevant for renderers such as the CloudMapRenderer because it
            // might have to animate the clouds.
            _context.DeltaTime = deltaTime;

            // Create cloud maps.
            _cloudMapRenderer.Render(_skyGroupNode.Children, _context);

            // Capture sky in cube map.
            _sceneCaptureRenderer.Render(_sceneCaptureNode, _context);
        }
Exemplo n.º 7
0
        protected override void OnRender(RenderContext context)
        {
            if (ActiveCameraNode == 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 and height.
            int halfWidth  = fullViewport.Width / 2;
            int halfHeight = fullViewport.Height / 2;
            var format     = new RenderTargetFormat(context.RenderTarget)
            {
                Width  = halfWidth,
                Height = halfHeight
            };

            var renderTarget0 = renderTargetPool.Obtain2D(format);
            var renderTarget1 = renderTargetPool.Obtain2D(format);
            var renderTarget2 = renderTargetPool.Obtain2D(format);
            var viewport0     = new Viewport(0, 0, halfWidth, halfHeight);
            var viewport1     = new Viewport(halfWidth, 0, halfWidth, halfHeight);
            var viewport2     = new Viewport(0, halfHeight, halfWidth, halfHeight);

            context.Scene         = Scene;
            context.CameraNode    = ActiveCameraNode;
            context.LodCameraNode = context.CameraNode;
            context.LodHysteresis = 0.5f;

            // Reduce detail level by increasing the LOD bias.
            context.LodBias = 2.0f;

            for (int i = 0; i < 4; i++)
            {
                Viewport       halfViewport;
                RenderTarget2D currentRenderTarget;
                if (i == 0)
                {
                    // TOP, LEFT
                    currentRenderTarget        = renderTarget0;
                    halfViewport               = new Viewport(0, 0, viewport0.Width, viewport0.Height);
                    context.LodBlendingEnabled = false;
                }
                else if (i == 1)
                {
                    // TOP, RIGHT
                    currentRenderTarget        = renderTarget1;
                    halfViewport               = new Viewport(0, 0, viewport1.Width, viewport1.Height);
                    context.LodBlendingEnabled = true;
                }
                else if (i == 2)
                {
                    // BOTTOM, LEFT
                    currentRenderTarget        = renderTarget2;
                    halfViewport               = new Viewport(0, 0, viewport2.Width, viewport2.Height);
                    context.LodBlendingEnabled = false;
                }
                else
                {
                    // BOTTOM, RIGHT
                    currentRenderTarget        = originalRenderTarget;
                    halfViewport               = new Viewport(fullViewport.X + halfWidth, fullViewport.Y + halfHeight, halfWidth, halfHeight);
                    context.LodBlendingEnabled = true;
                }

                var sceneQuery = Scene.Query <SceneQueryWithLodBlending>(context.CameraNode, context);

                if (i == 0 || i == 1)
                {
                    // TOP
                    for (int j = 0; j < sceneQuery.RenderableNodes.Count; j++)
                    {
                        if (sceneQuery.RenderableNodes[j].UserFlags == 1)
                        {
                            sceneQuery.RenderableNodes[j] = null;
                        }
                    }
                }
                else
                {
                    // BOTTOM
                    for (int j = 0; j < sceneQuery.RenderableNodes.Count; j++)
                    {
                        if (sceneQuery.RenderableNodes[j].UserFlags == 2)
                        {
                            sceneQuery.RenderableNodes[j] = null;
                        }
                    }
                }

                // Cloud maps need to be updated only once.
                if (i == 0)
                {
                    _cloudMapRenderer.Render(sceneQuery.SkyNodes, context);
                }

                // ----- G-Buffer Pass
                _gBufferRenderer.Render(sceneQuery.RenderableNodes, sceneQuery.DecalNodes, context);

                // ----- Shadow Pass
                context.RenderPass = "******";
                _shadowMapRenderer.Render(sceneQuery.Lights, context);
                context.RenderPass = null;

                context.Viewport = halfViewport;
                _shadowMaskRenderer.Render(sceneQuery.Lights, context);

                // Recycle shadow maps.
                foreach (var node in sceneQuery.Lights)
                {
                    var lightNode = (LightNode)node;
                    if (lightNode.Shadow != null)
                    {
                        renderTargetPool.Recycle(lightNode.Shadow.ShadowMap);
                        lightNode.Shadow.ShadowMap = null;
                    }
                }

                // ----- Light Buffer Pass
                _lightBufferRenderer.Render(sceneQuery.Lights, context);

                // ----- Material Pass
                context.RenderTarget = renderTargetPool.Obtain2D(new RenderTargetFormat(
                                                                     context.Viewport.Width,
                                                                     context.Viewport.Height,
                                                                     false,
                                                                     SurfaceFormat.HdrBlendable,
                                                                     DepthFormat.Depth24Stencil8));
                graphicsDevice.SetRenderTarget(context.RenderTarget);
                context.Viewport = graphicsDevice.Viewport;
                graphicsDevice.Clear(Color.Black);
                graphicsDevice.DepthStencilState = DepthStencilState.Default;
                graphicsDevice.RasterizerState   = RasterizerState.CullCounterClockwise;
                graphicsDevice.BlendState        = BlendState.Opaque;
                context.RenderPass = "******";
                _meshRenderer.Render(sceneQuery.RenderableNodes, context);
                _decalRenderer.Render(sceneQuery.DecalNodes, context);
                context.RenderPass = null;
                graphicsDevice.ResetTextures();

                // ----- Occlusion Queries
                _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 = "******";
                _transparentSceneRenderer.Render(sceneQuery.RenderableNodes, context, RenderOrder.BackToFront);
                context.RenderPass = null;
                graphicsDevice.ResetTextures();

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

                // ----- Post Processors
                context.SourceTexture = context.RenderTarget;
                context.RenderTarget  = currentRenderTarget;
                context.Viewport      = halfViewport;
                PostProcessors.Process(context);

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

                // ----- Optional: Restore the Z-Buffer
                _rebuildZBufferRenderer.Render(context, true);

                // ----- Debug Output
                DebugRenderer.Render(context);

                // ----- Draw Reticle
                if (DrawReticle)
                {
                    _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                    _spriteBatch.Draw(
                        _reticle,
                        new Vector2(halfViewport.Width / 2 - _reticle.Width / 2, halfViewport.Height / 2 - _reticle.Height / 2),
                        Color.Black);
                    _spriteBatch.End();
                }

                // ----- Clean-up
                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);
                renderTargetPool.Recycle(context.LightBuffer0);
                context.LightBuffer0 = null;
                renderTargetPool.Recycle(context.LightBuffer1);
                context.LightBuffer1 = null;
                _shadowMaskRenderer.RecycleShadowMasks();

                sceneQuery.Reset();
            }

            // ----- Copy screens.
            // Copy the previous screens from the temporary render targets into the back buffer.
            context.Viewport        = fullViewport;
            graphicsDevice.Viewport = fullViewport;

            _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone);
            _spriteBatch.Draw(renderTarget0, viewport0.Bounds, Color.White);
            _spriteBatch.Draw(renderTarget1, viewport1.Bounds, Color.White);
            _spriteBatch.Draw(renderTarget2, viewport2.Bounds, Color.White);
            _spriteBatch.End();

            renderTargetPool.Recycle(renderTarget0);
            renderTargetPool.Recycle(renderTarget1);
            renderTargetPool.Recycle(renderTarget2);

            context.Scene         = null;
            context.CameraNode    = null;
            context.LodCameraNode = null;
            context.RenderPass    = null;
        }