Monogame + Bloom

@Ravendarke a scene… a character and some graphics, and I want to bloom them all, the draw scene works. does it really matter?

if it helps, I removed most of the stuff, lets say I only draw one texture

protected void DrawSceneToTexture(RenderTarget2D renderTarget,GameTime gametime)
    {
        GraphicsDevice.SetRenderTarget(renderTarget);
        GraphicsDevice.Clear(Color.CornflowerBlue);
        spriteBatch.Begin(SpriteSortMode.Immediate,
 BlendState.AlphaBlend,
 SamplerState.PointClamp,
 null, null, null, null);
        spriteBatch.Draw(cursorTex, cursorPos, cursorSource,
               Color.White, 0.0f, Vector2.Zero, 3f, SpriteEffects.None, 0);
        spriteBatch.End();
        GraphicsDevice.SetRenderTarget(null);
    }

scene is now the blue background I set, the texture is not seen.

@Ravendarke I’ve just fixed the .fx the way you said, still blue screen :frowning: it wont draw any texture

edit:

uhmm, it seems like when I change bloom settings screen color changes, perhaps it blooms the background only for some reason

It is really impossible to debug it like this. I don´t, maybe your texture is black and it is under threshold for bloom, might be still the fact that bloom is component… personally, as I said, I would rewrite it into normal class (not XNA game component) or even better write new one which you will completely understand (you can still use helpers from old one).

You said you fixed shader, have you fixed parameter set (texture) in bloom component code?

@Ravendarke by setting bloom.ShowBuffer = BloomComponent.IntermediateBuffer here is what being drawn:

PRE-BLOOM:


BLURRED BOTH WAYS:

FINAL RESULT:

Bloom Combine:

// Pixel shader combines the bloom image with the original
// scene, using tweakable intensity levels and saturation.
// This is the final step in applying a bloom postprocess.

sampler BloomSampler : register(s0);
sampler BaseSampler : register(s1)
{ 
    Texture = (BaseTexture);  
    Filter = Linear;  
    AddressU = clamp;
    AddressV = clamp;
};

float BloomIntensity;
float BaseIntensity;

float BloomSaturation;
float BaseSaturation;


// Helper for modifying the saturation of a color.
float4 AdjustSaturation(float4 color, float saturation)
{
    // The constants 0.3, 0.59, and 0.11 are chosen because the
    // human eye is more sensitive to green light, and less to blue.
    float grey = dot(color, float3(0.3, 0.59, 0.11));

    return lerp(grey, color, saturation);
}


float4 PixelShaderFunction(float2 texCoord : TEXCOORD0) : COLOR0
{
    // Look up the bloom and original base image colors.
    float4 bloom = tex2D(BloomSampler, texCoord);
    float4 base = tex2D(BaseSampler, texCoord);
    
    // Adjust color saturation and intensity.
    bloom = AdjustSaturation(bloom, BloomSaturation) * BloomIntensity;
    base = AdjustSaturation(base, BaseSaturation) * BaseIntensity;
    
    // Darken down the base image in areas where there is a lot of bloom,
    // to prevent things looking excessively burned-out.
    base *= (1 - saturate(bloom));
    
    // Combine the two images.
    return base + bloom;
}


technique BloomCombine
{
                pass Pass1

                {

                                #if SM4

                                                PixelShader = compile ps_4_0_level_9_1 PixelShaderFunction();

                                #elif SM3

                                                PixelShader = compile ps_3_0 PixelShaderFunction();

                                #else

                                                PixelShader = compile ps_2_0 PixelShaderFunction();

                                #endif

                }

}

Bloom Compontent with set texture in parameter:

#region File Description
//-----------------------------------------------------------------------------
// BloomComponent.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
#endregion

namespace BloomPostprocess
{
    public class BloomComponent : DrawableGameComponent
    {
        #region Fields

        SpriteBatch spriteBatch;

        Effect bloomExtractEffect;
        Effect bloomCombineEffect;
        Effect gaussianBlurEffect;

        RenderTarget2D renderTarget1;
        RenderTarget2D renderTarget2;


        // Choose what display settings the bloom should use.
        public BloomSettings Settings
        {
            get { return settings; }
            set { settings = value; }
        }

        BloomSettings settings = BloomSettings.PresetSettings[0];


        // Optionally displays one of the intermediate buffers used
        // by the bloom postprocess, so you can see exactly what is
        // being drawn into each rendertarget.
        public enum IntermediateBuffer
        {
            PreBloom,
            BlurredHorizontally,
            BlurredBothWays,
            FinalResult,
        }

        public IntermediateBuffer ShowBuffer
        {
            get { return showBuffer; }
            set { showBuffer = value; }
        }

        IntermediateBuffer showBuffer = IntermediateBuffer.FinalResult;


        #endregion

        #region Initialization


        public BloomComponent(Game game)
            : base(game)
        {
            if (game == null)
                throw new ArgumentNullException("game");
        }


        /// <summary>
        /// Load your graphics content.
        /// </summary>
        public void LoadContent(GraphicsDevice g, ContentManager theContentManager)
        {
            spriteBatch = new SpriteBatch(g);
            bloomExtractEffect = theContentManager.Load<Effect>("BloomExtract");
            bloomCombineEffect = theContentManager.Load<Effect>("BloomCombine");
            gaussianBlurEffect = theContentManager.Load<Effect>("GaussianBlur");

            // Look up the resolution and format of our main backbuffer.
            PresentationParameters pp = g.PresentationParameters;

            int width = pp.BackBufferWidth;
            int height = pp.BackBufferHeight;

            SurfaceFormat format = pp.BackBufferFormat;

            // Create a texture for rendering the main scene, prior to applying bloom.


            // Create two rendertargets for the bloom processing. These are half the
            // size of the backbuffer, in order to minimize fillrate costs. Reducing
            // the resolution in this way doesn't hurt quality, because we are going
            // to be blurring the bloom images in any case.
            width /= 2;
            height /= 2;

            renderTarget1 = new RenderTarget2D(g, width, height, false, format, DepthFormat.Depth24);
            renderTarget2 = new RenderTarget2D(g, width, height, false, format, DepthFormat.Depth24);
        }


