Example #1
0
        protected override void DrawCore(RenderContext context)
        {
            var input  = GetInput(0);
            var output = GetOutput(0);

            if (input == null || output == null)
            {
                return;
            }

            // Gets the current camera state
            var camera = context.GetCameraFromSlot(Camera);

            if (camera != null)
            {
                // Update the parameters for this post effect
                CameraComponentRenderer.UpdateParameters(context, camera);
            }

            if (!Enabled)
            {
                if (input != output)
                {
                    Scaler.SetInput(input);
                    Scaler.SetOutput(output);
                    Scaler.Draw(context);
                }
                return;
            }

            // If input == output, than copy the input to a temporary texture
            if (input == output)
            {
                var newInput = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);
                GraphicsDevice.Copy(input, newInput);
                input = newInput;
            }

            var currentInput = input;

            if (depthOfField.Enabled && !depthOfField.Faulted && InputCount > 1 && GetInput(1) != null && GetInput(1).IsDepthStencil)
            {
                // DoF
                var dofOutput         = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);
                var inputDepthTexture = GetInput(1); // Depth
                depthOfField.SetColorDepthInput(input, inputDepthTexture);
                depthOfField.SetOutput(dofOutput);
                depthOfField.Draw(context);
                currentInput = dofOutput;
            }

            // Luminance pass (only if tone mapping is enabled)
            // TODO: This is not super pluggable to have this kind of dependencies. Check how to improve this
            var toneMap = colorTransformsGroup.Transforms.Get <ToneMap>();

            if (colorTransformsGroup.Enabled && !colorTransformsGroup.Faulted && toneMap != null && toneMap.Enabled)
            {
                const int LocalLuminanceDownScale = 3;

                // The luminance chain uses power-of-two intermediate targets, so it expects to output to one as well
                var lumWidth = Math.Min(MathUtil.NextPowerOfTwo(currentInput.Size.Width), MathUtil.NextPowerOfTwo(currentInput.Size.Height));
                lumWidth = Math.Max(1, lumWidth / 2);

                var lumSize          = new Size3(lumWidth, lumWidth, 1).Down2(LocalLuminanceDownScale);
                var luminanceTexture = NewScopedRenderTarget2D(lumSize.Width, lumSize.Height, PixelFormat.R16_Float, 1);

                luminanceEffect.SetInput(currentInput);
                luminanceEffect.SetOutput(luminanceTexture);
                luminanceEffect.Draw(context);

                // Set this parameter that will be used by the tone mapping
                colorTransformsGroup.Parameters.Set(LuminanceEffect.LuminanceResult, new LuminanceResult(luminanceEffect.AverageLuminance, luminanceTexture));
            }

            // Bright filter pass
            Texture brightTexture = null;

            if ((bloom.Enabled && !bloom.Faulted) || (lightStreak.Enabled && !lightStreak.Faulted) || (lensFlare.Enabled && !lensFlare.Faulted))
            {
                brightTexture = NewScopedRenderTarget2D(currentInput.Width, currentInput.Height, currentInput.Format, 1);

                brightFilter.SetInput(currentInput);
                brightFilter.SetOutput(brightTexture);
                brightFilter.Draw(context);
            }

            // Bloom pass
            if (bloom.Enabled && !bloom.Faulted)
            {
                bloom.SetInput(brightTexture);
                bloom.SetOutput(currentInput);
                bloom.Draw(context);
            }

            // Light streak pass
            if (lightStreak.Enabled && !lightStreak.Faulted)
            {
                lightStreak.SetInput(brightTexture);
                lightStreak.SetOutput(currentInput);
                lightStreak.Draw(context);
            }

            // Lens flare pass
            if (lensFlare.Enabled && !lensFlare.Faulted)
            {
                lensFlare.SetInput(brightTexture);
                lensFlare.SetOutput(currentInput);
                lensFlare.Draw(context);
            }

            var outputForLastEffectBeforeAntiAliasing = output;

            if (ssaa != null && ssaa.Enabled && !ssaa.Faulted)
            {
                outputForLastEffectBeforeAntiAliasing = NewScopedRenderTarget2D(output.Width, output.Height, output.Format);
            }

            // When FXAA is enabled we need to detect whether the ColorTransformGroup should output the Luminance into the alpha or not
            var fxaa = ssaa as FXAAEffect;
            var luminanceToChannelTransform = colorTransformsGroup.PostTransforms.Get <LuminanceToChannelTransform>();

            if (fxaa != null)
            {
                if (luminanceToChannelTransform == null)
                {
                    luminanceToChannelTransform = new LuminanceToChannelTransform {
                        ColorChannel = ColorChannel.A
                    };
                    colorTransformsGroup.PostTransforms.Add(luminanceToChannelTransform);
                }

                // Only enabled when FXAA is enabled and InputLuminanceInAlpha is true
                luminanceToChannelTransform.Enabled = fxaa.Enabled && fxaa.InputLuminanceInAlpha;
            }
            else if (luminanceToChannelTransform != null)
            {
                luminanceToChannelTransform.Enabled = false;
            }

            // Color transform group pass (tonemap, color grading)
            var lastEffect = colorTransformsGroup.Enabled && !colorTransformsGroup.Faulted ? (ImageEffect)colorTransformsGroup: Scaler;

            lastEffect.SetInput(currentInput);
            lastEffect.SetOutput(outputForLastEffectBeforeAntiAliasing);
            lastEffect.Draw(context);

            if (ssaa != null && ssaa.Enabled && !ssaa.Faulted)
            {
                ssaa.SetInput(outputForLastEffectBeforeAntiAliasing);
                ssaa.SetOutput(output);
                ssaa.Draw(context);
            }
        }
