Example #1
0
        // Renders the sky. This method is the RenderCallback of the SceneCaptureNode.
        private void RenderSky(RenderContext 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;
        }
Example #2
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;
        }
        /// <summary>
        /// Renders the environment maps for the image-based lights.
        /// </summary>
        /// <remarks>
        /// This method uses the current DeferredGraphicsScreen to render new environment maps at
        /// runtime. The DeferredGraphicsScreen has a SceneCaptureRenderer which we can use to
        /// capture environment maps of the current scene.
        /// To capture new environment maps the flag _updateEnvironmentMaps must be set to true.
        /// When this flag is set, SceneCaptureNodes are added to the scene. When the graphics
        /// screen calls the SceneCaptureRenderer the next time, the new environment maps will be
        /// captured.
        /// The flag _updateEnvironmentMaps remains true until the new environment maps are available.
        /// This method checks the SceneCaptureNode.LastFrame property to check if new environment maps
        /// have been computed. Usually, the environment maps will be available in the next frame.
        /// (However, the XNA Game class can skip graphics rendering if the game is running slowly.
        /// Then we would have to wait more than 1 frame.)
        /// When environment maps are being rendered, the image-based lights are disabled to capture
        /// only the scene with ambient and directional lights. Dynamic objects are also disabled
        /// to capture only the static scene.
        /// </remarks>
        private void UpdateEnvironmentMaps()
        {
            if (!_updateEnvironmentMaps)
            {
                return;
            }

            // One-time initializations:
            if (_sceneCaptureNodes[0] == null)
            {
                // Create cube maps and scene capture nodes.
                // (Note: A cube map size of 256 is enough for surfaces with a specular power
                // in the range [0, 200000].)
                for (int i = 0; i < _sceneCaptureNodes.Length; i++)
                {
                    var renderTargetCube = new RenderTargetCube(
                        GraphicsService.GraphicsDevice,
                        256,
                        true,
                        SurfaceFormat.Color,
                        DepthFormat.None);

                    var renderToTexture = new RenderToTexture {
                        Texture = renderTargetCube
                    };
                    var projection = new PerspectiveProjection();
                    projection.SetFieldOfView(ConstantsF.PiOver2, 1, 1, 100);
                    _sceneCaptureNodes[i] = new SceneCaptureNode(renderToTexture)
                    {
                        CameraNode = new CameraNode(new Camera(projection))
                        {
                            PoseWorld = _lightNodes[i].PoseWorld,
                        },
                    };

                    _imageBasedLights[i].Texture = renderTargetCube;
                }

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

                // The SceneCaptureRenderer has a render callback which defines what is rendered
                // into the scene capture render targets.
                _graphicsScreen.SceneCaptureRenderer.RenderCallback = context =>
                {
                    var graphicsDevice   = GraphicsService.GraphicsDevice;
                    var renderTargetPool = GraphicsService.RenderTargetPool;

                    // Get scene nodes which are visible by the current camera.
                    CustomSceneQuery sceneQuery = context.Scene.Query <CustomSceneQuery>(context.CameraNode, context);

                    // The final image has to be rendered into this render target.
                    var ldrTarget = context.RenderTarget;

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

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

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

            if (_sceneCaptureNodes[0].Parent == null)
            {
                // Add the scene capture nodes to the scene.
                for (int i = 0; i < _sceneCaptureNodes.Length; i++)
                {
                    _graphicsScreen.Scene.Children.Add(_sceneCaptureNodes[i]);
                }

                // Remember the old time stamp of the nodes.
                _oldEnvironmentMapTimeStamp = _sceneCaptureNodes[0].LastFrame;

                // Disable all lights except ambient and directional lights.
                // We do not capture the image-based lights or any other lights (e.g. point lights)
                // in the cube map.
                foreach (var lightNode in _graphicsScreen.Scene.GetDescendants().OfType <LightNode>())
                {
                    lightNode.IsEnabled = (lightNode.Light is AmbientLight) || (lightNode.Light is DirectionalLight);
                }

                // Disable dynamic objects.
                foreach (var node in _graphicsScreen.Scene.GetDescendants())
                {
                    if (node is MeshNode || node is LodGroupNode)
                    {
                        if (!node.IsStatic)
                        {
                            node.IsEnabled = false;
                        }
                    }
                }
            }
            else
            {
                // The scene capture nodes are part of the scene. Check if they have been
                // updated.
                if (_sceneCaptureNodes[0].LastFrame != _oldEnvironmentMapTimeStamp)
                {
                    // We have new environment maps. Restore the normal scene.
                    for (int i = 0; i < _sceneCaptureNodes.Length; i++)
                    {
                        _graphicsScreen.Scene.Children.Remove(_sceneCaptureNodes[i]);
                    }

                    _updateEnvironmentMaps = false;

                    foreach (var lightNode in _graphicsScreen.Scene.GetDescendants().OfType <LightNode>())
                    {
                        lightNode.IsEnabled = true;
                    }

                    foreach (var node in _graphicsScreen.Scene.GetDescendants())
                    {
                        if (node is MeshNode || node is LodGroupNode)
                        {
                            if (!node.IsStatic)
                            {
                                node.IsEnabled = true;
                            }
                        }
                    }
                }
            }
        }
Example #4
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);
        }