        /// <summary>
        /// Unload your graphics content.
        /// </summary>
        public void UnloadContent(ContentManager theContentManager)
        {
            renderTarget1.Dispose();
            renderTarget2.Dispose();
        }


        #endregion

        #region Draw


        /// <summary>
        /// This should be called at the very start of the scene rendering. The bloom
        /// component uses it to redirect drawing into its custom rendertarget, so it
        /// can capture the scene image in preparation for applying the bloom filter.
        /// </summary>
        public void BeginDraw(RenderTarget2D renderTarget)
        {
            if (Visible)
            {
                GraphicsDevice.SetRenderTarget(renderTarget);
            }
        }


        /// <summary>
        /// This is where it all happens. Grabs a scene that has already been rendered,
        /// and uses postprocess magic to add a glowing bloom effect over the top of it.
        /// </summary>

        public void Draw(GameTime gameTime, RenderTarget2D renderTarget)
        {
         

            // Pass 1: draw the scene into rendertarget 1, using a
            // shader that extracts only the brightest parts of the image.
            bloomExtractEffect.Parameters["BloomThreshold"].SetValue(
                Settings.BloomThreshold);

            DrawFullscreenQuad(renderTarget, renderTarget1,
                               bloomExtractEffect,
                               IntermediateBuffer.PreBloom);

            // Pass 2: draw from rendertarget 1 into rendertarget 2,
            // using a shader to apply a horizontal gaussian blur filter.
            SetBlurEffectParameters(1.0f / (float)renderTarget1.Width, 0);

            DrawFullscreenQuad(renderTarget1, renderTarget2,
                               gaussianBlurEffect,
                               IntermediateBuffer.BlurredHorizontally);

            // Pass 3: draw from rendertarget 2 back into rendertarget 1,
            // using a shader to apply a vertical gaussian blur filter.
            SetBlurEffectParameters(0, 1.0f / (float)renderTarget1.Height);

            DrawFullscreenQuad(renderTarget2, renderTarget1,
                               gaussianBlurEffect,
                               IntermediateBuffer.BlurredBothWays);

            // Pass 4: draw both rendertarget 1 and the original scene
            // image back into the main backbuffer, using a shader that
            // combines them to produce the final bloomed result.
            GraphicsDevice.SetRenderTarget(null);

            EffectParameterCollection parameters = bloomCombineEffect.Parameters;
            parameters["BaseTexture"].SetValue(renderTarget);
            parameters["BloomIntensity"].SetValue(Settings.BloomIntensity);
            parameters["BaseIntensity"].SetValue(Settings.BaseIntensity);
            parameters["BloomSaturation"].SetValue(Settings.BloomSaturation);
            parameters["BaseSaturation"].SetValue(Settings.BaseSaturation);

            GraphicsDevice.Textures[1] = renderTarget1;

            Viewport viewport = GraphicsDevice.Viewport;

            DrawFullscreenQuad(renderTarget,
                               viewport.Width, viewport.Height,
                               bloomCombineEffect,
                               IntermediateBuffer.FinalResult);

        }


        /// <summary>
        /// Helper for drawing a texture into a rendertarget, using
        /// a custom shader to apply postprocessing effects.
        /// </summary>
        void DrawFullscreenQuad(Texture2D texture, RenderTarget2D renderTarget,
                                Effect effect, IntermediateBuffer currentBuffer)
        {
            GraphicsDevice.SetRenderTarget(renderTarget);

            DrawFullscreenQuad(texture,
                               renderTarget.Width, renderTarget.Height,
                               effect, currentBuffer);
        }


        /// <summary>
        /// Helper for drawing a texture into the current rendertarget,
        /// using a custom shader to apply postprocessing effects.
        /// </summary>
        void DrawFullscreenQuad(Texture2D texture, int width, int height,
                                Effect effect, IntermediateBuffer currentBuffer)
        {
            // If the user has selected one of the show intermediate buffer options,
            // we still draw the quad to make sure the image will end up on the screen,
            // but might need to skip applying the custom pixel shader.
            if (showBuffer < currentBuffer)
            {
                effect = null;
            }

            spriteBatch.Begin(0, BlendState.Opaque, null, null, null, effect);
            spriteBatch.Draw(texture, new Rectangle(0, 0, width, height), Color.White);
            spriteBatch.End();
        }


        /// <summary>
        /// Computes sample weightings and texture coordinate offsets
        /// for one pass of a separable gaussian blur filter.
        /// </summary>
        void SetBlurEffectParameters(float dx, float dy)
        {
            // Look up the sample weight and offset effect parameters.
            EffectParameter weightsParameter, offsetsParameter;

            weightsParameter = gaussianBlurEffect.Parameters["SampleWeights"];
            offsetsParameter = gaussianBlurEffect.Parameters["SampleOffsets"];

            // Look up how many samples our gaussian blur effect supports.
            int sampleCount = weightsParameter.Elements.Count;

            // Create temporary arrays for computing our filter settings.
            float[] sampleWeights = new float[sampleCount];
            Vector2[] sampleOffsets = new Vector2[sampleCount];

            // The first sample always has a zero offset.
            sampleWeights[0] = ComputeGaussian(0);
            sampleOffsets[0] = new Vector2(0);

            // Maintain a sum of all the weighting values.
            float totalWeights = sampleWeights[0];

            // Add pairs of additional sample taps, positioned
            // along a line in both directions from the center.
            for (int i = 0; i < sampleCount / 2; i++)
            {
                // Store weights for the positive and negative taps.
                float weight = ComputeGaussian(i + 1);

                sampleWeights[i * 2 + 1] = weight;
                sampleWeights[i * 2 + 2] = weight;

                totalWeights += weight * 2;

                // To get the maximum amount of blurring from a limited number of
                // pixel shader samples, we take advantage of the bilinear filtering
                // hardware inside the texture fetch unit. If we position our texture
                // coordinates exactly halfway between two texels, the filtering unit
                // will average them for us, giving two samples for the price of one.
                // This allows us to step in units of two texels per sample, rather
                // than just one at a time. The 1.5 offset kicks things off by
                // positioning us nicely in between two texels.
                float sampleOffset = i * 2 + 1.5f;

                Vector2 delta = new Vector2(dx, dy) * sampleOffset;

                // Store texture coordinate offsets for the positive and negative taps.
                sampleOffsets[i * 2 + 1] = delta;
                sampleOffsets[i * 2 + 2] = -delta;
            }

            // Normalize the list of sample weightings, so they will always sum to one.
            for (int i = 0; i < sampleWeights.Length; i++)
            {
                sampleWeights[i] /= totalWeights;
            }

            // Tell the effect about our new filter settings.
            weightsParameter.SetValue(sampleWeights);
            offsetsParameter.SetValue(sampleOffsets);
        }


