2016-05-22 3 views
0

概要現在、キャンバス領域にクリッピングを適用する方法をどのように改善できますか?

私は、この場合TPaintBoxキャンバスには、キャンバスにグラフィックスの多くを描画する必要があります。 paintboxはTScrollBoxの子であり、paintboxのサイズは高さと幅が非常に大きくなる可能性があります(例:5000x5000)。

私は自分自身のオブジェクトを保持するTListを持っています。各オブジェクトには独自のXプロパティとYプロパティと独自のグラフィックがあります。ペイントボックスのOnPaintメソッドでは、リスト内の各オブジェクトを反復処理し、オブジェクトXとYの位置に格納されている座標でペイントボックスキャンバスに各オブジェクトのグラフィックを描画します。

これをすべて描画するとアプリケーションが遅くなり、非常に重くなるので、これを最適化する方法が必要でした。

明白なやり方は、CPUではなくGPUを何とか利用することですが、それははるかに複雑です.Firemonkeyは助けになるかもしれませんが、FMXではなくVCLタイプのプロジェクトで厳密に実行しています。

考えられる解決策?

私はCreateRectRgnに遭遇し、正しく理解していれば、スクロールボックスの可視領域などのペイントボックスにペイントボックスをペイントできれば、パフォーマンスが大幅に向上するはずだと考えました。私が最初に仮定し、何よりも私がペイントボックスキャンバスにペイントかをどのように最適化するための、これはでも良い方法かどうかである

procedure TForm1.PaintBox1Paint(Sender: TObject);  
var 
    MyRgn: HRGN; 
begin 
    // iterate and draw objects onto FBuffer (offscreen bitmap) first, 
    // note: FBuffer size is the same as the scrollboxes clientwidth 
    // and clientheight 
    //begin 
    // ... 
    //end; 

    // create and paint on a region (visible area of the scrollbox) on 
    // the paintbox rather than painting the whole paintbox. 
    MyRgn := CreateRectRgn(0, 0, ScrollBox1.ClientWidth, ScrollBox1.ClientHeight); 
    try 
    SelectClipRgn(PaintBox1.Canvas.Handle, MyRgn); 
    PaintBox1.Canvas.Draw(ScrollBox1.HorzScrollBar.Position, 
     ScrollBox1.VertScrollBar.Position, FBuffer); 
    SelectClipRgn(PaintBox1.Canvas.Handle, HRGN(nil)); 
finally 
    DeleteObject(MyRgn); 
end; 

質問

:だから、このことを念頭に置いて、私はの線に沿って何かを試してみました他にどのようなオプションがありますか?私が行うメモの唯一の他の事は、各オブジェクトのXとYをチェックすることです。スクロールボックスの可視領域の外にあれば、私はそれをペイントしません。

私はまだクリッピング領域を作成するという考えに慣れていますが、上記のコードサンプルは間違っています。私は、特にペイント方法の中で、地域を絶えず作成し、削除するという考えが嫌いです。

私のプロジェクトはかなり大きくなっていますが、実際にはこれをカスタムコントロールに入れていますが、何百ものオブジェクトを処理してペイントボックスキャンバスにペイントすると徐々に減速し、私がクリッピング領域を正しく実装していないか、あるいは私が常時作成している方法で、OnPaintメソッドから領域を描画してから削除してください。

これを実現するためのより現実的な方法がありますか?おそらく、フォーム作成時にリージョンを作成し、フォームdestroy(またはカスタムコントロールのコンストラクタ/デストラクタから)で破棄することは可能でしょうか?しかし、フォームやコントロールのサイズを変更した場合、どのようにクリッピング領域のサイズを変更するのですか?

私は本当にいくつかのアドバイスを使用して、私がより良いやり方をすることができるかもしれないことを理解するのを助けるために直面​​しているこの問題にいくつかの明快さを得ることができます。

ありがとうございました。

+2

GraphicControl(PaintBox)は、その親(ScrollBox)に対して取得されたDCで動作します。つまり、ペイントは既にスクロールボックスのクライアント領域にクリップされています。詳細は 'TWinControl.PaintControls'を参照してください。 –

+0

@SertacAkyuzうわー私は決してそれを知らなかった。その場合、私は自分自身のクリッピング領域を追加しようとする前に、それがもっと遅くなったと確信しているので、絵を最適化する別の方法を見つける必要があります。これに関係なく、私は実際にペイントボックスの親が私のためにこれを行うかどうかに関係なく、クリッピング領域を正しく設定していたかどうかにかかわらず、この疑問と疑問が残ります。私の仕事はより良い方法でアプローチできると確信していますが、途中で間違いを覚えたり修正したりするのはいつでも歓迎します。 – Craig

+0

@SertacAkyuzまた、私が実際にカスタムコントロールにすべてを入れたら、スクロールボックスにキャンバスをパブリッシュして直接ペイントして、子ペイントボックスを使うのではなく、また、スクロールボックスキャンバスのクリッピング領域が必要ですか? – Craig

答えて

2

コードサンプルとそのコメントに基づいて、すべてのオブジェクトを最初にオフスクリーンのビットマップに描画しているようです。

この場合、クリップ領域を使用するか使用しないかは、すべてのオブジェクトをオフスクリーンビットマップに描画するコードにボトルネックがあるため、大きな違いはありません。

コードを最適化する最適なソリューションは、可視領域にあるオブジェクトのみを描画することです。

ここであなたの主な質問は、あなたのオブジェクトのどれが見えているのかわからないのかを判断する最良の方法でなければなりません。

あなたのコメントで、地図のようなコントロールを作っていると言いました。あなたのマップを複数のセクターで構成されるグリッドに分割し、オブジェクトの位置に基づいて各セクターのオブジェクトデータを保存するのが最善の方法だと思います。各セクターは別々のTListになります。

これにより、表示されるセクタに基づいて少数のオブジェクトを反復処理するだけで、パフォーマンスをかなり向上させることができます。

これらのセクタのサイズは、オブジェクトの共通サイズによって異なります。

また、どのセクタを常に描画するかを決定するときは、表示領域を少し超えて描画するようにしてください。そのため、位置がセクタの境界線を越え、部分的にしか見えないオブジェクトも描画されます。あなたのオブジェクトの次元のどれもが個々のセクターのサイズを超えていない場合は、すべての目に見えるセクターと1行または1行を外側に描くだけで十分です。

+0

これは実行可能な解決策ですが、オブジェクトが表示されているかどうかに関わらずオブジェクトに応答させます。 – NGLN

+0

@ NGLN各オブジェクトを表示するかどうかを問い合わせるのは、オブジェクトの数が少ない場合にのみ実行可能です。しかし、あなたがそれらの多くを持っている場合は、それぞれの "尋ねる"ボトルネックになることができます。私の提案するアプローチの主な利点は、各オブジェクトに可視かどうかを「問いただす」必要はなく、特定のセクタが表示されているかどうかをチェックするだけで、セクタの一部のみが表示されるため、可視範囲にある。しかし、それは各オブジェクトのイテレーションと可視性を確認するよりもはるかに速くなる可能性があります... – SilverWarior

+0

..それを信じていても大丈夫ですが、大きなゲームマップを持つほとんどのコンピュータゲームは、オブジェクトがメモリに格納されたり、処理されたりする必要がある場合もあります。そして、ゲーム開発者として、私はこれを最初から手にして確認することができます。 – SilverWarior

関連する問題