Question

I have a windows platform game coded in C# XNA 4.0 using the Reach graphics settings. My project is based on the GameStateManagement sample but I later added Bloom and spriteSheet/spriteBatch functionality to it.

I desire to have a screenshot saved of the final screen output. However, when I save my screenshot it only shows the render before Bloom was applied and before my HUD text is displayed (which I draw after the Bloom). I have my screenshot saved at the end of my Draw method, after these two processes.

I have tried all kinds of things. Andrew's answer here Take screen shot in XNA was helpful and does save out an image; however, it is not saving out the final render.

I have a feeling it has something to do with the bloom process or maybe the spritebatch.

Here is my code:

    example {
    public override void Draw(GameTime gameTime)
    {
        ScreenManager.GraphicsDevice.SetRenderTarget(sceneRenderTarget);
        // Clear the screen to black
        ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
                                           Color.Black, 0, 0);
        SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
        spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);

    // then i draw all my game stuff

        spriteBatch.End();

        #region Post-Processing & Bloom
        ScreenManager.GraphicsDevice.SamplerStates[1] = SamplerState.LinearClamp;

        // Pass 1: draw the scene into rendertarget 1, using a
        // shader that extracts only the brightest parts of the image.
        bloomExtractEffect.Parameters["BloomThreshold"].SetValue(
            Settings.BloomThreshold);

        DrawFullscreenQuad(sceneRenderTarget, renderTarget1,
                           bloomExtractEffect,
                           IntermediateBuffer.PreBloom);

        // Pass 2: draw from rendertarget 1 into rendertarget 2,
        // using a shader to apply a horizontal gaussian blur filter.
        SetBlurEffectParameters(1.0f / (float)renderTarget1.Width, 0);

        DrawFullscreenQuad(renderTarget1, renderTarget2,
                           gaussianBlurEffect,
                           IntermediateBuffer.BlurredHorizontally);

        // Pass 3: draw from rendertarget 2 back into rendertarget 1,
        // using a shader to apply a vertical gaussian blur filter.
        SetBlurEffectParameters(0, 1.0f / (float)renderTarget1.Height);

        DrawFullscreenQuad(renderTarget2, renderTarget1,
                           gaussianBlurEffect,
                           IntermediateBuffer.BlurredBothWays);

        // Pass 4: draw both rendertarget 1 and the original scene
        // image back into the main backbuffer, using a shader that
        // combines them to produce the final bloomed result.
        ScreenManager.GraphicsDevice.SetRenderTarget(null);

        EffectParameterCollection parameters = bloomCombineEffect.Parameters;

        parameters["BloomIntensity"].SetValue(Settings.BloomIntensity);
        parameters["BaseIntensity"].SetValue(Settings.BaseIntensity);
        parameters["BloomSaturation"].SetValue(Settings.BloomSaturation);
        parameters["BaseSaturation"].SetValue(Settings.BaseSaturation);

        ScreenManager.GraphicsDevice.Textures[1] = sceneRenderTarget;

        Viewport viewport = ScreenManager.GraphicsDevice.Viewport;

        DrawFullscreenQuad(renderTarget1,
                           viewport.Width, viewport.Height,
                           bloomCombineEffect,
                           IntermediateBuffer.FinalResult);

        #endregion

        spriteBatch.Begin();
        // Draw HUD
        spriteBatch.End();


        if (screenShotTake)
        {
            using (FileStream fs = File.Open(@"screenshot" + (screenshotNumber) + @".png", FileMode.OpenOrCreate))
            {
                // Right here I try to save out the screen shot Texture2D
                sceneRenderTarget.SaveAsPng(fs, (int)viewportSize.X, (int)viewportSize.Y); // save render target to disk
            }
        }
    }




    #region PostProcess & Bloom
    void DrawFullscreenQuad(Texture2D texture, RenderTarget2D renderTarget,
                            Effect effect, IntermediateBuffer currentBuffer)
    {
        ScreenManager.GraphicsDevice.SetRenderTarget(renderTarget);

        DrawFullscreenQuad(texture,
                           renderTarget.Width, renderTarget.Height,
                           effect, currentBuffer);


    }

    void DrawFullscreenQuad(Texture2D texture, int width, int height,
                            Effect effect, IntermediateBuffer currentBuffer)
    {
        if (showBuffer < currentBuffer)
        {
            effect = null;
        }

        spriteBatch.Begin(0, BlendState.Opaque, null, null, null, effect);
        spriteBatch.Draw(texture, new Rectangle(0, 0, width, height), Color.White);
        spriteBatch.End();
    }

}

Was it helpful?

Solution

The problem is here:

ScreenManager.GraphicsDevice.SetRenderTarget(null);

Because of this line, you draw the effects to the back buffer, but the render target you're saving is left alone. You see the results of the effects because it's drawn directly, but what you save is not what you've drawn to the back buffer. To fix this, draw the effects to another RenderTarget, and then draw that as a single texture to the back buffer. Obviously this is another draw call to process, but it's a minimal cost. By doing that, you can then grab the texture from the new RenderTarget and save it however you like.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top