        /// <summary>
        /// Evaluates a single point on the gaussian falloff curve.
        /// Used for setting up the blur filter weightings.
        /// </summary>
        float ComputeGaussian(float n)
        {
            float theta = Settings.BlurAmount;

            return (float)((1.0 / Math.Sqrt(2 * Math.PI * theta)) *
                           Math.Exp(-(n * n) / (2 * theta * theta)));
        }


        #endregion
    }
}

Game class:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using BloomPostprocess;

namespace Morior
{
    /// <summary>
    /// This is the main type for your game.
    /// </summary>
    /// 
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Vector2 mPosition = new Vector2(250, 100);
        Laevus mLeavusSprite;
        DirtBlock b;
        Rectangle cursorSource;
        private Texture2D cursorTex;
        private Vector2 cursorPos;
        BloomComponent bloom;
        RenderTarget2D renderTarget;
        Rectangle rec;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            mLeavusSprite = new Laevus();
            b = new DirtBlock();
            renderTarget = new RenderTarget2D(
                          GraphicsDevice,
                          GraphicsDevice.PresentationParameters.BackBufferWidth,
                          GraphicsDevice.PresentationParameters.BackBufferHeight,
                          false,
                          GraphicsDevice.PresentationParameters.BackBufferFormat,
                          DepthFormat.Depth24);
            rec = new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
            bloom = new BloomComponent(this);
            Components.Add(bloom);
            bloom.Settings = new BloomSettings(null, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f);
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            // TODO: use this.Content to load your game content here
            mLeavusSprite.LoadContent(this.Content);
            mLeavusSprite.Position.Y = GraphicsDevice.Viewport.Height - mLeavusSprite.mSpriteTexture.Height - (mLeavusSprite.mSpriteTexture.Height / 6);
            mLeavusSprite.Position.X = GraphicsDevice.Viewport.Width / 2;
            b.LoadContent(this.Content);
            cursorTex = Content.Load<Texture2D>("sunset");
            cursorSource = new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
            bloom.LoadContent(GraphicsDevice, this.Content);
            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// game-specific content.
        /// </summary>
        protected override void UnloadContent()
        {
            
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            // TODO: Add your update logic here
            mLeavusSprite.Update(gameTime);
            var mouseState = Microsoft.Xna.Framework.Input.Mouse.GetState();

            cursorPos = new Vector2(mouseState.X, mouseState.Y);
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            bloom.ShowBuffer = BloomComponent.IntermediateBuffer.PreBloom;

            //bloom.BeginDraw(renderTarget);
            DrawSceneToTexture(renderTarget,gameTime);
            bloom.Draw(gameTime, renderTarget);
            //base.Draw(gameTime);
                
        }
        protected void DrawSceneToTexture(RenderTarget2D renderTarget, GameTime gametime)
        {

            GraphicsDevice.SetRenderTarget(renderTarget);

            GraphicsDevice.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true };

            // Draw the scene
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin(SpriteSortMode.Immediate,
     BlendState.AlphaBlend,
     SamplerState.PointClamp,
     null, null, null, null);



            mLeavusSprite.Draw(this.spriteBatch);
            b.Draw(this.spriteBatch);

            spriteBatch.Draw(cursorTex,  cursorSource,
                   Color.White);

            spriteBatch.End();
            // Drop the render target
            GraphicsDevice.SetRenderTarget(null);
        }
    }

}

I wish I could make my own shader, but as I said, I’m new to shaders, you really expect me to create whole new one when I cant even get premade one working? :frowning:

You are not setting texture right
this doesnt work in mono:

GraphicsDevice.Textures[1] = renderTarget1;

This will:

bloomCombineEffect.Parameters["BaseTexture"].SetParameter(renderTarget);

But you were setting wrong textures… why renderTarget
1 to sampler 1? It suppose to be base texture (so input RT in your case) and in Sampler 0 there should be renderTarget1 (RT that is blurred both ways) - so that spriteBatch draw should be drawing renderTarget1 and renderTarget (input RT) should be set as parameter.

Still, I dont think this will help you as your “blurred both way” in debug doesn´t look like blurred at all. But since we kinda broke part of game component I wouldn´t worry about that part at this point.

Btw: I suggest you to start all over.

1 Like

@Ravendarke I will start all over when ill finish with the last fixes you said, i did with the graphics.texture and setparamter doesnt exist, i used setvalue. And I didn’t understand where is sampler?

I think its correct

rendertarget is original
it takes renderatget and draws it to rendertarget1 for prebloom
then it takes rendertarget1 and draws it to rendertarget2 with horizontal blur,
then it takes 2 and draws it back to 1 with vertical blur, and at the end it draws rendertarget (the original) and the bloomcombieeffect that I think should be rendertarget1, no? or maybe it should draw rendertarget in bloomcombineeffect and in drawfullscreen rendertarget1? anyways I tried both and they give solid colors.

edit: this should be it, no?

        bloomCombineEffect.Parameters["BaseTexture"].SetValue(renderTarget);


        Viewport viewport = GraphicsDevice.Viewport;

        DrawFullscreenQuad(renderTarget1,
                           viewport.Width, viewport.Height,
                           bloomCombineEffect,
                           IntermediateBuffer.FinalResult);

This should be it, dunno if you have changed something else tho, but this part should be alright.

@Ravendarke Okay, so just to make sure, here is all the code, ill rewrite it tommorow to see if ill be able to find mistakes:

#region File Description
//-----------------------------------------------------------------------------
// BloomComponent.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
#endregion

namespace BloomPostprocess
{
    public class BloomComponent : DrawableGameComponent
    {
        #region Fields

        SpriteBatch spriteBatch;

        Effect bloomExtractEffect;
        Effect bloomCombineEffect;
        Effect gaussianBlurEffect;

        RenderTarget2D renderTarget1;
        RenderTarget2D renderTarget2;


