我正在为XNA 4.0开发图形引擎,我遇到了一个我找不到任何解决方案的问题。目前我正在尝试使用着色器实现灯光效果。图形引擎也包含一个粒子引擎,因此至少考虑性能对我来说非常重要。这两件事的结合会产生问题。
首先,我做了大量的阅读和研究,据我所知,你可以获得更好的表现。通过绘制调用,我的意思是当spograbatch将实际几何和纹理发送到GPU时。因此,我试图在一个批次中尽可能多地绘制。
现在出现了问题。我的引擎绘制方法有2个重载:
public static void Draw(Texture texture)
{
// Call spriteBatch.Draw(...);
}
public static void Draw(Light light)
{
// Call spriteBatch.Draw(...);
}
第一个重载只是使用默认着色器绘制普通纹理。第二个重载是绘制一个使用另一个着色器的灯。我想做的是:
public static void Draw(Texture texture)
{
// Use default shader
// Call spriteBatch.Draw(...);
}
public static void Draw(Light light)
{
// Use light shader
// Call spriteBatch.Draw(...);
}
但是,SpriteBatch不支持同时使用多个着色器,因此我尝试使用效果传递执行此操作:
public static void Draw(Texture texture)
{
effect.CurrentTechnique.Passes[0].Apply();
// Call spriteBatch.Draw(...);
}
public static void Draw(Light light)
{
effect.CurrentTechnique.Passes[1].Apply();
// Call spriteBatch.Draw(...);
}
这不起作用,因为调用spriteBatch.Draw()时未使用着色器,而是调用spriteBatch.End()时。因此,上面的代码使用我最后应用的传递来渲染所有内容。
我的第三次尝试是使用2个SpriteBatches:
public static void Begin()
{
spriteBatchColor.Begin([...], null); // Default shader.
spriteBatchLight.Begin([...], effect); // Light shader.
}
public static void Draw(Texture texture)
{
// Call spriteBatchColor.Draw(...);
}
public static void Draw(Light light)
{
// Call spriteBatchLight.Draw(...);
}
public static void End()
{
spriteBatchColor.End();
spriteBatchLight.End();
}
这确实有效,但是我的图层深度完全搞砸了,这并不是很奇怪,因为spriteBatchLight.End()最后被调用,所以它总是被绘制在spriteBatchColor所绘制的所有内容之上。
我知道我可以将SpriteSortMode设置为SpriteSortMode.Immediate,但之后我会获得很大的性能,因为该模式直接绘制了所有内容。由于在这种情况下性能非常重要,因此我希望通过尽可能少地绘制GPU调用进行优化,SpriteSortMode.Immediate对我来说不是一个选项。
所以,我的问题是:
有什么方法可以在一个批次中使用2种不同的效果/技巧/传递 ?或者有什么方法可以使用2个不同的SpriteBatches但是当我进行最终绘制时将它们组合在一起,这样层深度就不会搞砸了?
答案 0 :(得分:1)
实际执行此操作的方法是在主游戏类中创建List<RenderTarget2D>
并将其传递给正在绘制的函数/类。
在引擎绘制方法中:
public static void Draw(Texture texture, List<RenderTarget2D> targetList)
{
RenderTarget2D target = new RenderTarget2D(...);
//Tell spriteBatch to draw to target instead of the screen
spriteBatch.GraphicsDevice.SetRenderTarget(target);
//Make the renderTarget's background clear
spriteBatch.GraphicsDevice.Clear(new Color(0,0,0,0))
spriteBatch.Begin();
//Apply effect and draw
spriteBatch.End();
targetList.Add(target);
}
然后将每个纹理绘制到屏幕上。
在游戏抽奖方法中:
void Draw()
{
List<RenderTarget2D> targetList = new List<RenderTarget2D>();
engine.Draw(texture, targetList);
engine.Draw(light, targetList);
//Tell spriteBatch to draw to the screen
spriteBatch.GraphicsDevice.SetRenderTarget(null)
//Make the screen background black
spriteBatch.GraphicsDevice.Clear(Color.Black)
spriteBatch.Begin();
//Draw each target in target list to screen
spriteBatch.End();
}