Beispiel #1
0
        protected override void OnProcess(RenderContext context)
        {
            context.ThrowIfCameraMissing();
            context.ThrowIfGBuffer0Missing();

            var graphicsDevice   = GraphicsService.GraphicsDevice;
            var cameraNode       = context.CameraNode;
            var renderTargetPool = GraphicsService.RenderTargetPool;

            var source   = context.SourceTexture;
            var target   = context.RenderTarget;
            var viewport = context.Viewport;

            var sourceSize        = new Vector2F(source.Width, source.Height);
            int width             = (int)sourceSize.X;
            int height            = (int)sourceSize.Y;
            int downsampledWidth  = Math.Max(1, width / DownsampleFactor);
            int downsampledHeight = Math.Max(1, height / DownsampleFactor);

            if (TextureHelper.IsFloatingPointFormat(source.Format))
            {
                graphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
                InitializeGaussianBlur(new Vector2F(downsampledWidth, downsampledHeight), false);
            }
            else
            {
                graphicsDevice.SamplerStates[0] = SamplerState.LinearClamp;
                InitializeGaussianBlur(new Vector2F(downsampledWidth, downsampledHeight), true);
            }

            // Get temporary render targets.
            var            downsampleFormat = new RenderTargetFormat(downsampledWidth, downsampledHeight, false, source.Format, DepthFormat.None);
            RenderTarget2D blurredScene0    = renderTargetPool.Obtain2D(downsampleFormat);
            RenderTarget2D blurredScene1    = renderTargetPool.Obtain2D(downsampleFormat);

            var            blurredDepthFormat = new RenderTargetFormat(downsampledWidth, downsampledHeight, false, context.GBuffer0.Format, DepthFormat.None);
            RenderTarget2D blurredDepth0      = renderTargetPool.Obtain2D(blurredDepthFormat);

            var            cocFormat = new RenderTargetFormat(width, height, false, SurfaceFormat.Single, DepthFormat.None);
            RenderTarget2D cocImage  = renderTargetPool.Obtain2D(cocFormat);

            var            downSampledCocFormat = new RenderTargetFormat(downsampledWidth, downsampledHeight, false, cocFormat.SurfaceFormat, DepthFormat.None);
            RenderTarget2D cocImageBlurred      = renderTargetPool.Obtain2D(downSampledCocFormat);

            // ----- Create CoC map.
            _effect.CurrentTechnique = _effect.Techniques[0];
            graphicsDevice.SetRenderTarget(cocImage);
            _screenSizeParameter.SetValue(new Vector2(cocImage.Width, cocImage.Height));
            _depthTextureParameter.SetValue(context.GBuffer0);
            _nearBlurDistanceParameter.SetValue(NearBlurDistance);
            _nearFocusDistanceParameter.SetValue(NearFocusDistance);
            _farFocusDistanceParameter.SetValue(FarFocusDistance);
            _farBlurDistanceParameter.SetValue(FarBlurDistance);
            _farParameter.SetValue(cameraNode.Camera.Projection.Far);
            _circleOfConfusionPass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // ----- Downsample cocImage to cocImageBlurred.
            context.SourceTexture = cocImage;
            context.RenderTarget  = cocImageBlurred;
            context.Viewport      = new Viewport(0, 0, cocImageBlurred.Width, cocImageBlurred.Height);
            _downsampleFilter.Process(context);

            renderTargetPool.Recycle(cocImage);

            // ----- Downsample source to blurredScene0.
            context.SourceTexture = source;
            context.RenderTarget  = blurredScene0;
            context.Viewport      = new Viewport(0, 0, blurredScene0.Width, blurredScene0.Height);
            _downsampleFilter.Process(context);

            // ----- Downsample depth texture to blurredDepth0.
            context.SourceTexture = context.GBuffer0;
            context.RenderTarget  = blurredDepth0;
            context.Viewport      = new Viewport(0, 0, blurredDepth0.Width, blurredDepth0.Height);
            _downsampleFilter.Process(context);

            // ----- Blur scene.
            // Horizontal blur
            graphicsDevice.SetRenderTarget(blurredScene1);
            _screenSizeParameter.SetValue(new Vector2(blurredScene0.Width, blurredScene0.Height));
            _blurTextureParameter.SetValue(blurredScene0);
            _downsampledDepthTextureParameter.SetValue(blurredDepth0);
            _downsampledCocTextureParameter.SetValue(cocImageBlurred);
            _offsetsParameter.SetValue(_horizontalOffsets);
            _weightsParameter.SetValue(_weights);
            _blurPass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // Vertical blur.
            graphicsDevice.SetRenderTarget(blurredScene0);
            _blurTextureParameter.SetValue(blurredScene1);
            _offsetsParameter.SetValue(_verticalOffsets);
            _blurPass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            renderTargetPool.Recycle(blurredScene1);

            // ----- Blur cocImageBlurred.
            context.SourceTexture = cocImageBlurred;
            context.RenderTarget  = cocImageBlurred;
            context.Viewport      = new Viewport(0, 0, cocImageBlurred.Width, cocImageBlurred.Height);
            _cocBlur.Process(context); // We make a two pass blur, so context.SourceTexture can be equal to context.RenderTarget.

            // ----- Blur depth.
            context.SourceTexture = blurredDepth0;
            context.RenderTarget  = blurredDepth0;
            context.Viewport      = new Viewport(0, 0, blurredDepth0.Width, blurredDepth0.Height);
            _cocBlur.Process(context);

            // ----- Create final DoF image.
            _effect.CurrentTechnique = _effect.Techniques[0];
            graphicsDevice.SetRenderTarget(target);
            graphicsDevice.Viewport = viewport;
            _screenSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
            _sceneTextureParameter.SetValue(source);
            _blurTextureParameter.SetValue(blurredScene0);
            _depthTextureParameter.SetValue(context.GBuffer0);
            _downsampledDepthTextureParameter.SetValue(blurredDepth0);
            _downsampledCocTextureParameter.SetValue(cocImageBlurred);
            _depthOfFieldPass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // ----- Clean-up
            _depthTextureParameter.SetValue((Texture2D)null);
            _blurTextureParameter.SetValue((Texture2D)null);
            _downsampledDepthTextureParameter.SetValue((Texture2D)null);
            _downsampledCocTextureParameter.SetValue((Texture2D)null);
            _sceneTextureParameter.SetValue((Texture2D)null);
            renderTargetPool.Recycle(blurredScene0);
            renderTargetPool.Recycle(blurredDepth0);
            renderTargetPool.Recycle(cocImageBlurred);
            context.SourceTexture = source;
            context.RenderTarget  = target;
            context.Viewport      = viewport;
        }