        // Choose what display settings the bloom should use.
        public BloomSettings Settings
        {
            get { return settings; }
            set { settings = value; }
        }

        BloomSettings settings = BloomSettings.PresetSettings[0];


        // Optionally displays one of the intermediate buffers used
        // by the bloom postprocess, so you can see exactly what is
        // being drawn into each rendertarget.
        public enum IntermediateBuffer
        {
            PreBloom,
            BlurredHorizontally,
            BlurredBothWays,
            FinalResult,
        }

        public IntermediateBuffer ShowBuffer
        {
            get { return showBuffer; }
            set { showBuffer = value; }
        }

        IntermediateBuffer showBuffer = IntermediateBuffer.FinalResult;


        #endregion

        #region Initialization


        public BloomComponent(Game game)
            : base(game)
        {
            if (game == null)
                throw new ArgumentNullException("game");
        }


        /// <summary>
        /// Load your graphics content.
        /// </summary>
        public void LoadContent(GraphicsDevice g, ContentManager theContentManager)
        {
            spriteBatch = new SpriteBatch(g);
            bloomExtractEffect = theContentManager.Load<Effect>("BloomExtract");
            bloomCombineEffect = theContentManager.Load<Effect>("BloomCombine");
            gaussianBlurEffect = theContentManager.Load<Effect>("GaussianBlur");

            // Look up the resolution and format of our main backbuffer.
            PresentationParameters pp = g.PresentationParameters;

            int width = pp.BackBufferWidth;
            int height = pp.BackBufferHeight;

            SurfaceFormat format = pp.BackBufferFormat;

            // Create a texture for rendering the main scene, prior to applying bloom.


            // Create two rendertargets for the bloom processing. These are half the
            // size of the backbuffer, in order to minimize fillrate costs. Reducing
            // the resolution in this way doesn't hurt quality, because we are going
            // to be blurring the bloom images in any case.
            width /= 2;
            height /= 2;

            renderTarget1 = new RenderTarget2D(g, width, height, false, format, DepthFormat.Depth24);
            renderTarget2 = new RenderTarget2D(g, width, height, false, format, DepthFormat.Depth24);
        }


        /// <summary>
        /// Unload your graphics content.
        /// </summary>
        public void UnloadContent(ContentManager theContentManager)
        {
            renderTarget1.Dispose();
            renderTarget2.Dispose();
        }


        #endregion

        #region Draw


        /// <summary>
        /// This should be called at the very start of the scene rendering. The bloom
        /// component uses it to redirect drawing into its custom rendertarget, so it
        /// can capture the scene image in preparation for applying the bloom filter.
        /// </summary>
        public void BeginDraw(RenderTarget2D renderTarget)
        {
            if (Visible)
            {
                GraphicsDevice.SetRenderTarget(renderTarget);
            }
        }


        /// <summary>
        /// This is where it all happens. Grabs a scene that has already been rendered,
        /// and uses postprocess magic to add a glowing bloom effect over the top of it.
        /// </summary>

        public void Draw(GameTime gameTime, RenderTarget2D renderTarget)
        {
         

            // Pass 1: draw the scene into rendertarget 1, using a
            // shader that extracts only the brightest parts of the image.
            bloomExtractEffect.Parameters["BloomThreshold"].SetValue(
                Settings.BloomThreshold);

            DrawFullscreenQuad(renderTarget, renderTarget1,
                               bloomExtractEffect,
                               IntermediateBuffer.PreBloom);

            // Pass 2: draw from rendertarget 1 into rendertarget 2,
            // using a shader to apply a horizontal gaussian blur filter.
            SetBlurEffectParameters(1.0f / (float)renderTarget1.Width, 0);

            DrawFullscreenQuad(renderTarget1, renderTarget2,
                               gaussianBlurEffect,
                               IntermediateBuffer.BlurredHorizontally);

            // Pass 3: draw from rendertarget 2 back into rendertarget 1,
            // using a shader to apply a vertical gaussian blur filter.
            SetBlurEffectParameters(0, 1.0f / (float)renderTarget1.Height);

            DrawFullscreenQuad(renderTarget2, renderTarget1,
                               gaussianBlurEffect,
                               IntermediateBuffer.BlurredBothWays);

            // Pass 4: draw both rendertarget 1 and the original scene
            // image back into the main backbuffer, using a shader that
            // combines them to produce the final bloomed result.
            GraphicsDevice.SetRenderTarget(null);

            EffectParameterCollection parameters = bloomCombineEffect.Parameters;
           
            parameters["BloomIntensity"].SetValue(Settings.BloomIntensity);
            parameters["BaseIntensity"].SetValue(Settings.BaseIntensity);
            parameters["BloomSaturation"].SetValue(Settings.BloomSaturation);
            parameters["BaseSaturation"].SetValue(Settings.BaseSaturation);

            bloomCombineEffect.Parameters["BaseTexture"].SetValue(renderTarget);


            Viewport viewport = GraphicsDevice.Viewport;

            DrawFullscreenQuad(renderTarget1,
                               viewport.Width, viewport.Height,
                               bloomCombineEffect,
                               IntermediateBuffer.FinalResult);

        }


        /// <summary>
        /// Helper for drawing a texture into a rendertarget, using
        /// a custom shader to apply postprocessing effects.
        /// </summary>
        void DrawFullscreenQuad(Texture2D texture, RenderTarget2D renderTarget,
                                Effect effect, IntermediateBuffer currentBuffer)
        {
            GraphicsDevice.SetRenderTarget(renderTarget);

            DrawFullscreenQuad(texture,
                               renderTarget.Width, renderTarget.Height,
                               effect, currentBuffer);
        }


        /// <summary>
        /// Helper for drawing a texture into the current rendertarget,
        /// using a custom shader to apply postprocessing effects.
        /// </summary>
        void DrawFullscreenQuad(Texture2D texture, int width, int height,
                                Effect effect, IntermediateBuffer currentBuffer)
        {
            // If the user has selected one of the show intermediate buffer options,
            // we still draw the quad to make sure the image will end up on the screen,
            // but might need to skip applying the custom pixel shader.
            if (showBuffer < currentBuffer)
            {
                effect = null;
            }

            spriteBatch.Begin(0, BlendState.Opaque, null, null, null, effect);
            spriteBatch.Draw(texture, new Rectangle(0, 0, width, height), Color.White);
            spriteBatch.End();
        }


