3

openGL で 2D ゲームを作成しています。ウィンドウ全体を覆ういくつかのテクスチャをレンダリングしているときに、いくつかのパフォーマンスの問題が発生しました。

私が実際に行っているのは、画面のサイズでテクスチャを作成し、FBO を使用してシーンをそのテクスチャにレンダリングし、異なるオフセットでテクスチャを数回レンダリングして、一種の「影」を作成することです。しかし、そうすると、内蔵ビデオ カードを使用しているときにパフォーマンスが大幅に低下します。

したがって、全体として、画面全体に7つのクワッドをレンダリングします(背景画像、黒い「色合い」の5つの「影画像」、および真の色の同じテクスチャ)。サイズが 1024x1024 で、900x700 のウィンドウに収まる RGBA テクスチャを使用しています。テクスチャをレンダリングしていないときは 200 FPS、レンダリングしているときは 34 FPS を取得しています (両方のシナリオで、実際にテクスチャを作成し、シーンをレンダリングします)。基本的に 7 つのクワッドしかレンダリングしていないため、これは非常に奇妙です。奇妙なことは、CPU プロファイラーを実行しても、これがボトルネックであることを示唆していないことです (opengl はパイプライン アーキテクチャを使用しており、これが発生する可能性があることは知っていますが、ほとんどの場合は発生しません)。

外部ビデオ カードを使用すると、上記のテストを実行すると、一貫して 200 FPS が得られます。しかし、テクスチャへのシーン レンダリングを無効にし、画面へのテクスチャ レンダリングを無効にすると、~1000 FPS になります。これは、外部ビデオ カードでのみ発生します。統合ビデオ カードを使用して FBO を無効にすると、同じ 200 FPS になります。これは本当に私を混乱させます。

何が起こっているのか、また上記の数字が正しいかどうかを説明できる人はいますか?

内蔵ビデオ カード - Intel HD Graphics 4000

外付けビデオカード - NVIDIA GeForce GTX 660M

PS私はC#でゲームを書いているので、それが役に立ったらOpenTKを使います。

編集:

まず第一に、すべての回答に感謝します。それらはすべてある意味で非常に役に立ちましたが、残念ながら、単に「コードを簡素化/最適化する」だけでは不十分だと思います。レンダリング コードの一部を共有させてください。

//fields defined when the program is initialized

Rectangle viewport;
//Texture with the size of the viewport
Texture fboTexture;
FBO fbo;

//called every frame
public void Render()
{
    //bind the texture to the fbo
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbo.handle);
    GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, fboTexture,
       TextureTarget.Texture2D, texture.TextureID, level: 0);

    //Begin rendering in Ortho 2D space
    GL.MatrixMode(MatrixMode.Projection);
    GL.PushMatrix();
    GL.LoadIdentity();
    GL.Ortho(viewport.Left, viewport.Right, viewport.Top, viewport.Bottom, -1.0, 1.0);
    GL.MatrixMode(MatrixMode.Modelview);
    GL.PushMatrix();
    GL.LoadIdentity();

    GL.PushAttrib(AttribMask.ViewportBit);
    GL.Viewport(viewport);

    //Render the scene - this is really simple I render some quads using shaders
    RenderScene();

    //Back to Perspective
    GL.PopAttrib(); // pop viewport
    GL.MatrixMode(MatrixMode.Projection);
    GL.PopMatrix();
    GL.MatrixMode(MatrixMode.Modelview);
    GL.PopMatrix();

    //Detach the texture
    GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, fboTexture, 0,
                    0, level: 0);
    //Unbind the fbo
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);

    GL.PushMatrix();
    GL.Color4(Color.Black.WithAlpha(128)); //Sets the color to (0,0,0,128) in a RGBA format

    for (int i = 0; i < 5; i++)
    {
        GL.Translate(-1, -1, 0);
        //Simple Draw method which binds the texture and draws a quad at (0;0) with
        //its size
        fboTexture.Draw();
    }
    GL.PopMatrix();
    GL.Color4(Color.White);
    fboTexture.Draw();
}

したがって、fbo とテクスチャへのレンダリングに実際に問題があるとは思いません。これは、両方のカードでプログラムの速度が低下する原因ではないためです。以前はフレームごとに fbo を初期化していたため、Nvidia カードの速度が低下した可能性がありますが、すべてを事前に初期化すると、fbo の有無にかかわらず同じ FPS が得られます。

テクスチャを無効にしてテクスチャのない四角形をレンダリングすると同じ結果が得られるため、一般的にテクスチャには問題がないと思います。それでも、画面全体をカバーする場合でも、画面に 7 つのクワッドのみをレンダリングする場合、統合カードは 40 FPS よりも高速に動作するはずだと思います。

これを実際にプロファイリングして結果を返信するにはどうすればよいか、ヒントを教えてください。それは本当に役に立ちます。

編集2:

OK、少し実験したところ、はるかに優れたパフォーマンスを得ることができました。最初に、最終的なクワッドをシェーダーでレンダリングしてみましたが、期待したほどパフォーマンスに影響はありませんでした。

次に、プロファイラーを実行しようとしました。しかし、私の知る限り、SlimTune は単なる CPU プロファイラーであり、望んでいた結果が得られませんでした。次に、gDEBugger を試してみました。Visual Studio と統合されていますが、後で .NET プロジェクトをサポートしていないことがわかりました。外部バージョンを実行してみましたが、うまくいかないようでした (ただし、十分に遊んでいないだけかもしれません)。

本当にうまくいったのは、7 つのクワッドを画面に直接レンダリングするのではなく、最初にテクスチャでレンダリングし、再び fbo を使用してから、最終的なテクスチャを画面に一度レンダリングしたことです。これで fps が 40 から 120 になりました。テクスチャへのレンダリングは、画面への直接レンダリングよりも高速なのはなぜですか? それにもかかわらず、みんなの助けに感謝します-私は私の問題を解決したようです. 誰かが状況の合理的な説明を思いついたら、本当に感謝します.

