I'm creating a basic scene/level editor using XNA/Winforms using the base classes from http://xbox.create.msdn.com/en-US/education/catalog/sample/winforms_series_1
Everything works fine and gets drawn to my custom graphics device control - grid, axis, random testcube.
However, I'm loading textures using Texture2D.FromStream, and then applying alpha pre-multiplication to mimic the content pipelines behaviour. This involves rendering the texture to a RenderTarget2D, overwriting the existing texture data, and then restoring the default back buffer with SetRenderTarget(null). Afterwards, the control doesn't render anything. It clears the screen with the default color, but nothing shows - no grid, no axis, no random test cube.
Curiously, if I use the same texture loading method in my XNA game, everything works as expected. Textures gets loaded and everything shows up ingame.
Things I've tried:
- Disabling the alpha pre-multiplication function (everything shows up, nothing shows if its enabled)
- Calling reset on the graphics device and its service to see if that fixes it (it doesn't)
- Changing the color used to clear the screen when I've loaded a texture (screen color changes and everything vanishes)
- Recreating my grid, axis and test box (nothing shows)
- Fixing the projection/view so it looks at (0,0,0) (everything still disappears)
Anyone know what the underlying issue is here, or anything else I could try?
Render code
GraphicsDevice.Clear(Color.CornflowerBlue);
effect.World = Matrix.Identity;
// set the current view
effect.View = GetCurrentView();
effect.Projection = GetCurrentProjection();
// if wireframe, render as wireframe
if (WireframeMode)
GraphicsDevice.RasterizerState = wireRS;
if (Scene != null)
for (int i = 0; i < Scene.Meshes.Count; i++)
{
Mesh mesh = Scene.Meshes[i];
for (int j = 0; j < mesh.MeshParts.Count; j++)
{
MeshPart meshPart = mesh.MeshParts[j];
Texture2D texture = SynthesisManager.Import<Texture2D>(Scene.Materials[meshPart.MaterialIndex].DiffuseTexture);
effect.Texture = texture;
for (int k = 0; k < effect.CurrentTechnique.Passes.Count; k++)
{
effect.CurrentTechnique.Passes[k].Apply();
meshPart.Draw(GraphicsDevice);
}
}
}
// if wireframe is on, revert back to original
if (WireframeMode)
GraphicsDevice.RasterizerState = normalRS;
grid.Draw(GetCurrentView(), GetCurrentProjection());
Texture Alpha Pre-Multiplication
blendColorState = new BlendState
{
ColorDestinationBlend = Blend.Zero,
ColorWriteChannels = ColorWriteChannels.Red | ColorWriteChannels.Green | ColorWriteChannels.Blue,
AlphaDestinationBlend = Blend.Zero,
AlphaSourceBlend = Blend.SourceAlpha,
ColorSourceBlend = Blend.SourceAlpha
};
blendAlphaState = new BlendState
{
ColorWriteChannels = ColorWriteChannels.Alpha,
AlphaDestinationBlend = Blend.Zero,
ColorDestinationBlend = Blend.Zero,
AlphaSourceBlend = Blend.One,
ColorSourceBlend = Blend.One
};
GraphicsDevice gd = synthesisManager.GraphicsDevice;
SpriteBatch sb = synthesisManager.SpriteBatch;//new SpriteBatch(gd);
RenderTarget2D target = new RenderTarget2D(synthesisManager.GraphicsDevice, texture.Width, texture.Height);
Viewport viewportBackup = gd.Viewport;
gd.SetRenderTarget(target);
gd.Clear(Color.Black);
// Multiply each color by the source alpha, and write in just the color values into the final texture
sb.Begin(SpriteSortMode.Immediate, blendColorState);
sb.Draw(texture, texture.Bounds, Color.White);
sb.End();
// Now copy over the alpha values from the source texture to the final one, without multiplying them
sb.Begin(SpriteSortMode.Immediate, blendAlphaState);
sb.Draw(texture, texture.Bounds, Color.White);
sb.End();
// Release the GPU back to drawing to the screen
gd.SetRenderTarget(null);
gd.Viewport = viewportBackup;
// set the render target as the new texture
texture = target as Texture2D;
[EDIT]
Further investigating has revealed this section of code to be the cause of my problem
// Now copy over the alpha values from the source texture to the final one, without multiplying them
sb.Begin(SpriteSortMode.Immediate, blendAlphaState);
sb.Draw(texture, texture.Bounds, Color.White);
sb.End();
For whatever reason, this seems to be causing nothing to be rendered out. How and why I don't know, since this is the only time I'm using a SpriteBatch (currently) in my code, and all my other draw calls are using DrawPrimitives and DrawIndexedPrimitives.
[EDIT 2]
I've managed to narrow it down further. The issue seems to be with the ColorWriteChannels = ColorWriteChannels.Alpha
line in the blendAlphaState
tantalizer. Why this only causes a problem in WinForms and not XNA stumps me. Its all using the same code underneath.
SaveAsPng
on your texture can you verify that there is actual content properly rendered on that texture? Have you tried just using one of the built in blend states? \$\endgroup\$SaveAsPng
. I haven't tried the default blend states since they don't do the required operations correctly, hence the need for custom ones. Anyway, I've managed to narrow down the problem further. \$\endgroup\$