14

所以我正在用 XNA 3.1 做一个东西,我有很多通过像素着色器应用的单独效果。这些来自各种来源,例如特殊攻击,环境等。我遇到的问题是我注意到帧速率显着降低。

目前,我正在将整个场景绘制到 RenderTarget2D,然后将所有效果应用到该 RenderTarget2D。我存储了一个包含效果及其 ID 的 SortedDictionary(ID 用于在运行时更改参数),并且我正在对其进行迭代并一个接一个地应用每个效果:

foreach(KeyValuePair<Ref<int>,Effect> p in renderEffects)
{
    Effect r = p.Value;
    g.SetRenderTarget(0, MainGame.MainRenderTarget);
    //Change RenderTarget to allow code to grab existing texture in the same draw area.
    levelDraw = MainGame.LevelRenderTarget.GetTexture();
    //Change back to draw back to this texture, allowing render effects to be layered.
    g.SetRenderTarget(0, MainGame.LevelRenderTarget);

    MainGame.StartDraw(MainGame.GameBatch);
    //Starts the sprite batch and sets some parameters
    r.Begin();
    r.CurrentTechnique.Passes[0].Begin();
    MainGame.GameBatch.Draw(levelDraw, new Rectangle(0, 0, levelDraw.Width, levelDraw.Height), Color.White);
    r.CurrentTechnique.Passes[0].End();
    r.End();
    MainGame.GameBatch.End();
}

现在,当仅叠加 3 个效果时,这会产生明显的帧丢失,而当应用 10 个效果时,它会从 60FPS 下降到 16FPS,这当然是不可接受的。我想知道是否有更有效的方法来做到这一点。考虑到我只有一个纹理,我认为我可以将效果组合到一个文件中并执行多个通道,而无需重新抓取纹理。但是,我不确定这是否可能。

我不太确定最好的方法是什么,尽管我想一定有比我现在做的更好的方法。

4

2 回答 2

2

片段中的方法可能非常慢,因为您正在为每个效果进行纹理抓取和全屏绘制,这会在着色器内部发生的任何事情之上强调 CPU 和 GPU 之间的内存带宽。正如您在帖子中建议的那样,您可能需要创建一组着色器,每个着色器都包含多个操作,而不是一遍又一遍地运行读写循环:一个昂贵的着色器通常仍然比许多读写重复更快简单的着色器。

您可能想查看Shawn Hargreaves 关于 HLSL 中的着色器片段的文章以及Tim Jones 在 XNA 中执行此操作的代码

于 2012-12-30T08:40:39.133 回答
1

绘制时是否对所有内容进行了完全着色?如果你的着色器计算量很大,你应该先做一个“深度通道”,只测试/写入 Z 缓冲区(颜色缓冲区写入关闭)。此外,使用非常简单的着色器来“深度填充”屏幕。

换句话说,渲染所有不透明对象仅在第一遍时更新深度缓冲区。

在第二次通过时,您打开着色器(并关闭深度写入,无需使用带宽来写回已经存在的相同值)。这将掩盖任何透支像素的所有不必要的工作,因为它们将立即通过深度测试。

编辑:现在我意识到 OP 正在做全屏效果,而不是场景渲染。

于 2012-12-22T03:03:22.537 回答