Alpha blending RenderTarget2D

Hello!

I have problems alpha blending multiple RenderTarget2Ds. The following is the minimal reproductible example:

`protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.TransparentBlack);
    
    // FIRST CIRCLE
    var renderTarget = CreateRenderTarget();
    GraphicsDevice.SetRenderTarget(renderTarget);
    GraphicsDevice.Clear(Color.TransparentBlack);
    
    _spriteBatch.Begin(blendState: BlendState.AlphaBlend);
    _spriteBatch.Draw(_whiteCircleTexture, new Vector2(0,0), Color.White * 0.5f);
    _spriteBatch.End();

    GraphicsDevice.SetRenderTarget(null);

    _spriteBatch.Begin();
    _spriteBatch.Draw(renderTarget, new Vector2(0, 0), Color.White * 0.5f);
    _spriteBatch.End();

    renderTarget.Dispose();

    // SECOND CIRCLE
    var renderTarget2 = CreateRenderTarget();
    GraphicsDevice.SetRenderTarget(renderTarget2);
    GraphicsDevice.Clear(Color.TransparentBlack);
    
    _spriteBatch.Begin(blendState: BlendState.AlphaBlend);
    _spriteBatch.Draw(_whiteCircleTexture, new Vector2(0, 0), Color.White * 0.5f);
    _spriteBatch.End();

    GraphicsDevice.SetRenderTarget(null);

    _spriteBatch.Begin();
    _spriteBatch.Draw(renderTarget2, new Vector2(400, 0), Color.White * 0.5f);
    _spriteBatch.End();

    renderTarget2.Dispose();

    base.Draw(gameTime);
}

private RenderTarget2D CreateRenderTarget()
{
    var pp = GraphicsDevice.PresentationParameters;
    return new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, pp.BackBufferFormat, DepthFormat.Depth24Stencil8, 0, RenderTargetUsage.PreserveContents);
} `

What I want to achieve is to create RenderTarget2D, draw a semitransparent white circle, blend this RenderTarget2D to the screen and repeat this with another (slightly shifted) circle. The result should be something like this:

But no matter what I do, always only the second circle is visible. Could you please help me with this?

I think you might need to use BlendState.NonPremultiplied instead of BlendState.AlphaBlend. You also aren’t using any blend state in your second begin call, so I think it will just go to the default of AlphaBlend? I can’t remember what it is… but maybe.

Anyway, give that a try.

Thank you Trinith, but I think I have actually tried different possible BlendState combinations and nothing worked.

BlendState.AlphaBlend in all 4 _spriteBatch.Begin calls doesn’t change anything, BlendState.NonPremultiplied gives only black screen.

I really don’t know.

Hmm ok, was worth a shot. Whenever I’m having troubles, that’s almost always the culprit. I have to run out but I’ll try to remember to check this out. You’ve posted some code so it should be pretty easy to play around with. Nothing else obvious jumps out at me.

When you switch to a render target, and then switch back to the backbuffer, the backbuffer will loose it’s content. You have to render to both render targets first, and then draw them to the backbuffer in one go.

you can draw them in a chain under the default settings.

        public float motiony = 0;
        protected override void Draw(GameTime gameTime)
        {
            var elapsed = gameTime.ElapsedGameTime.TotalSeconds.ToFloat();
            motiony += elapsed;
            if (motiony > 1.0f)
                motiony = 0f;

            GraphicsDevice.Clear(Color.CornflowerBlue); // Clear backbuffer.


            GraphicsDevice.SetRenderTarget(rTargetA); // Set the drawing target to be a off screen rendering buffer.

            spriteBatch.Begin();
            spriteBatch.Draw(dotTexture, new Rectangle(0, (int)(motiony * 100), 100, 100), Color.Yellow * .5f); 
            spriteBatch.End();

            GraphicsDevice.SetRenderTarget(rTargetB); // Set the drawing target to be a  different off screen rendering buffer.

            spriteBatch.Begin();
            spriteBatch.Draw((Texture2D)rTargetA, new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height), Color.White);
            spriteBatch.End();

            spriteBatch.Begin();
            spriteBatch.Draw(dotTexture, new Rectangle(60, (int)(motiony * 100), 100, 100), Color.Red * .5f); 
            spriteBatch.End();
          
            GraphicsDevice.SetRenderTarget(null); // Set the drawing target to be the back buffer.

            spriteBatch.Begin();
            spriteBatch.Draw((Texture2D)rTargetB, new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height), Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }

Though i dunno how to auto clear the render targets to a clear color
I guess you could overwrite the whole thing with a draw seems like there should be a way to do it with clear.

Yes, that’s it, you guys are right. The key is to call GraphicsDevice.SetRenderTarget(null); only once. This is working:

` protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.TransparentBlack);

    // FIRST CIRCLE
    var renderTarget = CreateRenderTarget();
    GraphicsDevice.SetRenderTarget(renderTarget);
    GraphicsDevice.Clear(Color.TransparentBlack);
    
    _spriteBatch.Begin(blendState: BlendState.AlphaBlend);
    _spriteBatch.Draw(_whiteCircleTexture, new Vector2(0,0), Color.White * 0.5f);
    _spriteBatch.End();

    // SECOND CIRCLE
    var renderTarget2 = CreateRenderTarget();
    GraphicsDevice.SetRenderTarget(renderTarget2);
    GraphicsDevice.Clear(Color.TransparentBlack);
    
    _spriteBatch.Begin(blendState: BlendState.AlphaBlend);
    _spriteBatch.Draw(_whiteCircleTexture, new Vector2(400, 0), Color.White * 0.5f);
    _spriteBatch.End();

    GraphicsDevice.SetRenderTarget(null);

    _spriteBatch.Begin(blendState: BlendState.AlphaBlend);
    _spriteBatch.Draw(renderTarget, new Vector2(0, 0), Color.White * 0.5f);
    _spriteBatch.Draw(renderTarget2, new Vector2(0, 0), Color.White * 0.5f);
    _spriteBatch.End();

    renderTarget.Dispose();
    renderTarget2.Dispose();

    base.Draw(gameTime);
}

private RenderTarget2D CreateRenderTarget()
{
    var pp = GraphicsDevice.PresentationParameters;
    return new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight);
}`

Thank all of you very much for your help! To be honest, the forum looks a bit sleepy, but the community is amazing!

I didn’t get a chance to look last night but it looks like you guys got it sorted out. Nice :slight_smile:

Yes, it is resolved now.

I am working with Monogame for about a week and I must say I am really impressed. The framework is clean and well organized, it is a real joy to develop with it.

Since it’s around this topic, I also wanted to point out the use of RenderTargetUsage.PreserveContents in an overload of the RenderTarget2D constructor. This can be a helpful feature when you need to create various render targets between drawing to the backbuffer and such, but be mindful of its possible performance costs, pending on use.