2012-06-13 13 views
24

私は現在ゲームに取り組んでおり、私は背景イメージを持つメインメニューを持っていたいと思っています。大きな画像ではGraphics.DrawImageが遅すぎますか?

しかし、私はこの方法Graphics.DrawImage()は本当に遅い見つけます。私はある程度の測定をしました。 MenuBackgroundが解像度800 x 1200ピクセルの私のリソースイメージであると仮定しましょう。私は別の800 x 1200ビットマップに描画します(まず、すべてをバッファビットマップにレンダリングしてから、それをスケールして最終的に画面に描画します)。これが複数のプレーヤーの解像度の可能性にどう対処するのですか?それは決して次の段落を参照してください)。

だから私は、次のコードを測定しました:

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

// First let's render background image into original-sized bitmap: 

OriginalRenderGraphics.DrawImage(Properties.Resources.MenuBackground, 
    new Rectangle(0, 0, Globals.OriginalScreenWidth, Globals.OriginalScreenHeight)); 

SW.Stop(); 
System.Windows.Forms.MessageBox.Show(SW.ElapsedMilliseconds + " milliseconds"); 

結果は私には意外に静かである - Stopwatch対策40 - 50 millisecondsの間に何かを。また、背景画像だけが描画されるわけではないので、メニュー全体には約100ms以上の時間がかかります。これは、観測可能なラグを意味します。

私はPaintイベントによって与えられたGraphicsオブジェクトにそれを描くことを試みたが、結果は30 - 40 millisecondsだった - あまり変わっていません。

だから、それはGraphics.DrawImage()が大きく画像を描画するため使用不可能であることを、意味するのでしょうか?もしそうなら、私は自分のゲームのパフォーマンスを向上させるために何をすべきですか?

+1

「使用できない」とは、「糖蜜のカタツムリのようにゆっくり」を意味する場合は「はい」です。他の人が言っているように、XNAに試してみてください。 XNAフレームワークに慣れていないかぎり、2Dスプライトレンダリングに固執し、そうするなら3Dに向かって移動します。 – CodeHxr

+1

私はそれだけで類推のためにupvotingです。 :) – Ani

答えて

84

はい、遅すぎます。

Paint.NETを開発しながら、私は数年前にこの問題に遭遇した(実際には、最初から、それはかなりイライラさせられました!)。レンダリングのパフォーマンスは、ビットマップのサイズに常に比例し、再描画するよう指示された領域のサイズには比例していたため、非常に厳しいものでした。つまり、OnPaint()を実装しGraphics.DrawImage()を呼び出すときに、無効/再描画領域のサイズがダウンしたため、ビットマップのサイズが上がってフレームレートが上がり、フレームレートが上がることはありませんでした。小さなビットマップ、たとえば800x600は常に正常に動作しましたが、サイズが大きい画像(例:2400x1800)は非常に遅かったです。 (前の段落では、高価なバイキュービックフィルタでスケーリングしてパフォーマンスに悪影響を及ぼすなど、何も起こっていないことを前提とすることができます)。

WinFormsを強制的にGDI +を使用して、背後でGraphicsオブジェクトを作成することさえ回避します。その時点で、別のレンダリングツールキットをその上に重ねることができます(Direct2Dなど)。しかし、それは簡単ではありません。私はPaint.NETでこれを行い、ReflectorのようなクラスをSystemLayer DLLのGdiPaintControlという名前で使用することで何が必要なのかを知ることができますが、私は最後の手段と考えています。

