protected override void DrawCore(RenderContext context) { var input = GetSafeInput(0); var output = GetSafeOutput(0); // Render the luminance to a power-of-two target, so we preserve energy on downscaling var startWidth = Math.Max(1, Math.Min(MathUtil.NextPowerOfTwo(input.Size.Width), MathUtil.NextPowerOfTwo(input.Size.Height)) / 2); var startSize = new Size3(startWidth, startWidth, 1); var blurTextureSize = startSize.Down2(UpscaleCount); Texture outputTextureDown = null; if (blurTextureSize.Width != 1 && blurTextureSize.Height != 1) { outputTextureDown = NewScopedRenderTarget2D(blurTextureSize.Width, blurTextureSize.Height, luminanceFormat, 1); } var luminanceMap = NewScopedRenderTarget2D(startSize.Width, startSize.Height, luminanceFormat, 1); // Calculate the first luminance map luminanceLogEffect.SetInput(input); luminanceLogEffect.SetOutput(luminanceMap); luminanceLogEffect.Draw(context); // Downscales luminance up to BlurTexture (optional) and 1x1 multiScaler.SetInput(luminanceMap); if (outputTextureDown == null) { multiScaler.SetOutput(luminance1x1); } else { multiScaler.SetOutput(outputTextureDown, luminance1x1); } multiScaler.Draw(); // If we have an output texture if (outputTextureDown != null) { // Blur x2 the intermediate output texture blur.SetInput(outputTextureDown); blur.SetOutput(outputTextureDown); blur.Draw(context); blur.Draw(context); // Upscale from intermediate to output multiScaler.SetInput(outputTextureDown); multiScaler.SetOutput(output); multiScaler.Draw(context); } else { // TODO: Workaround to that the output filled with 1x1 Scaler.SetInput(luminance1x1); Scaler.SetOutput(output); Scaler.Draw(context); } // Calculate average luminance only if needed if (EnableAverageLuminanceReadback) { readback.SetInput(luminance1x1); readback.Draw(); var rawLogValue = readback.Result[0]; AverageLuminance = (float)Math.Pow(2.0, rawLogValue); // In case AvergaeLuminance go crazy because of halp float/infinity precision, some code to save the values here: //if (float.IsInfinity(AverageLuminance)) //{ // using (var stream = new FileStream("luminance_input.dds", FileMode.Create, FileAccess.Write)) // { // input.Save(stream, ImageFileType.Dds); // } // using (var stream = new FileStream("luminance.dds", FileMode.Create, FileAccess.Write)) // { // luminanceMap.Save(stream, ImageFileType.Dds); // } //} } }
protected override void DrawCore(RenderContext context) { var input = GetInput(0); var output = GetOutput(0) ?? input; if (input == null) { return; } // If afterimage is active, add some persistence to the brightness if (afterimage.Enabled) { var persistenceBrightness = NewScopedRenderTarget2D(input.Description); afterimage.SetInput(0, input); afterimage.SetOutput(persistenceBrightness); afterimage.Draw(context); input = persistenceBrightness; } // A distortion can be applied to the bloom effect to simulate anamorphic lenses if (Distortion.X > 1f || Distortion.Y > 1f) { int distortedWidth = (int)Math.Max(1, input.Description.Width / Distortion.X); int distortedHeight = (int)Math.Max(1, input.Description.Height / Distortion.Y); var anamorphicInput = NewScopedRenderTarget2D(distortedWidth, distortedHeight, input.Format); Scaler.SetInput(input); Scaler.SetOutput(anamorphicInput); Scaler.Draw(context, "Anamorphic distortion"); input = anamorphicInput; } // ---------------------------------------- // Downscale / 4 // ---------------------------------------- const int DownScaleBasis = 1; var nextSize = input.Size.Down2(DownScaleBasis); var inputTextureDown4 = NewScopedRenderTarget2D(nextSize.Width, nextSize.Height, input.Format); Scaler.SetInput(input); Scaler.SetOutput(inputTextureDown4); Scaler.Draw(context, "Down/4"); var blurTexture = inputTextureDown4; // TODO: Support automatic additional downscales based on a quality parameter instead // Additional downscales if (DownScale > 0) { nextSize = nextSize.Down2(DownScale); blurTexture = NewScopedRenderTarget2D(nextSize.Width, nextSize.Height, input.Format); multiScaler.SetInput(inputTextureDown4); multiScaler.SetOutput(blurTexture); multiScaler.Draw(context); } // Max blur size no more than 1/4 of input size var inputMaxBlurRadiusInPixels = 0.25 * Math.Max(input.Width, input.Height) * Math.Pow(2, -DownScaleBasis - DownScale); blur.Radius = Math.Max(1, (int)MathUtil.Lerp(1, inputMaxBlurRadiusInPixels, Math.Max(0, Radius / 100.0f))); blur.SigmaRatio = Math.Max(1.0f, SigmaRatio); blur.SetInput(blurTexture); blur.SetOutput(blurTexture); blur.Draw(context); // TODO: Support automatic additional downscales if (DownScale > 0) { multiScaler.SetInput(blurTexture); multiScaler.SetOutput(inputTextureDown4); multiScaler.Draw(context); } // Copy the input texture to the output if (ShowOnlyMip || ShowOnlyBloom) { GraphicsDevice.Clear(output, Color.Black); } // Switch to additive GraphicsDevice.SetBlendState(GraphicsDevice.BlendStates.Additive); Scaler.Color = new Color4(Amount); Scaler.SetInput(inputTextureDown4); Scaler.SetOutput(output); Scaler.Draw(context); Scaler.Reset(); GraphicsDevice.SetBlendState(GraphicsDevice.BlendStates.Default); }