Example #2
0
        public bool RequiresSsrGBuffers => false; // localReflections.Enabled; TODO : to merge with RLR branch.

        protected override void DrawCore(RenderDrawContext context)
        {
            var input  = GetInput(0);
            var output = GetOutput(0);

            if (input == null || output == null)
            {
                return;
            }

            var inputDepthTexture = GetInput(1); // Depth

            // Update the parameters for this post effect
            if (!Enabled)
            {
                if (input != output)
                {
                    Scaler.SetInput(input);
                    Scaler.SetOutput(output);
                    Scaler.Draw(context);
                }
                return;
            }

            // If input == output, than copy the input to a temporary texture
            if (input == output)
            {
                var newInput = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);
                context.CommandList.Copy(input, newInput);
                input = newInput;
            }

            var currentInput = input;

            var  fxaa    = Antialiasing as FXAAEffect;
            bool aaFirst = Bloom != null && Bloom.StableConvolution;
            bool needAA  = fxaa != null && fxaa.Enabled;

            // do AA here, first. (hybrid method from Karis2013)
            if (aaFirst && needAA)
            {
                using (context.QueryManager.BeginProfile(Color.Green, ImageEffectProfilingKeys.HybridFxaa))
                {
                    // explanation:
                    // The Karis method (Unreal Engine 4.1x), uses a hybrid pipeline to execute AA.
                    // The AA is usually done at the end of the pipeline, but we don't benefit from
                    // AA for the posteffects, which is a shame.
                    // The Karis method, executes AA at the beginning, but for AA to be correct, it must work post tonemapping,
                    // and even more in fact, in gamma space too. Plus, it waits for the alpha=luma to be a "perceptive luma" so also gamma space.
                    // in our case, working in gamma space created monstruous outlining artefacts around eggageratedely strong constrasted objects (way in hdr range).
                    // so AA works in linear space, but still with gamma luma, as a light tradeoff to supress artefacts.

                    // create a 16 bits target for FXAA:
                    var aaSurface = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);

                    // render range compression & perceptual luma to alpha channel:
                    rangeCompress.SetInput(currentInput);
                    rangeCompress.SetOutput(aaSurface);
                    rangeCompress.Draw(context);

                    // do AA:
                    fxaa.InputLuminanceInAlpha = true;
                    Antialiasing.SetInput(aaSurface);
                    Antialiasing.SetOutput(currentInput);
                    Antialiasing.Draw(context);

                    // reverse tone LDR to HDR:
                    rangeDecompress.SetInput(currentInput);
                    rangeDecompress.SetOutput(aaSurface);
                    rangeDecompress.Draw(context);
                    currentInput = aaSurface;
                }
            }

            if (AmbientOcclusion.Enabled && inputDepthTexture != null)
            {
                using (context.QueryManager.BeginProfile(Color.Green, ImageEffectProfilingKeys.AmbientOcclusion))
                {
                    // Ambient Occlusion
                    var aoOutput = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);
                    AmbientOcclusion.SetColorDepthInput(currentInput, inputDepthTexture);
                    AmbientOcclusion.SetOutput(aoOutput);
                    AmbientOcclusion.Draw(context);
                    currentInput = aoOutput;
                }
            }

            if (DepthOfField.Enabled && inputDepthTexture != null)
            {
                using (context.QueryManager.BeginProfile(Color.Green, ImageEffectProfilingKeys.DepthOfField))
                {
                    // DoF
                    var dofOutput = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);
                    DepthOfField.SetColorDepthInput(currentInput, inputDepthTexture);
                    DepthOfField.SetOutput(dofOutput);
                    DepthOfField.Draw(context);
                    currentInput = dofOutput;
                }
            }

            // Luminance pass (only if tone mapping is enabled)
            // TODO: This is not super pluggable to have this kind of dependencies. Check how to improve this
            var toneMap = colorTransformsGroup.Transforms.Get <ToneMap>();

            if (colorTransformsGroup.Enabled && toneMap != null && toneMap.Enabled)
            {
                using (context.QueryManager.BeginProfile(Color.Green, ImageEffectProfilingKeys.AverageLumiance))
                {
                    Texture luminanceTexture = null;
                    if (toneMap.UseLocalLuminance)
                    {
                        const int localLuminanceDownScale = 3;

                        // The luminance chain uses power-of-two intermediate targets, so it expects to output to one as well
                        var lumWidth = Math.Min(MathUtil.NextPowerOfTwo(currentInput.Size.Width), MathUtil.NextPowerOfTwo(currentInput.Size.Height));
                        lumWidth = Math.Max(1, lumWidth / 2);

                        var lumSize = new Size3(lumWidth, lumWidth, 1).Down2(localLuminanceDownScale);
                        luminanceTexture = NewScopedRenderTarget2D(lumSize.Width, lumSize.Height, PixelFormat.R16_Float, 1);

                        luminanceEffect.SetOutput(luminanceTexture);
                    }

                    luminanceEffect.EnableLocalLuminanceCalculation = toneMap.UseLocalLuminance;
                    luminanceEffect.SetInput(currentInput);
                    luminanceEffect.Draw(context);

                    // Set this parameter that will be used by the tone mapping
                    colorTransformsGroup.Parameters.Set(LuminanceEffect.LuminanceResult, new LuminanceResult(luminanceEffect.AverageLuminance, luminanceTexture));
                }
            }

            if (BrightFilter.Enabled && (Bloom.Enabled || LightStreak.Enabled || LensFlare.Enabled))
            {
                Texture brightTexture = NewScopedRenderTarget2D(currentInput.Width, currentInput.Height, currentInput.Format, 1);
                using (context.QueryManager.BeginProfile(Color.Green, ImageEffectProfilingKeys.BrightFilter))
                {
                    // Bright filter pass

                    BrightFilter.SetInput(currentInput);
                    BrightFilter.SetOutput(brightTexture);
                    BrightFilter.Draw(context);
                }

                // Bloom pass
                if (Bloom.Enabled)
                {
                    using (context.QueryManager.BeginProfile(Color.Green, ImageEffectProfilingKeys.Bloom))
                    {
                        Bloom.SetInput(brightTexture);
                        Bloom.SetOutput(currentInput);
                        Bloom.Draw(context);
                    }
                }

                // Light streak pass
                if (LightStreak.Enabled)
                {
                    using (context.QueryManager.BeginProfile(Color.Green, ImageEffectProfilingKeys.LightStreak))
                    {
                        LightStreak.SetInput(brightTexture);
                        LightStreak.SetOutput(currentInput);
                        LightStreak.Draw(context);
                    }
                }

                // Lens flare pass
                if (LensFlare.Enabled)
                {
                    using (context.QueryManager.BeginProfile(Color.Green, ImageEffectProfilingKeys.LensFlare))
                    {
                        LensFlare.SetInput(brightTexture);
                        LensFlare.SetOutput(currentInput);
                        LensFlare.Draw(context);
                    }
                }
            }

            bool aaLast     = needAA && !aaFirst;
            var  toneOutput = aaLast ? NewScopedRenderTarget2D(input.Width, input.Height, input.Format) : output;

            // When FXAA is enabled we need to detect whether the ColorTransformGroup should output the Luminance into the alpha or not
            var luminanceToChannelTransform = colorTransformsGroup.PostTransforms.Get <LuminanceToChannelTransform>();

            if (fxaa != null)
            {
                if (luminanceToChannelTransform == null)
                {
                    luminanceToChannelTransform = new LuminanceToChannelTransform {
                        ColorChannel = ColorChannel.A
                    };
                    colorTransformsGroup.PostTransforms.Add(luminanceToChannelTransform);
                }

                // Only enabled when FXAA is enabled and InputLuminanceInAlpha is true
                luminanceToChannelTransform.Enabled = fxaa.Enabled && fxaa.InputLuminanceInAlpha;
            }
            else if (luminanceToChannelTransform != null)
            {
                luminanceToChannelTransform.Enabled = false;
            }

            using (context.QueryManager.BeginProfile(Color.Green, ImageEffectProfilingKeys.ColorTransformGroup))
            {
                // Color transform group pass (tonemap, color grading)
                var lastEffect = colorTransformsGroup.Enabled ? (ImageEffect)colorTransformsGroup : Scaler;
                lastEffect.SetInput(currentInput);
                lastEffect.SetOutput(toneOutput);
                lastEffect.Draw(context);
            }

            // do AA here, last, if not already done.
            if (aaLast)
            {
                using (context.QueryManager.BeginProfile(Color.Green, ImageEffectProfilingKeys.Fxaa))
                {
                    Antialiasing.SetInput(toneOutput);
                    Antialiasing.SetOutput(output);
                    Antialiasing.Draw(context);
                }
            }
        }