Beispiel #2
0
        protected override void OnProcess(RenderContext context)
        {
            var graphicsDevice   = GraphicsService.GraphicsDevice;
            var renderTargetPool = GraphicsService.RenderTargetPool;

            var source   = context.SourceTexture;
            var target   = context.RenderTarget;
            var viewport = context.Viewport;

            int downsampledWidth  = Math.Max(1, source.Width / DownsampleFactor);
            int downsampledHeight = Math.Max(1, source.Height / DownsampleFactor);

            // ----- Get temporary render targets.
            var sourceDownsampled = renderTargetPool.Obtain2D(new RenderTargetFormat(
                                                                  downsampledWidth,
                                                                  downsampledHeight,
                                                                  false,
                                                                  source.Format,
                                                                  DepthFormat.None));
            var bloom = renderTargetPool.Obtain2D(new RenderTargetFormat(
                                                      downsampledWidth,
                                                      downsampledHeight,
                                                      false,
                                                      SurfaceFormat.Color,
                                                      DepthFormat.None));

            // ----- Downsample scene.
            context.RenderTarget = sourceDownsampled;
            context.Viewport     = new Viewport(0, 0, sourceDownsampled.Width, sourceDownsampled.Height);
            _downsampleFilter.Process(context);

            // ----- Compute luminance.
            context.SourceTexture = sourceDownsampled;
            context.RenderTarget  = _luminanceTarget;
            context.Viewport      = new Viewport(0, 0, _luminanceTarget.Width, _luminanceTarget.Height);
            _luminance.Process(context);

            // ----- Create bloom image.
            graphicsDevice.SetRenderTarget(bloom);
            _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
            _bloomThresholdParameter.SetValue(BloomThreshold);
            _middleGrayParameter.SetValue(MiddleGray);
            _minExposureParameter.SetValue(MinExposure);
            _maxExposureParameter.SetValue(MaxExposure);
            _bloomIntensityParameter.SetValue(BloomIntensity);
            _sceneTextureParameter.SetValue(sourceDownsampled);
            _luminanceTextureParameter.SetValue(_luminanceTarget);
            _brightnessPass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // sourceDownsampled is not needed anymore.
            renderTargetPool.Recycle(sourceDownsampled);

            // We make a two-pass blur, so source can be equal to target.
            context.SourceTexture = bloom;
            context.RenderTarget  = bloom;
            context.Viewport      = new Viewport(0, 0, bloom.Width, bloom.Height);
            _blur.Process(context);

            // ----- Combine scene and bloom.
            graphicsDevice.SetRenderTarget(target);
            graphicsDevice.Viewport = viewport;
            _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
            _sceneTextureParameter.SetValue(source);
            _bloomTextureParameter.SetValue(bloom);
            _luminanceTextureParameter.SetValue(_luminanceTarget);
            _middleGrayParameter.SetValue(MiddleGray);

            if (EnableBlueShift)
            {
                _blueShiftColorParameter.SetValue((Vector3)BlueShiftColor);
                _blueShiftParameter.SetValue(new Vector2(1 / BlueShiftCenter, 1 / BlueShiftRange));
                _combineWithBlueShiftPass.Apply();
            }
            else
            {
                _combinePass.Apply();
            }

            graphicsDevice.DrawFullScreenQuad();

            // ----- Clean-up
            _sceneTextureParameter.SetValue((Texture2D)null);
            _luminanceTextureParameter.SetValue((Texture2D)null);
            _bloomTextureParameter.SetValue((Texture2D)null);
            renderTargetPool.Recycle(bloom);
            context.SourceTexture = source;
            context.RenderTarget  = target;
            context.Viewport      = viewport;
        }
