所以我用XNA 3.1做了一件事,我有很多通过像素着色器应用的单独效果。这些来自各种各样的来源,如特殊攻击、环境等等。我遇到的问题是,我注意到帧速率显著降低。
目前,我正在将整个场景绘制到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,这当然是不可接受的。我想知道是否有更有效的方法来做到这一点。考虑到我只有一个纹理,我认为我可以将效果组合到一个文件中,并执行多个过程,而无需将纹理抓回来。然而,我不确定这是否可能。
我真的不确定最好的方法是什么,尽管我想肯定有比我现在做的更好的方法
片段中的方法可能非常慢,因为您正在为每个效果进行纹理抓取和全屏绘制,这会在着色器内部发生的一切之上,强调CPU和GPU之间的内存带宽。正如您在文章中所建议的那样,您可能需要创建一组着色器,每个着色器都包含多个操作,而不是一遍又一遍地运行读写循环:一个昂贵的着色器通常仍然比简单着色器的许多读写重复要快。
你可能想看看Shawn Hargreaves关于HLSL中着色器片段的文章,以及Tim Jones在XNA 中这样做的代码
绘制时是否对所有内容都进行了完全着色?如果着色器计算量很大,则应首先执行"深度传递",仅Z测试/写入Z缓冲区(颜色缓冲区写入处于禁用状态)。此外,使用简单的着色器"深度填充"屏幕。
换句话说,渲染所有不透明对象,在第一次通过时只更新深度缓冲区
在第二个过程中,启用着色器(并禁用深度写入,无需使用带宽来写回已存在的相同值)。这将掩盖任何透支像素的所有不必要的工作,因为它们将立即通过深度测试。
编辑:现在我意识到OP是在做全屏效果,而不是场景渲染。