Jump to content
  • Advertisement
Sign in to follow this  
MasterEvilAce

[XNA] Manual "Premultiply Alpha" rendering issue

This topic is 2613 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm using XNA4, and I was rendering everything perfectly to screen using spritebatches on premultiplied alpha PNG's.
Decided to forego the Content.Load that XNA provides and use Texture2D.FromStream in order to dynamically load PNGs, in order for the artist to test graphical changes quicker without recompiling.

In doing so I had to find some code in order to convert the Texture2D to a "premultiplied alpha" format, which is what XNA4 defaults to normally.

This is the code I found from: http://jakepoz.com/jake_poznanski__speeding_up_xna.html

// Blah blah
Texture2D t = Texture2D.FromStream(graphicsDevice, titleStream);
// Blah blah


blendColor = new BlendState();
blendColor.ColorWriteChannels = ColorWriteChannels.Red | ColorWriteChannels.Green | ColorWriteChannels.Blue;
blendColor.AlphaDestinationBlend = Blend.Zero;
blendColor.ColorDestinationBlend = Blend.Zero;
blendColor.AlphaSourceBlend = Blend.SourceAlpha;
blendColor.ColorSourceBlend = Blend.SourceAlpha;

blendAlpha = new BlendState();
blendAlpha.ColorWriteChannels = ColorWriteChannels.Alpha;
blendAlpha.AlphaDestinationBlend = Blend.Zero;
blendAlpha.ColorDestinationBlend = Blend.Zero;
blendAlpha.AlphaSourceBlend = Blend.One;
blendAlpha.ColorSourceBlend = Blend.One;


RenderTarget2D target = new RenderTarget2D(graphicsDevice, t.Width, t.Height);
graphicsDevice.SetRenderTarget(target);
{
graphicsDevice.Clear(Color.Black);
SpriteBatch spriteBatch = new SpriteBatch(graphicsDevice);

// Multiply each color by the source alpha, and write in just the color values into the final texture
spriteBatch.Begin(SpriteSortMode.Immediate, blendColor);
spriteBatch.Draw(t, t.Bounds, Color.White);
spriteBatch.End();

// Now copy over the alpha values from the PNG source texture to the final one, without multiplying them
spriteBatch.Begin(SpriteSortMode.Immediate, blendAlpha);
spriteBatch.Draw(t, t.Bounds, Color.White);
spriteBatch.End();
}
graphicsDevice.SetRenderTarget(null);
t = target as Texture2D;


Using this code, everything renders correctly just as it did before the switch-over.
However, now when I resize the game window (or maximize/restore the window) the rendering breaks, and all textures end up black. The only thing that still renders is the HUD, where I used DrawString().
This did not happen previously.
Infact, I can comment out all of the Premultiply Alpha code from above, and the issue goes away, except now that I'm not using a "premultiplied alpha" texture, the rendering is funky.

What is the issue that is going on, here? I have a feeling it has to do with changing the RenderTarget, but I'm not entirely sure.

Share this post


Link to post
Share on other sites
Advertisement
Doing some more investigating.. I found this post
http://stackoverflow.com/questions/5509265/after-writing-to-a-rendertarget-how-to-efficiently-clone-the-output

It looks like RenderTarget2D is volatile and can lose its contents when the backbuffer resizes. This makes sense.
I've noticed there is a RenderTargetUsage.PreserveContents that can be passed in via constructor.. I've tried this and it makes no difference at all. (This doesn't make sense.)

I see there was no "real solution" to the guy's problem...
For now I'm going to use his solution and copy the texture data from the RenderTarget2D into a new Texture2D.

I'm still wondering if anybody has any better ideas?

Share this post


Link to post
Share on other sites
It's my understanding that rendertarget contents are lost when the graphicsdevice is lost/reset. If the device is reset, you have to handle re-creating the texture data again. Do not use RednerTarget2D to store data between frames*, since they may not persist (I think some dynamic vertex buffers are the same way).

For what you are describing, it seems much simpler to just use GetData<Color> and SetData<Color> and multiply the alpha for every pixel in a Texture2d. Or, you can use your drawing method above, and then copy the data over to a Target2D.

EDIT: *that is, data that you don't want to have to regenerate after a device lost event

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!