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