ただし、使用しているビットマップサイズ(800x1200)は、300MHz Pentium II程度のものをターゲットにしていない限り、高度な相互運用性に頼らなくてもGDI +でも問題なく動作するはずです。ここで助けるかもしれないいくつかのヒントがあります:

  • をあなたはGraphics.DrawImage()への呼び出しで、不透明なビットマップ(アルファなし/透明度)を使用している場合は、それはアルファチャンネル付き32ビットのビットマップです特に場合(ただし、 の場合は不透明です。または気にしない場合)DrawImage()を呼び出す前にGraphics.CompositingModeCompositingMode.SourceCopyに設定してください(後で元の値に戻してください。そうしないと、通常の描画プリミティブは非常に醜いと見えます)。これにより、1ピクセルあたり多くの余分な混合計算がスキップされます。
  • Graphics.InterpolationModeInterpolationMode.HighQualityBicubicのように設定されていないことを確認してください。 NearestNeighborを使用すると最も速くなりますが、ストレッチがあると、(2倍、3倍、4倍などで伸びない限り)非常に良く見えません。Bilinearは通常は良い妥協点です。ビットマップサイズが描画対象の領域と一致する場合は、何も使用しないでください(ピクセル単位)。NearestNeighbor
  • OnPaint()にあるGraphicsオブジェクトに必ず描画します。
  • 常に図面をOnPaintで行ってください。領域を再描画する必要がある場合は、Invalidate()に電話してください。今描画が必要な場合は、Invalidate()の後にUpdate()に電話してください。これは、WM_PAINTメッセージ(OnPaint()への呼び出しをもたらす)が「優先度の低い」メッセージであるため、合理的なアプローチです。ウィンドウマネージャーによる他の処理が最初に実行されます。そうすれば、フレームスキップとヒッチングが頻繁に行われる可能性があります。
  • System.Windows.Forms.Timerをフレームレート/ティックタイマとして使用するとうまく動作しません。これらはWin32のSetTimerを使用して実装され、WM_TIMERメッセージが生成され、Timer.Tickイベントが生成され、WM_TIMERはメッセージキューが空の場合にのみ送信される別の低優先メッセージです。 System.Threading.Timerを使用し、Control.Invoke()を使用して(正しいスレッドを使用していることを確認してください)、Control.Update()を呼び出してください。
  • 通常、Control.CreateGraphics()を使用しないでください。 (必ず「OnPaint()に描画する」と「OnPaint()で常にGraphicsを使用してください」
  • Paintイベントハンドラを使用しないことをお勧めします。代わりに、Controlから派生するはずのクラスにOnPaint()を実装してください。別のクラスから派生します。 PictureBoxまたはUserControlは、値を追加しないか、オーバーヘッドを追加します。 (BTW PictureBoxはよく誤解されることがあります。おそらくそれを使用することはほとんどありません)。

希望に役立ちます。

+2

あなたはupvotes.For背景のグリッドを描画するトンのヒントはありますか? TextureBrushは速く見えますが、ズームファクタでカスタムスケーリングをしても機能しません。 – GorillaApe

+1

このポストの最適化は補間モードでした。 'Bilinear'を' NearestNeighbor'に変更すると、図面が8倍速くなりました。 – Pietu1998

+0

年後にも、あなたはwinformsで絵を描く人々を手助けしています – Nathan

3

GDI +は、おそらくゲームのための最良の選択ではありません。 DirectX/XNAまたはOpenGLは、どのようなグラフィックアクセラレーションが可能であっても非常に高速であるため、使用する必要があります。

3

GDI +任意の手段によって、スピード狂ではありません。あなたはXNA/DirectX/OpenGLを調べましたか?あなたはXNA/DirectX/OpenGLを調べましたか?あなたはXNA/DirectX/OpenGLを調べましたか?これらは、ゲーム開発用に設計されたフレームワークであり、WinFormsやWPFなどのUIフレームワークを使用するよりも効率的で柔軟性があります。ライブラリはすべてC#バインディングを提供します。

BitBltのような関数を使用してネイティブコードにインジェクトすることはできますが、マネージコード境界をまたぐオーバーヘッドがあります。

+0

OpenGL/DirectXもお勧めします。さまざまな理由から、XNAは実際には最良の選択肢ではありません。使いやすさ、はい - しかし、長期的にはそれはハンディキャップのビットです。 – Ani

+0

@ananthonline:そうです、言及する価値があります。 DirectXは、クロスプラットフォームサポートを気にしない場合、OpenGLよりも優れています。あなたはあなたのコメントを拡大することができますか? "長期的には[XNAは]ハンディキャップのビット" *です。私は深刻なゲーム開発者ではなく、私の趣味であるので、おそらく私の知るところにはいくつかの穴があります。 –

+0

XNAは、その使用にいくつかの前提を設けています。私が考えることができる深刻な限界の1つは、複数のレンダリングターゲットがデプスバッファを共有できないため、遅延レンダリングを効率的に実行することが不可能な一般的なシナリオを作成できることです。詳細はこちらをご覧ください(http://forums.create.msdn.com/forums/p/64179/397431.aspx) – Ani

関連する問題