        /// <summary>
        /// Computes sample weightings and texture coordinate offsets
        /// for one pass of a separable gaussian blur filter.
        /// </summary>
        void SetBlurEffectParameters(float dx, float dy)
        {
            // Look up the sample weight and offset effect parameters.
            EffectParameter weightsParameter, offsetsParameter;

            weightsParameter = gaussianBlurEffect.Parameters["SampleWeights"];
            offsetsParameter = gaussianBlurEffect.Parameters["SampleOffsets"];

            // Look up how many samples our gaussian blur effect supports.
            int sampleCount = weightsParameter.Elements.Count;

            // Create temporary arrays for computing our filter settings.
            float[] sampleWeights = new float[sampleCount];
            Vector2[] sampleOffsets = new Vector2[sampleCount];

            // The first sample always has a zero offset.
            sampleWeights[0] = ComputeGaussian(0);
            sampleOffsets[0] = new Vector2(0);

            // Maintain a sum of all the weighting values.
            float totalWeights = sampleWeights[0];

            // Add pairs of additional sample taps, positioned
            // along a line in both directions from the center.
            for (int i = 0; i < sampleCount / 2; i++)
            {
                // Store weights for the positive and negative taps.
                float weight = ComputeGaussian(i + 1);

                sampleWeights[i * 2 + 1] = weight;
                sampleWeights[i * 2 + 2] = weight;

                totalWeights += weight * 2;

                // To get the maximum amount of blurring from a limited number of
                // pixel shader samples, we take advantage of the bilinear filtering
                // hardware inside the texture fetch unit. If we position our texture
                // coordinates exactly halfway between two texels, the filtering unit
                // will average them for us, giving two samples for the price of one.
                // This allows us to step in units of two texels per sample, rather
                // than just one at a time. The 1.5 offset kicks things off by
                // positioning us nicely in between two texels.
                float sampleOffset = i * 2 + 1.5f;

                Vector2 delta = new Vector2(dx, dy) * sampleOffset;

                // Store texture coordinate offsets for the positive and negative taps.
                sampleOffsets[i * 2 + 1] = delta;
                sampleOffsets[i * 2 + 2] = -delta;
            }

            // Normalize the list of sample weightings, so they will always sum to one.
            for (int i = 0; i < sampleWeights.Length; i++)
            {
                sampleWeights[i] /= totalWeights;
            }

            // Tell the effect about our new filter settings.
            weightsParameter.SetValue(sampleWeights);
            offsetsParameter.SetValue(sampleOffsets);
        }


        /// <summary>
        /// Evaluates a single point on the gaussian falloff curve.
        /// Used for setting up the blur filter weightings.
        /// </summary>
        float ComputeGaussian(float n)
        {
            float theta = Settings.BlurAmount;

            return (float)((1.0 / Math.Sqrt(2 * Math.PI * theta)) *
                           Math.Exp(-(n * n) / (2 * theta * theta)));
        }


        #endregion
    }
}