4

3 に答える 3

6

コードを見たりプロファイリングしたりしていないので、明らかにこれは推測ですが、統合カードは後処理 (「影」効果を実現するためにテクスチャを数回描画する) に苦労していると思います。

あなたがこれらの概念にどの程度精通しているかはわかりません。

後処理について

後処理とは、完成したシーンをテクスチャにレンダリングし、画面に表示する前に画像に効果を適用するプロセスです。後処理の一般的な用途は次のとおりです。

  • ブルーム - 明るいピクセルを隣接する暗いピクセルに「ブリード」することで、明るさをより自然にシミュレートします。

  • ハイ ダイナミック レンジ レンダリング - Bloom の兄貴分。シーンは浮動小数点テクスチャにレンダリングされ、より広い色範囲が可能になります (通常は 0 で黒、1 で完全な明るさになります)。画面に表示される最終的な色は、画面上のすべてのピクセルの平均輝度を使用して計算されます。これらすべての効果は、カメラが人間の目のように機能することです。暗い部屋では、明るい光 (たとえば、窓から) は非常に明るく見えますが、外に出ると、カメラは調整され、光はそのようにしか見えません。太陽を直視すると明るい。

  • セル シェーディング - 漫画のような外観になるように色が変更されます。

  • モーションブラー

  • 被写界深度 - ゲーム内のカメラは、特定の距離にあるオブジェクトのみが焦点を合わせ、残りはぼやけている実際のカメラ (またはあなたの目) に近似しています。

  • Deferred shading - シーンがレンダリングされた後に照明が計算される、後処理のかなり高度なアプリケーションです。これには大量のビデオ RAM が必要ですが (通常、複数のフルスクリーン テクスチャを使用します)、多数のライトをシーンにすばやく追加できます。

要するに、後処理を使用して多くの巧妙なトリックを行うことができます。不運にも...

後処理にはコストがかかる

後処理の優れた点は、そのコストがシーンの幾何学的な複雑さとは無関係であることです。100 万個の三角形を描画した場合でも、12 個の三角形を描画した場合でも、同じ時間がかかります。ただし、それが欠点でもあります。後処理を行うために四角形を何度もレンダリングするだけですが、各ピクセルのレンダリングにはコストがかかります。より大きなテクスチャを使用すると、コストが大きくなります。

専用のグラフィックス カードには明らかに、後処理を適用するためのコンピューティング リソースがはるかに多くありますが、統合カードには通常、適用できるリソースがはるかに少なくなります。このため、ビデオ ゲームの「低い」グラフィック設定では多くの後処理効果が無効になることがよくあります。遅延はグラフィックス カードで発生するため、これは CPU プロファイラーのボトルネックとして表示されません。CPU は、グラフィック カードが終了するのを待ってからプログラムを続行します (より正確には、CPU はグラフィック カードが終了するのを待っている間、別のプログラムを実行しています)。

どうすれば物事をスピードアップできますか?

  • より少ないパスを使用します。パスを半分にすると、後処理にかかる時間が半分になります。そのために、

  • シェーダーを使用します。どこにも言及していないので、後処理にシェーダーを使用しているかどうかはわかりません。シェーダーを使用すると、基本的に C に似た言語で関数を記述できます (OpenGL を使用しているため、GLSL または Cg を使用できます)。この関数は、オブジェクトのレンダリングされたすべてのピクセルで実行されます。これらは好きなパラメータを取ることができ、後処理に非常に役立ちます。シェーダーを使用してクワッドを描画するように設定すると、シーンのすべてのピクセルで実行したいアルゴリズムを挿入できます。

于 2012-10-30T01:07:45.630 に答える
1

いくつかのコードを見るといいでしょう。2 つの間の唯一の違いが外部 GPU を使用するかどうかである場合、GPU へのデータのストリーミングが遅くなる可能性があるため、違いはメモリ管理 (つまり、FBO をいつどのように作成するかなど) にある可能性があります。あらゆる種類の OpenGL バッファを作成するもの、またはあらゆる種類のデータをそれに送信するものを初期化に移動してみてください。あなたが何をしているかを正確に見なければ、これ以上詳細なアドバイスをすることはできません.

于 2012-10-30T00:25:07.710 に答える
1

レンダリングするクワッドの数だけではありません。あなたの場合、ビデオカードが必要とする三角形の量にもっと関係があると思います。

前述のように、フルスクリーンの後処理を行う一般的な方法は、シェーダーを使用することです。統合カードのパフォーマンスを向上させたいが、シェーダーを使用できない場合は、レンダリング ルーチンを簡素化する必要があります。

アルファブレンディングが本当に必要かどうかを確認してください。一部のカード/ドライバーでは、アルファ チャネルを使用してテクスチャをレンダリングすると、パフォーマンスが大幅に低下する可能性があります。

フルスクリーンの塗りつぶしの量を減らすやや低品質の方法は、最初にすべての影の描画を別の小さなテクスチャ (たとえば、1024x1024 ではなく 256x256) で実行することです。次に、その合成シャドウ テクスチャを使用してクワッドをバッファーに描画します。この方法では、7 つの 1024x1024 クワッドの代わりに、6 つの 256x256 と 1 つの 1024x1024 だけが必要になります。しかし、あなたは解像度に負けます。

別のテクニックは、あなたの場合に適用できるかどうかはわかりませんが、複雑な背景を事前にレンダリングすることです。これにより、レンダリング ループでの描画を減らす必要があります。

于 2012-10-30T03:05:19.857 に答える