XNA - 描画パフォーマンスを向上させるためにスプライトを結合しますか?

StackOverflow https://stackoverflow.com/questions/1637086

  •  06-07-2019
  •  | 
  •  

質問

大量の 3D オブジェクトをレンダリングするときに、それらをマージして巨大なメッシュを形成し、描画呼び出しが 1 回だけ行われるようにできるとどこかで読みました。したがって、次のように引用させてください。「GPU はその魔法を発揮する」一方で、 CPU は他の通話のために空きます 描くよりも。

それで私の質問ですが、これは実現可能でしょうか? 2D環境パフォーマンス 念頭に置いて?

たとえば、単純なタイル システムがあるとします。ビュー内の各タイルに対して描画呼び出しを行う代わりに、 すべてのタイルを結合する 大きなスプライトを形成し、それに対して描画を呼び出します。

私にはグラフィックス パフォーマンスに関する経験がまったくないため、ヒントやリンクなど、この問題に関する洞察をいただければ幸いです。

編集: 説明が悪くてごめんなさい。私は個人使用のためにタイルエンジンを作成しており、できるだけ多用途にしたいと考えています。したがって、近い将来に大量のタイルを描画する必要がある場合に備えて最適化したいと考えています。

する タイルシートを使用しますが、私が質問で言いたかったのは、シートから描画されるすべてのタイルを新しい Texture2D にマージするとパフォーマンスが向上するかどうかです。例えば:

画面上に描画する 128x72 のタイルがあります。すべてのタイルをループして、描画するタイルごとにdrawを呼び出す代わりに、すべてのタイルをサイズ1280x720の新しいスプライトにマージして描画します。この方法では、draw() メソッドのみが呼び出されます。 フレームごとに 1 回. 。私の 質問 3D を実行するときに 3D オブジェクトを単一のメッシュにマージするので、パフォーマンスが向上するかどうかでした。

なぜなら、私が集めた情報によると、draw() の呼び出しはパフォーマンスに大きな負荷がかかるため、できるだけ呼び出しを少なくする必要があるからです。肯定したり否定したりする人はいますか?:)

役に立ちましたか?

解決

XNA と 3D については経験がありませんが、2D ゲームについてアドバイスをさせていただきます。私は今年の初めに XNA でタイル エンジンを作成するのに時間を費やしましたが、同じことを疑問に思いました。簡単に言うと「はい」です。パフォーマンスが心配な場合は、タイルをより大きなスプライトに結合するのが良い考えです。ただし、興味がある場合は、さらに長い答えがあります。

一般に、パフォーマンスの最適化に関しては、答えはほとんど常に「それをしないでください」です。パフォーマンスのために最適化する必要があると確信している場合は、次の答えはほとんど常に「まだやらないでください」です。最後に、パフォーマンスのために最適化しようとする場合、最も重要なことは、ベンチマークを使用して、変更の前後にパフォーマンスの正確な測定値を収集することです。それがなければ、成功しているかどうかはわかりません。

さて、2D ゲームに関連して、テクスチャの切り替えを少なくするほど、タイル エンジンのパフォーマンスが大幅に向上することがわかりました。たとえば、草タイルと砂利タイルがあるとします。これらがメモリ内の 2 つの別個のテクスチャであり、草タイル、次に砂利タイル、そして草タイルを画面に描画すると、GPU は草テクスチャをロードし、次に砂利テクスチャのロードに切り替えてから、草のテクスチャを元に戻して、別の草のタイルを描画します。これにより、パフォーマンスが急速に低下します。これを回避する最も簡単な方法は、スプライトシートを用意し、草と砂利のタイルを 1 つのテクスチャに配置し、毎回同じテクスチャ上の異なる領域から描画するように SpriteBatch に指示するだけです。

もう 1 つ考慮すべき点は、画面上に一度に描画するタイルの数です。具体的には思い出せませんが、一度に何千ものタイルを描画していました(ズームアウトした表示で)。質問で示唆されているように、より大きなタイルを使用し、描画するタイルの数を減らしたところ、パフォーマンスも向上したことに気付きました。ただし、これは前の段落で説明したほど大きな改善ではありませんでした。それでも、さまざまな実装によるパフォーマンスの変化を測定することをお勧めします。また、数十または数百のタイルしか描画していない場合は、今すぐ最適化を試みる価値はないかもしれません (2 番目の段落を参照)。