I’m totally new here, but I could offer a few ideas. If I understand correctly, you’re running the monogame pipeline to build an fx originally made for xna. Assuming you double clicked mgcb and went edit - add existing item - and used copy (if not already in there), then made sure settings say: Processor: Effect - MonoGame. Then it should try to build it when you click build, however the fx probably need some changes. For each effect I would add this to the top: (# in front of defines):
define TECHNIQUE(name, vsname, psname) technique name { pass { VertexShader = compile vs_5_0 vsname(); PixelShader = compile ps_5_0 psname(); }}
define BEGIN_CONSTANTS cbuffer Parameters : register(b0) {
define END_CONSTANTS };
define DECLARE_TEXTURE(Name, index) Texture2D Name : register(t##index); sampler Name##Sampler : register(s##index)
define SAMPLE_TEXTURE(Name, texCoord) Name.Sample(Name##Sampler, texCoord)

Then any textures would be like this:

DECLARE_TEXTURE(Texture, 0);
DECLARE_TEXTURE(Flare, 1);

and you would pass as a parameter (after loading - not in loop).
And all your passed variables in a cbuffer like this:

BEGIN_CONSTANTS
float4x4 MatrixTransform;
float2 lightPosition; // just examples
float density; // just examples
END_CONSTANTS

Any other vars should not be out here. I would make them local as I don’t think they work otherwise.

Then a struct which must match vertex declaration. ie:
(Shaders need VS and PS)

struct VSOutput
{
float4 position : SV_Position; // <—this must be SV_Position - not POSITION0 or other
float4 color : COLOR0;
float2 texCoord : TEXCOORD0;
}

VSOutput yourVertShader(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0)
{
VSOutput output;
output.position = mul(position, MatrixTransform); // <— must not forget to set this param or nothing shows
output.color = color;
output.texCoord = texCoord;
return output;
}

float4 yourPixShader(VSOutput input) : SV_Target0 // <-- not sure if this must be SV_Target0 ?
{
float2 TexCoord = input.texCoord;
float4 col = SAMPLE_TEXTURE(Texture, TexCoord);
float3 other_col = SAMPLE_TEXTURE(Flare, TexCoord);
return col + float4(other_col,1); // just a random weird example
}

TECHNIQUE(SpriteBatch, SpriteVertexShader, SpritePixelShader);

If using spritebatch, I would pass the effect in the Begin statement. Otherwise I would apply before rendering to target. Make sure to pass textures as params though and maybe try commenting out setting clamp (just to see since that caused a prob for me once). Spritebatch should set linear clamping as default.

I’m no expert - but that’s what I did to make things work. Maybe this helps?

He is rendering full screen quad postprocessing, there is no reason why to drag 4x4 transformation matrix into this. Default vertex shader will do just fine. I suppose he changed POSITION0 otherwise it would crash right away with appropriate error.

His issues lies inside messed up rendering pipeline. Changes for shaders I´ve mentioned here and in linked thread are sufficient.

Btw, if it wont work, send it to me, I will take a look if I will have time.

The variables need to be in cbuffers. I tried outside cbuffer and couldn’t get them to work. Also without using that DECLARE_TEXTURE macro and regular param passing, I couldn’t get the 2nd texture. Also like I said, it seems like the compiler was ignoring globals.
Oh, now I remember why I needed the VS. I wanted to use ps_5_0 and needed the corresponding shader level for the VS. I found out that for some reason even though I was using shader 4_… it was saying I had too many operations for ps_2_0 even though I was specifying 4+ … so I assumed a glitch in the compiler which was still checking for operations not exceeding level 2 even when using 4, tried 5 - and voila - it worked. :slight_smile:

E D I T:
It seems in MonoGame you do not need to bypass the vs in spritebatch as in xna(altho it doesn’t hurt cuz you can add some vertex animation). Also I was wrong about cbuffers. It only seems to be a problem if you specify both cbuffers and don’t use at the same time. Also I discovered ps_4_0_level_9_x shaders are dx9 compatible with instruction limit for ps_2 – so in that case it’s not a glitch - just use 4_0 or 5_0 for example.

@Ravendarke OH MY GOD! IT WORKED!!. I re-wrote the whole thing, and it worked, I can’t believe it! Thank you so much!

Only last question is left, how do I choose what to bloom and what not? if I want only specific texture to be bloomed, do I create a whole new render target for it?

@AlienScribble Thank you for attempting to help, I was about to try what you wrote but it ended up working surprisingly. :slight_smile:

@Ravendarke by trying to bloom one image that is on top and placing a background image the result is the bloomed image with black background, I don’t understand why… or at least I don’t know how to fix it, what porbably is happening is that it draws only the cursor’s render target… same question applies to how to draw two bloomed rendertargets, it only draws the last one.

  protected override void Draw(GameTime gameTime)
        {

            DrawSceneToTexture(renderTarget, gameTime);
            DrawCursor(cursor, gameTime);
            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend,
SamplerState.LinearClamp, DepthStencilState.Default,
RasterizerState.CullNone);
            spriteBatch.Draw(renderTarget, rec, Color.White);
            spriteBatch.End();
           
           bloom.Draw(gameTime, cursor);
           
            base.Draw(gameTime);
        }
        protected void DrawCursor(RenderTarget2D renderTarget, GameTime gametime)
        {

            GraphicsDevice.SetRenderTarget(renderTarget);

            GraphicsDevice.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true };
            GraphicsDevice.Clear(Color.Transparent);
            // Draw the scene
           
            spriteBatch.Begin(SpriteSortMode.Immediate,
     BlendState.AlphaBlend,
     SamplerState.PointClamp,
     null, null, null, null);

            spriteBatch.Draw(cursorTex, cursorPos, cursorSource,
                   Color.White, 0.0f, Vector2.Zero, 3f, SpriteEffects.None, 0);

            spriteBatch.End();
            // Drop the render target
            GraphicsDevice.SetRenderTarget(null);
        }
        protected void DrawSceneToTexture(RenderTarget2D renderTarget, GameTime gametime)
        {

            GraphicsDevice.SetRenderTarget(renderTarget);

            GraphicsDevice.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true };

            // Draw the scene
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin(SpriteSortMode.Immediate,
     BlendState.AlphaBlend,
     SamplerState.PointClamp,
     null, null, null, null);



            mLeavusSprite.Draw(this.spriteBatch);
            b.Draw(this.spriteBatch);

            spriteBatch.End();
            // Drop the render target
            GraphicsDevice.SetRenderTarget(null);
        }

Cool, getting there! I noticed before the bloom draws the full screen quad with BlendState.Opaque so maybe that would result in losing transparency of the bloomed layer?

@AlienScribble Yes! and I tried changing it to “AlphaBlend” and “Addive”, it doesn’t do anything ;c, I also tried changing the color to Transparent but it wont do anything.

Hmm. Odd. The first couple things that come to mind is it looks like the global renderTarget var and local renderTarget have the same name, but I doubt it would mix them up since I think it favors the local when resolving. Otherwise I might also not set the rendertarget to null after each spritebatch end as that sets backbuffer to target (not as efficient - even though technically that shouldn’t be the problem). I’ve had quirky behavior from render target switching with multiple textures before, so maybe under the hood something is being reset causing you to loose the texture from the first rendertarget? I would try that anyway but it probably isn’t the problem. If you comment out bloom.Draw the background shows but while on it disappears and only the cursor - is that right?
Perhaps too it is something in the shader with how it treats the transparent pixels in the bloom formula? I’ll take a look at it.

@AlienScribble I shouldve posted here the new code, because i made it easier to read and changed a bit, anyways here it is :

BloomCompontent:

#region File Description
//-----------------------------------------------------------------------------
// BloomComponent.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
#endregion

namespace BloomPostprocess
{
    public class BloomComponent : DrawableGameComponent
    {
        #region Fields

        SpriteBatch spriteBatch;

        Effect bloomExtractEffect;
        Effect bloomCombineEffect;
        Effect gaussianBlurEffect;

        RenderTarget2D renderTarget1;
        RenderTarget2D renderTarget2;


        // Choose what display settings the bloom should use.
        public BloomSettings Settings
        {
            get { return settings; }
            set { settings = value; }
        }

        BloomSettings settings = BloomSettings.PresetSettings[0];


        // Optionally displays one of the intermediate buffers used
        // by the bloom postprocess, so you can see exactly what is
        // being drawn into each rendertarget.
        public enum IntermediateBuffer
        {
            PreBloom,
            BlurredHorizontally,
            BlurredBothWays,
            FinalResult,
        }

        public IntermediateBuffer ShowBuffer
        {
            get { return showBuffer; }
            set { showBuffer = value; }
        }

        IntermediateBuffer showBuffer = IntermediateBuffer.FinalResult;


        #endregion

        #region Initialization


        public BloomComponent(Game game)
            : base(game)
        {
            if (game == null)
                throw new ArgumentNullException("game");
        }


        /// <summary>
        /// Load your graphics content.
        /// </summary>
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            bloomExtractEffect = Game.Content.Load<Effect>("BloomExtract.mgfx");
            bloomCombineEffect = Game.Content.Load<Effect>("BloomCombine.mgfx");
            gaussianBlurEffect = Game.Content.Load<Effect>("GaussianBlur.mgfx");

            // Look up the resolution and format of our main backbuffer.
            PresentationParameters pp = GraphicsDevice.PresentationParameters;

