tags:

views:

1455

answers:

1

What I am trying to do is use alpha blending in XNA to make part of a drawn texture transparent. So for instance, I clear the screen to some color, lets say Blue. Then I draw a texture that is red. Finally I draw a texture that is just a radial gradient from completely transparent in the center to completely black at the edge. What I want is the Red texture drawn earlier to be transparent in the same places as the radial gradient texture. So you should be able to see the blue back ground through the red texture.

I thought that this would work.

GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin(SpriteBlendMode.None);
spriteBatch.Draw(bg, new Vector2(0, 0), Color.White);
spriteBatch.End();

spriteBatch.Begin(SpriteBlendMode.None);

GraphicsDevice.RenderState.AlphaBlendEnable = true;
GraphicsDevice.RenderState.AlphaSourceBlend = Blend.One;
GraphicsDevice.RenderState.AlphaDestinationBlend = Blend.Zero;
GraphicsDevice.RenderState.SourceBlend = Blend.Zero;
GraphicsDevice.RenderState.DestinationBlend = Blend.One;
GraphicsDevice.RenderState.BlendFunction = BlendFunction.Add;

spriteBatch.Draw(circle, new Vector2(0, 0), Color.White);
spriteBatch.End();

GraphicsDevice.RenderState.AlphaBlendEnable = false;

But it just seems to ignore all my RenderState settings. I also tried setting the SpriteBlendMode to AlphaBlend. It blends the textures, but that is not the effect I want.

Any help would be appreciated.

A: 

What you're trying to to is alpha channel masking.The easiest way is to bake the alpha channel using the content pipeline. But if for some reason you want to do it at runtime here's how (roughly) using a render target (A better and faster solution would be to write a shader)

First create a RenderTarget2D to store and intermediate masked texture

RenderTarget2D maskRenderTarget = GfxComponent.CreateRenderTarget(GraphicsDevice,
    1, SurfaceFormat.Single);

Set the renderTarget, and device state

GraphicsDevice.SetRenderTarget(0, maskRenderTarget);
GraphicsDevice.RenderState.AlphaBlendEnable = true;
GraphicsDevice.RenderState.DestinationBlend = Blend.Zero;
GraphicsDevice.RenderState.SourceBlend = Blend.One;

Set the channels to write to the R, G, B channels and draw the first texture using a sprite batch

GraphicsDevice.RenderState.ColorWriteChannels = ColorWriteChannels.Red  | ColorWriteChannels.Green | ColorWriteChannels.Blue;
spriteBatch.Draw(bg, new Vector2(0, 0), Color.White);

Set channels to alpha only, and draw the alpha mask

GraphicsDevice.RenderState.ColorWriteChannels = ColorWriteChannels.Alpha;
spriteBatch.Draw(circle, new Vector2(0, 0), Color.White);

you can now restore the render target to the back buffer and draw your texture using alpha blending.

maskedTexture = shadowRenderTarget.GetTexture();
...

Also don't forget to restore the state:

GraphicsDevice.RenderState.ColorWriteChannels = ColorWriteChannels.All;
...
Pop Catalin
Thanks for the answer and this is extremely close, but their is one problem. The circle texture is smaller than the background texture, and what is happening with the above code is the back ground is only drawn where the circle texture exists. The idea is to draw the circle texture where the mouse pointer is and the user can see through the back ground where the circle texture is.
DangerMouse
@David, If you need to invert the alpha mask clear the alpha channel using white and draw the circle using black.
Pop Catalin
It worked thanks. I had to add GraphicsDevice.RenderState.DestinationBlend = Blend.Zero;GraphicsDevice.RenderState.SourceBlend = Blend.One;right before drawing the circles to get it to work though. I thought this was the default values but it didn't work until I set them.Thanks for all the help.
DangerMouse