【问题标题】:XNA screenshot shows pre-Bloom, not final renderXNA 屏幕截图显示的是预渲染,而不是最终渲染
【发布时间】:2012-12-12 08:20:06
【问题描述】:

我有一个使用 Reach 图形设置用 C# XNA 4.0 编码的 Windows 平台游戏。我的项目基于 GameStateManagement 示例,但后来我添加了 Bloom 和 spriteSheet/spriteBatch 功能。

我希望保存最终屏幕输出的屏幕截图。但是,当我保存我的屏幕截图时,它只显示了在应用 Bloom 之前和显示我的 HUD 文本之前的渲染(我在 Bloom 之后绘制)。在这两个过程之后,我在 Draw 方法结束时保存了我的屏幕截图。

我尝试过各种各样的事情。安德鲁在Take screen shot in XNA 的回答很有帮助,并且确实保存了图像;但是,它不会保存最终渲染。

我感觉它与绽放过程或精灵批次有关。

这是我的代码:

    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();
    }

}

【问题讨论】:

  • 您是否在 spriteBatch.Begin() 调用中使用 SpriteSortMode.Deferred?
  • 是的,我是:spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
  • 为什么要保存spritebatch.End()之前的截图?你有没有试过如果你以后这样做会发生什么?
  • 它不会改变结果。
  • 可能在您保存屏幕截图时显卡还没有时间服务于 Bloom + HUD 绘制调用?

标签: c# xna screenshot spritebatch bloom


【解决方案1】:

问题出在这里:

ScreenManager.GraphicsDevice.SetRenderTarget(null);

由于这条线,您将效果绘制到后台缓冲区,但您保存的渲染目标被单独留下。您会看到效果的结果,因为它是直接绘制的,但您保存的不是您绘制到后台缓冲区的内容。要解决此问题,请将效果绘制到另一个 RenderTarget,然后将其作为单个纹理绘制到后台缓冲区。显然,这是对进程的另一个绘制调用,但它的成本最低。这样一来,您就可以从新的 RenderTarget 中获取纹理并根据需要进行保存。

【讨论】:

  • 啊,谢谢。你说的有效。我最终创建了 renderTargetFinal,将其设置为目标,然后设置为 null 并将 final 绘制为 null。屏幕截图运行良好。
猜你喜欢
  • 2014-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-30
  • 1970-01-01
  • 1970-01-01
  • 2013-04-28
  • 1970-01-01
相关资源
最近更新 更多