            int width = pp.BackBufferWidth;
            int height = pp.BackBufferHeight;

            SurfaceFormat format = pp.BackBufferFormat;

            // Create a texture for rendering the main scene, prior to applying bloom.


            // Create two rendertargets for the bloom processing. These are half the
            // size of the backbuffer, in order to minimize fillrate costs. Reducing
            // the resolution in this way doesn't hurt quality, because we are going
            // to be blurring the bloom images in any case.
            width /= 2;
            height /= 2;

            renderTarget1 = new RenderTarget2D(GraphicsDevice, width, height, false, format, DepthFormat.None);
            renderTarget2 = new RenderTarget2D(GraphicsDevice, width, height, false, format, DepthFormat.None);
        }


        /// <summary>
        /// Unload your graphics content.
        /// </summary>
        protected override void UnloadContent()
        {
            renderTarget1.Dispose();
            renderTarget2.Dispose();
        }


        #endregion

        #region Draw


        /// <summary>
        /// This should be called at the very start of the scene rendering. The bloom
        /// component uses it to redirect drawing into its custom rendertarget, so it
        /// can capture the scene image in preparation for applying the bloom filter.
        /// </summary>
        public void BeginDraw(RenderTarget2D renderTarget)
        {
            if (Visible)
            {
                GraphicsDevice.SetRenderTarget(renderTarget);
            }
        }


        /// <summary>
        /// This is where it all happens. Grabs a scene that has already been rendered,
        /// and uses postprocess magic to add a glowing bloom effect over the top of it.
        /// </summary>
        public void Draw(GameTime gameTime, RenderTarget2D sceneRenderTarget)
        {
            GraphicsDevice.SamplerStates[1] = SamplerState.LinearClamp;

            // Pass 1: draw the scene into rendertarget 1, using a
            // shader that extracts only the brightest parts of the image.
            bloomExtractEffect.Parameters["BloomThreshold"].SetValue(
                Settings.BloomThreshold);

            DrawFullscreenQuad(sceneRenderTarget, renderTarget1,
                               bloomExtractEffect,
                               IntermediateBuffer.PreBloom);

            // Pass 2: draw from rendertarget 1 into rendertarget 2,
            // using a shader to apply a horizontal gaussian blur filter.
            SetBlurEffectParameters(1.0f / (float)renderTarget1.Width, 0);

            DrawFullscreenQuad(renderTarget1, renderTarget2,
                               gaussianBlurEffect,
                               IntermediateBuffer.BlurredHorizontally);

            // Pass 3: draw from rendertarget 2 back into rendertarget 1,
            // using a shader to apply a vertical gaussian blur filter.
            SetBlurEffectParameters(0, 1.0f / (float)renderTarget1.Height);

            DrawFullscreenQuad(renderTarget2, renderTarget1,
                               gaussianBlurEffect,
                               IntermediateBuffer.BlurredBothWays);

            // Pass 4: draw both rendertarget 1 and the original scene
            // image back into the main backbuffer, using a shader that
            // combines them to produce the final bloomed result.
            GraphicsDevice.SetRenderTarget(null);

            EffectParameterCollection parameters = bloomCombineEffect.Parameters;

            parameters["BloomIntensity"].SetValue(Settings.BloomIntensity);
            parameters["BaseIntensity"].SetValue(Settings.BaseIntensity);
            parameters["BloomSaturation"].SetValue(Settings.BloomSaturation);
            parameters["BaseSaturation"].SetValue(Settings.BaseSaturation);

            bloomCombineEffect.Parameters["BaseTexture"].SetValue(sceneRenderTarget);

            Viewport viewport = GraphicsDevice.Viewport;

            DrawFullscreenQuad(renderTarget1,
                               viewport.Width, viewport.Height,
                               bloomCombineEffect,
                               IntermediateBuffer.FinalResult);
        }


        /// <summary>
        /// Helper for drawing a texture into a rendertarget, using
        /// a custom shader to apply postprocessing effects.
        /// </summary>
        void DrawFullscreenQuad(Texture2D texture, RenderTarget2D renderTarget,
                                Effect effect, IntermediateBuffer currentBuffer)
        {
            GraphicsDevice.SetRenderTarget(renderTarget);

            DrawFullscreenQuad(texture,
                               renderTarget.Width, renderTarget.Height,
                               effect, currentBuffer);
        }


        /// <summary>
        /// Helper for drawing a texture into the current rendertarget,
        /// using a custom shader to apply postprocessing effects.
        /// </summary>
        void DrawFullscreenQuad(Texture2D texture, int width, int height,
                                Effect effect, IntermediateBuffer currentBuffer)
        {
            // If the user has selected one of the show intermediate buffer options,
            // we still draw the quad to make sure the image will end up on the screen,
            // but might need to skip applying the custom pixel shader.
            if (showBuffer < currentBuffer)
            {
                effect = null;
            }

            spriteBatch.Begin(0, BlendState.AlphaBlend, null, null, null, effect);
            spriteBatch.Draw(texture, new Rectangle(0, 0, width, height), Color.White);
            spriteBatch.End();
        }