Beispiel #3
0
        protected override void OnProcess(RenderContext context)
        {
            context.ThrowIfCameraMissing();

            var graphicsDevice   = GraphicsService.GraphicsDevice;
            var renderTargetPool = GraphicsService.RenderTargetPool;
            var cameraNode       = context.CameraNode;

            var source   = context.SourceTexture;
            var target   = context.RenderTarget;
            var viewport = context.Viewport;

            if (Quality == 0)
            {
                // No ambient occlusion.
                if (!CombineWithSource)
                {
                    // CombineWithSource is not set. --> Simply clear the render target to white.
                    graphicsDevice.SetRenderTarget(target);
                    graphicsDevice.Viewport = viewport;
                    graphicsDevice.Clear(Color.White);
                }
                else
                {
                    // Copy source image to target.
                    _copyFilter.Process(context);
                }
                return;
            }

            // Try to get downsampled depth buffer from render context.
            // If we cannot find it in the render context, we downsample it manually.
            Texture2D      downsampledDepthTexture = null;
            RenderTarget2D downsampledDepthTarget  = null;

            if (DownsampleFactor == 2)
            {
                object dummy;
                if (context.Data.TryGetValue(RenderContextKeys.DepthBufferHalf, out dummy))
                {
                    downsampledDepthTexture = dummy as Texture2D;
                }
            }

            if (downsampledDepthTexture == null)
            {
                context.ThrowIfGBuffer0Missing();

                if (DownsampleFactor == 1)
                {
                    downsampledDepthTexture = context.GBuffer0;
                }
                else
                {
                    // Downsample manually.
                    // If we do not downsample the depth target, we get artifacts (strange horizontal and vertical
                    // lines). TODO: Check what causes the artifacts and try to remove the downsampling.
                    downsampledDepthTarget = renderTargetPool.Obtain2D(new RenderTargetFormat(
                                                                           context.GBuffer0.Width / DownsampleFactor,
                                                                           context.GBuffer0.Height / DownsampleFactor,
                                                                           false,
                                                                           context.GBuffer0.Format,
                                                                           DepthFormat.None));
                    context.SourceTexture = context.GBuffer0;
                    context.RenderTarget  = downsampledDepthTarget;
                    context.Viewport      = new Viewport(0, 0, downsampledDepthTarget.Width, downsampledDepthTarget.Height);
                    _downsampleFilter.Process(context);
                    downsampledDepthTexture = downsampledDepthTarget;
                }
            }

            // We use two temporary render targets.
            // We do not use a floating point format because float textures cannot use hardware filtering.

            RenderTarget2D temp0;

            if (!CombineWithSource && target != null &&
                target.Width == context.GBuffer0.Width / DownsampleFactor &&
                target.Height == context.GBuffer0.Height / DownsampleFactor &&
                Strength < 1)
            {
                // If we do not have to combine the AO result with the source image, and if the target
                // image has the half resolution, then we can use the target image directly and do not
                // need a temporary render target.
                // Also, a Strength > 1 is always applied in a separate pass because applying a Strength
                // > 1 before the blur has no effect.

                temp0 = target;
            }
            else
            {
                temp0 = renderTargetPool.Obtain2D(new RenderTargetFormat(
                                                      context.GBuffer0.Width / DownsampleFactor,
                                                      context.GBuffer0.Height / DownsampleFactor,
                                                      false,
                                                      SurfaceFormat.Color,
                                                      DepthFormat.None));
            }

            // Create SSAO.
            graphicsDevice.SetRenderTarget(temp0);
            _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
            _farParameter.SetValue(cameraNode.Camera.Projection.Far);
            _radiusParameter.SetValue((Vector2)Radii);
            _maxDistancesParameter.SetValue((Vector2)MaxDistances);
            _strengthParameter.SetValue(Strength < 1 ? Strength : 1);
            _gBuffer0Parameter.SetValue(downsampledDepthTexture);
            if (Quality == 1)
            {
                _createLinesAPass.Apply();
            }
            else
            {
                _createLinesBPass.Apply();
            }

            graphicsDevice.DrawFullScreenQuad();

            if (UseEdgeAwareBlur)
            {
                RenderTarget2D temp1 = renderTargetPool.Obtain2D(new RenderTargetFormat(
                                                                     context.GBuffer0.Width / DownsampleFactor,
                                                                     context.GBuffer0.Height / DownsampleFactor,
                                                                     false,
                                                                     SurfaceFormat.Color,
                                                                     DepthFormat.None));

                for (int i = 0; i < NumberOfBlurPasses; i++)
                {
                    // Blur horizontally.
                    // Note: We use a bilateral filter which is not separable - but the results are still ok
                    // if we use separate the horizontal and vertical blur.
                    graphicsDevice.SetRenderTarget(temp1);
                    _occlusionTextureParameter.SetValue(temp0);
                    _blurHorizontalPass.Apply();
                    graphicsDevice.DrawFullScreenQuad();

                    // Blur vertically.
                    graphicsDevice.SetRenderTarget(temp0);
                    _occlusionTextureParameter.SetValue(temp1);
                    _blurVerticalPass.Apply();
                    graphicsDevice.DrawFullScreenQuad();
                }

                // A few render targets are not needed anymore.
                renderTargetPool.Recycle(downsampledDepthTarget);
                renderTargetPool.Recycle(temp1);
            }
            else
            {
                // A few render targets are not needed anymore.
                renderTargetPool.Recycle(downsampledDepthTarget);

                context.SourceTexture = temp0;
                context.RenderTarget  = temp0;
                context.Viewport      = new Viewport(0, 0, temp0.Width, temp0.Height);
                for (int i = 0; i < NumberOfBlurPasses; i++)
                {
                    _blur.Process(context);
                }
            }

            _strengthParameter.SetValue(Strength > 1 ? Strength : 1);

            if (CombineWithSource)
            {
                if (TextureHelper.IsFloatingPointFormat(source.Format))
                {
                    graphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
                }
                else
                {
                    graphicsDevice.SamplerStates[0] = SamplerState.LinearClamp;
                }

                // Combine with scene.
                graphicsDevice.SetRenderTarget(target);
                graphicsDevice.Viewport = viewport;
                _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
                _occlusionTextureParameter.SetValue(temp0);
                _sourceTextureParameter.SetValue(source);
                _combinePass.Apply();
                graphicsDevice.DrawFullScreenQuad();
            }
            else
            {
                if (temp0 != target)
                {
                    graphicsDevice.SetRenderTarget(target);
                    graphicsDevice.Viewport = viewport;
                    _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
                    _occlusionTextureParameter.SetValue(temp0);
                    _copyPass.Apply();
                    graphicsDevice.DrawFullScreenQuad();
                }
            }

            // Clean-up
            if (temp0 != target)
            {
                renderTargetPool.Recycle(temp0);
            }

            _sourceTextureParameter.SetValue((Texture2D)null);
            _gBuffer0Parameter.SetValue((Texture2D)null);
            _occlusionTextureParameter.SetValue((Texture2D)null);
            context.SourceTexture = source;
            context.RenderTarget  = target;
            context.Viewport      = viewport;
        }
