0

XNA 4.0 用のグラフィック エンジンの作業を行っていますが、解決策が見つからない問題に遭遇しました。現在、シェーダーを使用して光の効果を実装しようとしています。グラフィック エンジンもパーティクル エンジンで構成されているため、少なくともパフォーマンスを考慮することは非常に重要です。これら2つの組み合わせが問題を引き起こします。

まず第一に、私は多くの読書と調査を行ってきましたが、私が理解していることから、ドローコールが少ないほどパフォーマンスが向上します。ドロー コールとは、スプライト バッチが実際のジオメトリとテクスチャを GPU に送信するタイミングを意味します。したがって、私は1 つのバッチ内でできるだけ多くを描画しようとしています。

そして今、問題が発生します。エンジンの描画メソッドには 2 つのオーバーロードがあります。

public static void Draw(Texture texture)
{
    // Call spriteBatch.Draw(...);
}

public static void Draw(Light light)
{
    // Call spriteBatch.Draw(...);
}

最初のオーバーロードは、デフォルト シェーダーを使用して通常のテクスチャを描画するだけです。2 番目のオーバーロードは、別のシェーダーを使用するライトを描画します。私がやりたいことは次のとおりです。

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() が呼び出されたときに、これも機能しませんでした。したがって、上記のコードは、最後に適用したパスですべてをレンダリングしました。

私の 3 番目の試みは、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 はオプションではありません。

だから、私の質問は:

1 つのバッチ内で2 つの異なるエフェクト/テクニック/パスを使用する方法はありますか? または、2 つの異なる SpriteBatches を使用して、最終的な描画を行うときにそれらを組み合わせて、レイヤーの深さが台無しにならないようにする方法はありますか?

4

1 に答える 1

1

うわー、それは完全に間違っているので、私の以前の答えは無視してください。

これを行う実際の方法はList<RenderTarget2D>、メインのゲーム クラスで を作成し、それを描画している関数/クラスに渡すことです。

In Engine Draw メソッド:

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();
}
于 2014-03-10T04:27:19.080 に答える