        /// <summary>
        /// Computes sample weightings and texture coordinate offsets
        /// for one pass of a separable gaussian blur filter.
        /// </summary>
        void SetBlurEffectParameters(float dx, float dy)
        {
            // Look up the sample weight and offset effect parameters.
            EffectParameter weightsParameter, offsetsParameter;

            weightsParameter = gaussianBlurEffect.Parameters["SampleWeights"];
            offsetsParameter = gaussianBlurEffect.Parameters["SampleOffsets"];

            // Look up how many samples our gaussian blur effect supports.
            int sampleCount = weightsParameter.Elements.Count;

            // Create temporary arrays for computing our filter settings.
            float[] sampleWeights = new float[sampleCount];
            Vector2[] sampleOffsets = new Vector2[sampleCount];

            // The first sample always has a zero offset.
            sampleWeights[0] = ComputeGaussian(0);
            sampleOffsets[0] = new Vector2(0);

            // Maintain a sum of all the weighting values.
            float totalWeights = sampleWeights[0];

            // Add pairs of additional sample taps, positioned
            // along a line in both directions from the center.
            for (int i = 0; i < sampleCount / 2; i++)
            {
                // Store weights for the positive and negative taps.
                float weight = ComputeGaussian(i + 1);

                sampleWeights[i * 2 + 1] = weight;
                sampleWeights[i * 2 + 2] = weight;

                totalWeights += weight * 2;

                // To get the maximum amount of blurring from a limited number of
                // pixel shader samples, we take advantage of the bilinear filtering
                // hardware inside the texture fetch unit. If we position our texture
                // coordinates exactly halfway between two texels, the filtering unit
                // will average them for us, giving two samples for the price of one.
                // This allows us to step in units of two texels per sample, rather
                // than just one at a time. The 1.5 offset kicks things off by
                // positioning us nicely in between two texels.
                float sampleOffset = i * 2 + 1.5f;

                Vector2 delta = new Vector2(dx, dy) * sampleOffset;

                // Store texture coordinate offsets for the positive and negative taps.
                sampleOffsets[i * 2 + 1] = delta;
                sampleOffsets[i * 2 + 2] = -delta;
            }

            // Normalize the list of sample weightings, so they will always sum to one.
            for (int i = 0; i < sampleWeights.Length; i++)
            {
                sampleWeights[i] /= totalWeights;
            }

            // Tell the effect about our new filter settings.
            weightsParameter.SetValue(sampleWeights);
            offsetsParameter.SetValue(sampleOffsets);
        }


        /// <summary>
        /// Evaluates a single point on the gaussian falloff curve.
        /// Used for setting up the blur filter weightings.
        /// </summary>
        float ComputeGaussian(float n)
        {
            float theta = Settings.BlurAmount;

            return (float)((1.0 / Math.Sqrt(2 * Math.PI * theta)) *
                           Math.Exp(-(n * n) / (2 * theta * theta)));
        }


        #endregion
    }
}

And when I take away the bloom, only black background is drown, I think its because I don’t draw the cursor, when I also draw the cursor like that:

      spriteBatch.Draw(cursor, rec, Color.White);

it shows both cursor and background as expected if I add bloom, cursor gets black background. When I take away

 GraphicsDevice.SetRenderTarget(null);

at cursors draw function when bloom is off it removes the black background and doesnt draw the cursor, but when i remove it with bloom its where stuff get weird, the cursor is not drawn, but the background is drawn with bloom…

FIGURED IT OUT.

Okay. So a friend of my explained to me something I thought I understood, and very fast I figured out an solution. GraphicsDevice.SetRenderTarget(null); is setting graphicsdevice to the backbuffer, this acts like a rendertarget, that draws stuff on the screen, meaning that if I set it to null and draw to it, it will show on the screen, unless I called it again and drew again, which would reset it and remove what I drew before and draw the new thing. This was the reason it would show only the cursor, I would ask it to remove everything it drew before, and draw the cursor, if I wanted it to draw what I drew before, I had to draw everything I want including the cursor after the null setting.

How did I solve it?
by simply editing the graphicsdevice.setrendertarget(null); to a new rendertarget, I made the draw function return a new render target and drew everything on it, and later on in my game draw I drew the drawtarget with the background and other textures I wanted, it’s that simple.

 public RenderTarget2D Draw(GameTime gameTime, RenderTarget2D sceneRenderTarget)
        {
            GraphicsDevice.SamplerStates[1] = SamplerState.LinearClamp;

            // Pass 1: draw the scene into rendertarget 1, using a
            // shader that extracts only the brightest parts of the image.
            bloomExtractEffect.Parameters["BloomThreshold"].SetValue(
                Settings.BloomThreshold);

            DrawFullscreenQuad(sceneRenderTarget, renderTarget1,
                               bloomExtractEffect,
                               IntermediateBuffer.PreBloom);

            // Pass 2: draw from rendertarget 1 into rendertarget 2,
            // using a shader to apply a horizontal gaussian blur filter.
            SetBlurEffectParameters(1.0f / (float)renderTarget1.Width, 0);

            DrawFullscreenQuad(renderTarget1, renderTarget2,
                               gaussianBlurEffect,
                               IntermediateBuffer.BlurredHorizontally);

            // Pass 3: draw from rendertarget 2 back into rendertarget 1,
            // using a shader to apply a vertical gaussian blur filter.
            SetBlurEffectParameters(0, 1.0f / (float)renderTarget1.Height);

            DrawFullscreenQuad(renderTarget2, renderTarget1,
                               gaussianBlurEffect,
                               IntermediateBuffer.BlurredBothWays);

            // Pass 4: draw both rendertarget 1 and the original scene
            // image back into the main backbuffer, using a shader that
            // combines them to produce the final bloomed result.
            GraphicsDevice.SetRenderTarget(renderTarget3);

            EffectParameterCollection parameters = bloomCombineEffect.Parameters;

            parameters["BloomIntensity"].SetValue(Settings.BloomIntensity);
            parameters["BaseIntensity"].SetValue(Settings.BaseIntensity);
            parameters["BloomSaturation"].SetValue(Settings.BloomSaturation);
            parameters["BaseSaturation"].SetValue(Settings.BaseSaturation);

            bloomCombineEffect.Parameters["BaseTexture"].SetValue(sceneRenderTarget);

            Viewport viewport = GraphicsDevice.Viewport;

            DrawFullscreenQuad(renderTarget1,
                               viewport.Width, viewport.Height,
                               bloomCombineEffect,
                               IntermediateBuffer.FinalResult);
            return renderTarget3;
        }
1 Like

That’s awesome! I decided I liked the idea of a bloom of this type and ended up doing the same as you. I got stuck with black backgrounds too until I added this line in the DrawFullscreenQuad just before begin:
device.Clear(Color.TransparentBlack);
Whoops. :wink:
Before that I only had it at the beginning of the draw forgetting that all the render targets need to be cleared as transparent. Technically one could “bloom” stuff in 2d withs something like photoshop, but parametric blooming gives nice potential for animating the effect (like pulsation or something). One could also probably remove the GraphicsDevice.SamplerStates[1] = SamplerState.LinearClamp; line since I think we’re already doing it in the shader now.
Hey much thanks to you and Ravendarke for this. Maybe later I could put up a tutorial on me site for this.

1 Like

@AlienScribble Sounds awesome , and I agree, please link me to the blog post if you will make one!