4

どこかで、多くの3Dオブジェクトをレンダリングするときに、これらをマージして巨大なメッシュを形成し、描画呼び出しが1回だけ行われるようにすることができると読んだことがあります。したがって、「GPUはその魔法を実行します」と引用しますが、CPUは描画以外の呼び出しに使用できます。

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

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

グラフィックパフォーマンスの経験がないので、ヒント、リンク、その他の問題についての洞察は大歓迎です。

編集:私の悪い説明でごめんなさい。私は個人用のタイルエンジンを作成しており、可能な限り用途が広いことを望んでいます。したがって、近い将来にたくさんのタイルを描画する必要がある場合に備えて、最適化したいと思います。

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

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

私が収集した情報は、draw()の呼び出しはパフォーマンスの低下であり、できるだけ少なく呼び出す必要があるということです。確認または拒否する人はいますか?:)

4

4 に答える 4

11

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

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

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

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

私がこれを完全に作り上げているわけではないことをご承知おきください。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 回だけ描画しました。一番下のテストケースでは、質問で尋ねたように、128x72 の 1 つのソース画像をタイルで描画しました。これが結果です。

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

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

于 2009-10-28T21:02:24.383 に答える
3

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

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

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

于 2009-10-29T13:13:17.903 に答える
1

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

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

于 2012-10-18T01:52:02.640 に答える
0

パフォーマンスは普遍的な義務でも、神からの命令でもありません。それは目的を達成するための手段です。あなたが持っているものが十分に機能する場合、そのパフォーマンスを改善しても文字通り何も得られません. 「常に可能な限り最高のパフォーマンス」を維持することは、時期尚早の最適化の定義であり、防止するよりも多くの問題を引き起こします。

于 2010-08-16T18:33:18.890 に答える