Beispiel #4
0
        protected override void OnProcess(RenderContext context)
        {
            context.ThrowIfCameraMissing();
            context.ThrowIfGBuffer0Missing();

            var graphicsDevice   = GraphicsService.GraphicsDevice;
            var renderTargetPool = GraphicsService.RenderTargetPool;

            var source   = context.SourceTexture;
            var target   = context.RenderTarget;
            var viewport = context.Viewport;

            // Get temporary render targets.
            var sourceSize            = new Vector2F(source.Width, source.Height);
            var isFloatingPointFormat = TextureHelper.IsFloatingPointFormat(source.Format);

            var sceneFormat = new RenderTargetFormat(source.Width, source.Height, false, source.Format, DepthFormat.None);
            var maskedScene = renderTargetPool.Obtain2D(sceneFormat);

            var rayFormat = new RenderTargetFormat(
                Math.Max(1, (int)(sourceSize.X / DownsampleFactor)),
                Math.Max(1, (int)(sourceSize.Y / DownsampleFactor)),
                false,
                source.Format,
                DepthFormat.None);
            var rayImage0 = renderTargetPool.Obtain2D(rayFormat);
            var rayImage1 = renderTargetPool.Obtain2D(rayFormat);

            // Get view and view-projection transforms.
            var    cameraNode     = context.CameraNode;
            Matrix projection     = cameraNode.Camera.Projection.ToMatrix();
            Matrix view           = cameraNode.View;
            Matrix viewProjection = projection * view;

            // We simply place the light source "far away" in opposite light ray direction.
            Vector4 lightPositionWorld = new Vector4(-LightDirection * 10000, 1);

            // Convert to clip space.
            Vector4 lightPositionProj = viewProjection * lightPositionWorld;
            Vector3 lightPositionClip = Vector4.HomogeneousDivide(lightPositionProj);

            // Convert from clip space [-1, 1] to texture space [0, 1].
            Vector2 lightPosition = new Vector2(lightPositionClip.X * 0.5f + 0.5f, -lightPositionClip.Y * 0.5f + 0.5f);

            // We use dot²(forward, -LightDirection) as a smooth S-shaped attenuation
            // curve to reduce the god ray effect when we look orthogonal or away from the sun.
            var   lightDirectionView = view.TransformDirection(LightDirection);
            float z           = Math.Max(0, lightDirectionView.Z);
            float attenuation = z * z;

            // Common effect parameters.
            _parameters0Parameter.SetValue(new Vector4(lightPosition.X, lightPosition.Y, LightRadius * LightRadius, Scale));
            _parameters1Parameter.SetValue(new Vector2(Softness, graphicsDevice.Viewport.AspectRatio));
            _intensityParameter.SetValue((Vector3)Intensity * attenuation);
            _numberOfSamplesParameter.SetValue(NumberOfSamples);
            _gBuffer0Parameter.SetValue(context.GBuffer0);

            // First, create a scene image where occluders are black.
            graphicsDevice.SetRenderTarget(maskedScene);
            _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
            _sourceTextureParameter.SetValue(source);
            graphicsDevice.SamplerStates[0] = isFloatingPointFormat ? SamplerState.PointClamp : SamplerState.LinearClamp;
            graphicsDevice.SamplerStates[1] = SamplerState.PointClamp; // G-Buffer 0.
            _createMaskPass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // Downsample image.
            context.SourceTexture = maskedScene;
            context.RenderTarget  = rayImage0;
            context.Viewport      = new Viewport(0, 0, rayImage0.Width, rayImage0.Height);
            _downsampleFilter.Process(context);

            // Compute light shafts.
            _viewportSizeParameter.SetValue(new Vector2(context.Viewport.Width, context.Viewport.Height));
            graphicsDevice.SamplerStates[0] = isFloatingPointFormat ? SamplerState.PointClamp : SamplerState.LinearClamp;
            for (int i = 0; i < NumberOfPasses; i++)
            {
                graphicsDevice.SetRenderTarget(rayImage1);
                _sourceTextureParameter.SetValue(rayImage0);
                _blurPass.Apply();
                graphicsDevice.DrawFullScreenQuad();

                // Put the current result in variable rayImage0.
                MathHelper.Swap(ref rayImage0, ref rayImage1);
            }

            // Combine light shaft image with scene.
            graphicsDevice.SetRenderTarget(target);
            graphicsDevice.Viewport = viewport;
            _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
            _sourceTextureParameter.SetValue(source);
            _rayTextureParameter.SetValue(rayImage0);
            graphicsDevice.SamplerStates[0] = isFloatingPointFormat ? SamplerState.PointClamp : SamplerState.LinearClamp;
            graphicsDevice.SamplerStates[1] = isFloatingPointFormat ? SamplerState.PointClamp : SamplerState.LinearClamp;
            _combinePass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // Clean-up
            _sourceTextureParameter.SetValue((Texture2D)null);
            _gBuffer0Parameter.SetValue((Texture2D)null);
            _rayTextureParameter.SetValue((Texture2D)null);
            renderTargetPool.Recycle(maskedScene);
            renderTargetPool.Recycle(rayImage0);
            renderTargetPool.Recycle(rayImage1);
            context.SourceTexture = source;
            context.RenderTarget  = target;
            context.Viewport      = viewport;
        }