私がこれを完全にでっち上げているわけではないことを知っておいていただきたいのですが、ここにテクスチャ スワッピングやスプライトシートなどに関する Shawn Hargreaves の投稿へのリンクを貼っておきます。このトピックについて検索すると、XNA フォーラムや Shawn Hargreaves のブログにもおそらくより適切な投稿があるでしょう。

http://forums.xna.com/forums/p/24254/131437.aspx#131437

アップデート:

質問を更新したので、私の投稿も更新させてください。パフォーマンスの違いがどのようなものかを知るために、いくつかのサンプルのベンチマークを行うことにしました。私の Draw() 関数には次のものがあります。

        GraphicsDevice.Clear(Color.CornflowerBlue);

        Stopwatch sw = new Stopwatch();
        sw.Start();

        spriteBatch.Begin();

#if !DEBUG
        spriteBatch.Draw(tex, new Rectangle(0, 0, 
                         GraphicsDevice.Viewport.Width,
                         GraphicsDevice.Viewport.Height), 
                         Color.White);            
#else
        for (int i = 0; i < 128; i++)
            for (int j = 0; j < 72; j++)
            {
                Rectangle r = new Rectangle(i * 10, j * 10, 10, 10);
                spriteBatch.Draw(tex, r, r, Color.White);
            }
#endif
        spriteBatch.End();

        sw.Stop();

        if (draws > 60)
        {
            numTicks += sw.ElapsedTicks;
        }
        draws++;

        if (draws % 100 == 0)
            Console.WriteLine("avg ticks: " + numTicks / (draws - 60));

        base.Draw(gameTime);

「#if !DEBUG」ステートメントに感嘆符をドロップするだけで、2 つの方法を切り替えることができます。最初の 60 回の抽選はいくつかの初期設定 (実際にはわかりません) が含まれており、平均を歪めていたためスキップしました。1280x720 の画像を 1 つダウンロードし、一番上のテスト ケースでは 1 回だけ描画しました。一番下のテストケースでは、質問で質問したように、1 つのソース画像を 128x72 のタイルで描画しました。結果は次のとおりです。

1 つの画像を描画する:

avg ticks: 68566
avg ticks: 73668
avg ticks: 82659
avg ticks: 81654
avg ticks: 81104
avg ticks: 84664
avg ticks: 86626
avg ticks: 88211
avg ticks: 87677
avg ticks: 86694
avg ticks: 86713
avg ticks: 88116
avg ticks: 89380
avg ticks: 92158

128x72 タイルの描画:

avg ticks: 7902592
avg ticks: 8052819
avg ticks: 8012696
avg ticks: 8008819
avg ticks: 7985545
avg ticks: 8028217
avg ticks: 8046837
avg ticks: 8291755
avg ticks: 8309384
avg ticks: 8336120
avg ticks: 8320260
avg ticks: 8322150
avg ticks: 8381845
avg ticks: 8364629

ご覧のとおり、そこには数桁の差があるため、これはかなり重要です。この種のことをテストするのは非常に簡単です。私が見逃した可能性のあるものを考慮に入れるために、特定の設定に対して独自のベンチマークを実行することをお勧めします。

他のヒント

グラフィックスカードがテクスチャを切り替える必要が少ないほど、パフォーマンスが向上します。必要に応じて、SpriteBatch.Begin()メソッドのテクスチャで並べ替えて、グラフィックカードがテクスチャをできるだけ切り替えないようにすることができます。

理にかなったら、タイル/スプライトをシートに入れました。たとえば、1つのキャラクターがシートにあり、タイルの1つのレイヤーが同じシートにある場合があります。これはこれまでのところかなりうまく機能しています。

ただし、最適化は必要になるまで最適化しないでください。ゲームが十分に高速に実行される場合、最適化に悩まされる理由です。

  

Rectangle r = new Rectangle(i * 10、j * 10、10、10);

多くの新しいオブジェクトを作成すると、ガベージコレクションが呼び出され、ガベージコレクションが大幅に遅くなる可能性があります。 新しいオブジェクトを大きなループに割り当てないでください:

パフォーマンスは普遍的な命令ではなく、神からの命令でもありません。それは終わりへの手段です。十分なパフォーマンスを発揮している場合、そのパフォーマンスを改善しても文字通り何も得られません。 「常に最高のパフォーマンス」を維持するは時期尚早な最適化の定義であり、防止するよりも多くの頭痛を引き起こします。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top