protected override void DrawCore(RenderContext contextParameters) { var input = GetInput(0); var output = GetOutput(0) ?? input; if (input == null) { return; } // Downscale to 1/2 var halfSize = input.Size.Down2(); var halfSizeRenderTarget = NewScopedRenderTarget2D(halfSize.Width, halfSize.Height, input.Format); Scaler.SetInput(input); Scaler.SetOutput(halfSizeRenderTarget); Scaler.Draw(contextParameters, "Downsize to 0.5"); // Work on a blurred bright map var blurredBright = NewScopedRenderTarget2D(halfSizeRenderTarget.Description); blur.Radius = 8; blur.SetInput(halfSizeRenderTarget); blur.SetOutput(blurredBright); blur.Draw(contextParameters); // Draws a few artifacts var flareRenderTargetInitial = NewScopedRenderTarget2D(halfSizeRenderTarget.Description); var flareRenderTarget = NewScopedRenderTarget2D(halfSizeRenderTarget.Description); flareArtifactEffect.Parameters.Set(FlareArtifactKeys.Count, ZoomOffsetsDistortions.Length); flareArtifactEffect.Parameters.Set(FlareArtifactShaderKeys.ZoomOffsetsDistortions, ZoomOffsetsDistortions); flareArtifactEffect.Parameters.Set(FlareArtifactShaderKeys.AberrationStrength, ColorAberrationStrength); flareArtifactEffect.Parameters.Set(FlareArtifactShaderKeys.ColorAberrations, ColorAberrations); flareArtifactEffect.Parameters.Set(FlareArtifactShaderKeys.Amount, Amount * 0.0005f); flareArtifactEffect.SetInput(0, blurredBright); flareArtifactEffect.SetOutput(flareRenderTargetInitial); flareArtifactEffect.Draw(contextParameters); // Replicates the artifacts around flareReplicateEffect.Parameters.Set(FlareReplicateKeys.Amount, Amount * 0.0005f); flareReplicateEffect.Parameters.Set(FlareReplicateKeys.HaloFactor, Amount * 0.0005f * HaloFactor); flareReplicateEffect.SetInput(0, flareRenderTargetInitial); flareReplicateEffect.SetInput(1, blurredBright); flareReplicateEffect.SetOutput(flareRenderTarget); flareReplicateEffect.Draw(contextParameters); // Adds the result to the scene GraphicsDevice.SetBlendState(GraphicsDevice.BlendStates.Additive); Scaler.SetInput(flareRenderTarget); Scaler.SetOutput(output); Scaler.Draw(contextParameters); GraphicsDevice.SetBlendState(GraphicsDevice.BlendStates.Default); }
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(RenderDrawContext contextParameters) { var input = GetInput(0); var output = GetOutput(0) ?? input; if (input == null || StreakCount == 0 || IterationCount == 0) { return; } // Downscale to 1 / 4 var halfSize = input.Size.Down2(); var halfSizeRenderTarget = NewScopedRenderTarget2D(halfSize.Width, halfSize.Height, input.Format); Scaler.SetInput(input); Scaler.SetOutput(halfSizeRenderTarget); Scaler.Draw(contextParameters, "Downsize to 0.5"); var fourthSize = halfSize.Down2(); var fourthSizeRenderTarget = NewScopedRenderTarget2D(fourthSize.Width, fourthSize.Height, input.Format); Scaler.SetInput(halfSizeRenderTarget); Scaler.SetOutput(fourthSizeRenderTarget); Scaler.Draw(contextParameters, "Downsize to 0.25"); var originalDownsize = fourthSizeRenderTarget; // Put all the streaks in an accumulation buffer var accumulationBuffer = NewScopedRenderTarget2D(fourthSizeRenderTarget.Description); // 2 scratch textures to ping-pong between var scratchTextureA = NewScopedRenderTarget2D(fourthSizeRenderTarget.Description); var scratchTextureB = NewScopedRenderTarget2D(fourthSizeRenderTarget.Description); var writeToScratchA = true; Vector2 direction; Texture currentInput = null, currentOutput = null; Vector3 colorAberration; colorAberration.X = (float)MathUtil.Lerp(1.0, ColorAberrationCoefficients.X, ColorAberrationStrength); colorAberration.Y = (float)MathUtil.Lerp(1.0, ColorAberrationCoefficients.Y, ColorAberrationStrength); colorAberration.Z = (float)MathUtil.Lerp(1.0, ColorAberrationCoefficients.Z, ColorAberrationStrength); lightStreakEffect.Parameters.Set(LightStreakShaderKeys.ColorAberrationCoefficients, colorAberration); for (int streak = 0; streak < StreakCount; streak++) { // Treats one streak // Direction vector float angle = MathUtil.DegreesToRadians(Phase) + streak * MathUtil.TwoPi / StreakCount; direction.X = (float)Math.Cos(angle); direction.Y = (float)Math.Sin(angle); // Extends the length recursively for (int level = 0; level < IterationCount; level++) { // Calculates weights and attenuation factors for all the taps float totalWeight = 0; float passLength = (float)Math.Pow(TapsPerIteration, level); for (int i = 0; i < TapsPerIteration; i++) { tapOffsetsWeights[i].X = i * passLength; tapOffsetsWeights[i].Y = (float)Math.Pow(MathUtil.Lerp(0.7f, 1.0f, Attenuation), i * passLength); totalWeight += tapOffsetsWeights[i].Y; } // Normalizes the weights for (int i = 0; i < TapsPerIteration; i++) { tapOffsetsWeights[i].Y /= totalWeight; } currentInput = writeToScratchA ? scratchTextureB : scratchTextureA; if (level == 0) { currentInput = originalDownsize; } currentOutput = writeToScratchA ? scratchTextureA : scratchTextureB; lightStreakEffect.Parameters.Set(LightStreakKeys.Count, TapsPerIteration); lightStreakEffect.Parameters.Set(LightStreakKeys.AnamorphicCount, AnamorphicOffsetsWeights.Length); lightStreakEffect.Parameters.Set(LightStreakShaderKeys.TapOffsetsWeights, tapOffsetsWeights); lightStreakEffect.Parameters.Set(LightStreakShaderKeys.AnamorphicOffsetsWeight, AnamorphicOffsetsWeights); lightStreakEffect.Parameters.Set(LightStreakShaderKeys.Direction, direction); lightStreakEffect.SetInput(0, currentInput); lightStreakEffect.SetOutput(currentOutput); lightStreakEffect.Draw(contextParameters, lightStreakDebugStrings[(streak * IterationCount) + level]); writeToScratchA = !writeToScratchA; } // Writes this streak to the accumulation buffer if (streak > 0) { combiner.BlendState = BlendStates.Additive; } combiner.SetInput(0, currentOutput); combiner.Factors[0] = (1f / StreakCount) * 0.2f * Amount; combiner.SetOutput(accumulationBuffer); ((RendererBase)combiner).Draw(contextParameters); combiner.BlendState = BlendStates.Default; } // All the light streaks have been drawn to the accumulation buffer. // Upscales and blurs the accumulation buffer. var accumulationUpscaled = NewScopedRenderTarget2D(halfSizeRenderTarget.Description); Scaler.SetInput(accumulationBuffer); Scaler.SetOutput(accumulationUpscaled); ((RendererBase)Scaler).Draw(contextParameters); blur.Radius = 3; blur.SetInput(accumulationUpscaled); blur.SetOutput(accumulationUpscaled); ((RendererBase)blur).Draw(contextParameters); // Adds the result to the original color buffer. Scaler.BlendState = BlendStates.Additive; Scaler.SetInput(accumulationUpscaled); Scaler.SetOutput(output); ((RendererBase)Scaler).Draw(contextParameters); Scaler.BlendState = BlendStates.Default; }
protected override void DrawCore(RenderDrawContext 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); ((RendererBase)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); ((RendererBase)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); ((RendererBase)blur).Draw(context); // TODO: Support automatic additional downscales if (DownScale > 0) { multiScaler.SetInput(blurTexture); multiScaler.SetOutput(inputTextureDown4); ((RendererBase)multiScaler).Draw(context); } // Copy the input texture to the output if (ShowOnlyMip || ShowOnlyBloom) { context.CommandList.Clear(output, Color.Black); } // Switch to additive Scaler.BlendState = BlendStates.Additive; Scaler.Color = new Color4(Amount); Scaler.SetInput(inputTextureDown4); Scaler.SetOutput(output); ((RendererBase)Scaler).Draw(context); Scaler.Reset(); Scaler.BlendState = BlendStates.Default; }