Beispiel #5
0
        protected override void OnProcess(RenderContext context)
        {
            if (TextureHelper.IsFloatingPointFormat(context.SourceTexture.Format))
            {
                throw new GraphicsException("Source texture format must not be a floating-point format.");
            }

            var graphicsDevice   = GraphicsService.GraphicsDevice;
            var renderTargetPool = GraphicsService.RenderTargetPool;

            var source   = context.SourceTexture;
            var target   = context.RenderTarget;
            var viewport = context.Viewport;

            int downsampledWidth  = Math.Max(1, source.Width / DownsampleFactor);
            int downsampledHeight = Math.Max(1, source.Height / DownsampleFactor);

            // ----- Get temporary render targets.
            var            bloomFormat = new RenderTargetFormat(downsampledWidth, downsampledHeight, false, SurfaceFormat.Color, DepthFormat.None);
            RenderTarget2D bloom0      = renderTargetPool.Obtain2D(bloomFormat);
            RenderTarget2D bloom1      = renderTargetPool.Obtain2D(bloomFormat);

            // ----- Downsample scene to bloom0.
            context.RenderTarget = bloom0;
            context.Viewport     = new Viewport(0, 0, bloom0.Width, bloom0.Height);
            _downsampleFilter.Process(context);

            // ----- Create bloom image
            graphicsDevice.SetRenderTarget(bloom1);
            _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
            _bloomThresholdParameter.SetValue(Threshold);
            _bloomIntensityParameter.SetValue(Intensity);
            _bloomSaturationParameter.SetValue(Saturation);
            _sceneTextureParameter.SetValue(bloom0);
            _brightnessPass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // bloom0 is not needed anymore.
            renderTargetPool.Recycle(bloom0);

            // We make a two-pass blur, so source can be equal to target.
            context.SourceTexture = bloom1;
            context.RenderTarget  = bloom1;
            _blur.Process(context);

            // ----- Combine scene and bloom.
            graphicsDevice.SetRenderTarget(target);
            graphicsDevice.Viewport = viewport;
            _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
            _sceneTextureParameter.SetValue(source);
            _bloomTextureParameter.SetValue(bloom1);
            _combinePass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // ----- Clean-up
            _sceneTextureParameter.SetValue((Texture2D)null);
            _bloomTextureParameter.SetValue((Texture2D)null);
            renderTargetPool.Recycle(bloom1);

            // Restore original context.
            context.SourceTexture = source;
            context.RenderTarget  = target;
            context.Viewport      = viewport;
        }
        protected override void OnProcess(RenderContext context)
        {
            context.ThrowIfCameraMissing();

            var graphicsDevice   = GraphicsService.GraphicsDevice;
            var renderTargetPool = GraphicsService.RenderTargetPool;
            var source           = context.SourceTexture;
            var target           = context.RenderTarget;
            var viewport         = context.Viewport;

            RenderTarget2D temp128x128 = renderTargetPool.Obtain2D(
                new RenderTargetFormat(128, 128, false, SurfaceFormat.HalfVector4, DepthFormat.None));
            RenderTarget2D temp64x64 = renderTargetPool.Obtain2D(
                new RenderTargetFormat(64, 64, false, SurfaceFormat.HalfVector4, DepthFormat.None));
            RenderTarget2D luminance = renderTargetPool.Obtain2D(
                new RenderTargetFormat(1, 1, false, SurfaceFormat.HalfVector4, DepthFormat.None));

            // ----- Downsample scene into temp128x128.
            context.RenderTarget = temp128x128;
            context.Viewport     = new Viewport(0, 0, temp128x128.Width, temp128x128.Height);
            _downsampleFilter.Process(context);

            _useGeometricMeanParameter.SetValue(UseGeometricMean);

            // Get view-dependent information stored in camera node.
            var    cameraNode = context.CameraNode;
            object dummy;

            cameraNode.ViewDependentData.TryGetValue(this, out dummy);
            var data = dummy as ViewDependentData;

            if (data == null)
            {
                data = new ViewDependentData(GraphicsService);
                cameraNode.ViewDependentData[this] = data;
            }

            if (UseAdaption)
            {
                // Use adaption if required by user and if we already have luminance info.
                _useAdaptionParameter.SetValue(data.LastLuminance != null);
                _deltaTimeParameter.SetValue((float)context.DeltaTime.TotalSeconds);
                _adaptionSpeedParameter.SetValue(AdaptionSpeed);
                _lastLuminanceTextureParameter.SetValue(data.LastLuminance);
            }
            else
            {
                _useAdaptionParameter.SetValue(false);
                _lastLuminanceTextureParameter.SetValue((Texture2D)null);

                // Reset old luminance info.
                data.Dispose();
            }

            // ----- First downsample temp128x128 into temp64x64 and create luminance info.
            graphicsDevice.SetRenderTarget(temp64x64);
            _textureParameter.SetValue(temp128x128);
            _sourceSizeParameter.SetValue(new Vector2(temp128x128.Width, temp128x128.Height));
            _targetSizeParameter.SetValue(new Vector2(temp64x64.Width, temp64x64.Height));
            _createPass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // temp128x128 is not needed anymore.
            renderTargetPool.Recycle(temp128x128);

            // ----- Downsample luminance info.
            RenderTarget2D last = temp64x64;

            while (last.Width > 2)
            {
                Debug.Assert(last.Width == last.Height, "The render target must be quadratic");

                RenderTarget2D temp = renderTargetPool.Obtain2D(
                    new RenderTargetFormat(last.Width / 2, last.Height / 2, false, last.Format, DepthFormat.None));

                graphicsDevice.SetRenderTarget(temp);
                _textureParameter.SetValue(last);
                _sourceSizeParameter.SetValue(new Vector2(last.Width, last.Height));
                _targetSizeParameter.SetValue(new Vector2(temp.Width, temp.Height));
                _downsamplePass.Apply();
                graphicsDevice.DrawFullScreenQuad();

                renderTargetPool.Recycle(last);
                last = temp;
            }

            // ----- Sample 'last' and store final info in 'luminance'.
            graphicsDevice.SetRenderTarget(luminance);
            _textureParameter.SetValue(last);
            _sourceSizeParameter.SetValue(new Vector2(last.Width, last.Height));
            _targetSizeParameter.SetValue(new Vector2(luminance.Width, luminance.Height));
            _finalPass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            renderTargetPool.Recycle(last);

            // ----- Copy luminance to original context.RenderTarget.
            context.SourceTexture = luminance;
            context.RenderTarget  = target;
            context.Viewport      = viewport;
            _copyFilter.Process(context);

            // ----- Store luminance for next frame.
            renderTargetPool.Recycle(data.LastLuminance);
            data.LastLuminance = luminance;

            // Restore original context.
            context.SourceTexture = source;

            _textureParameter.SetValue((Texture2D)null);
        }