【问题标题】:XNA 4.0 Use Multiple Effects In One BatchXNA 4.0 在一批中使用多种效果
【发布时间】:2013-12-08 20:32:44
【问题描述】:

我正在为 XNA 4.0 开发图形引擎,但遇到了一个我找不到任何解决方案的问题。目前我正在尝试通过使用着色器来实现灯光效果。图形引擎还包含一个粒子引擎,因此至少考虑性能对我来说非常重要。这两件事的结合产生了问题。

首先,我进行了大量阅读和研究,据我了解,您进行的绘制调用越少,性能越好。通过绘制调用,我的意思是当 spritebatch 将实际几何体和纹理发送到 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() 时使用着色器。因此,上面的代码使用我上次应用的 pass 渲染了所有内容。

我的第三次尝试是使用 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 个不同的 SpriteBatch,然后在我进行最终绘制时将它们组合起来,这样图层深度就不会被弄乱?

【问题讨论】:

标签: c# optimization shader xna-4.0 spritebatch


【解决方案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();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-01
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    • 2015-04-16
    相关资源
    最近更新 更多