0
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ Can you post your render code? \$\endgroup\$ – test Jan 5 '15 at 6:11
  • \$\begingroup\$ If you call 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\$ – test Jan 13 '15 at 17:55
  • \$\begingroup\$ It saves the modified texture correctly when using 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\$ – Seta Jan 14 '15 at 5:56
  • \$\begingroup\$ It doesn't answer the question "why is doesn't work" but can't you convert it without rendering? Get the data from the texture, convert the color values and use Texture.SetData<Color>()? \$\endgroup\$ – Felsir Jan 31 '16 at 10:38
0
\$\begingroup\$

So, you draw all on the render target and after calling gd.SetRenderTarget(null) you need draw your render target on the screen.

gd.SetRenderTarget(target);

// ... drawing on the render target ...

gd.SetRenderTarget(null); // now draw on the screen ...

sb.Begin();
sb.Draw(target, Vector2.Zero, Color.White); // ... your rended target
sb.End();
\$\endgroup\$
  • \$\begingroup\$ This doesn't answer my problem at all. I'm applying transforms to a texture using a render target, and then restoring the back buffer, and using the modified rendertarget (a glorified texture) in place of the original texture on my model which is being drawn to the back buffer along with my grid. Everything renders fine pre texture transform, but nothing after it. \$\endgroup\$ – Seta Jan 6 '15 at 22:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.