5

これは私の最初の質問ですが、私は長い間潜んでいます。これを 2 つの部分に分けて説明します。1 つの部分では、私が何をしているのか、なぜこれが進むべき道だと思うのかを説明します。2 つ目は、自分では解決できない実際の問題です。

私は何をやっている? 私は現在、リアルタイムで表示されることを意図した 2 次元の機能をレンダリングするためのフレームワークを開発しています。ブラウザの Google マップのようなアプリケーションを考えることができますが、フレームワークはあらゆる種類の地理データをレンダリングすることを意図しています (Google タイルのような軸に沿ったラスター データだけではありません)。

このフレームワークは、デスクトップおよびラップトップ用の WPF アプリケーションである当社 (会社) の最新製品に統合される予定です。

したがって、実際にジオメトリのみをレンダリングするために WPF を選択しました。Visibility と Occlusion Culling は自分で行い、入力処理 (マウス ピッキング) やカメラの移動なども行っています。

リアルタイム アプリケーションであるため、少なくとも 30 FPS を達成する必要があります。このフレームワークは、画像をレンダリングするときに適切に機能します。フレームごとに数千のビットマップを問題なく描画できますが、ポリゴン データが大きな問題であることが判明しました。

WPFを使用して、特にDrawingContextとStreamGeometryを使用して、かなりの量のポリラインとポリゴンデータをレンダリングしている実際の質問。これまでの私の理解では、これがパフォーマンスが必要な場合の方法です。しかし、私はこれから期待した結果を達成することができません。

これは、StreamGeometry に実際のデータを入力する方法です。

using (StreamGeometryContext ctx = Geometry.Open())
{
        foreach (var segment in segments)
    {
        var first = ToWpf(segment[0]);
        ctx.BeginFigure(first, false, false);

        // Skip the first point, obviously
        List<Point> points = segment.Skip(1).Select(ToWpf).ToList();
        ctx.PolyLineTo(points, true, false);
    }
}
    Geometry.Freeze();

そして、これが私のジオメトリを描く方法です:

_dc.PushTransform(_mercatorToView);
_dc.DrawGeometry(null, _pen, polyline);
_dc.Pop();

テストとして、OpenStreetMap から ESRI シェイプをアプリケーションにロードしてパフォーマンスをテストしましたが、まったく満足できませんでした。テスト データは、合計 20,000 ラインの 3500 ライン セグメントで構成されています。

各セグメントを独自の StreamGeometry にマッピングするとパフォーマンスが非常に悪くなりますが、私はすでにそれを期待していました: レンダリングには約 14 秒かかります。

次に、複数の数値を使用して、より多くのセグメントを同じ StreamGeometry にパックしようとしました: 80 StreamGeometry、レンダリングには約 50 ミリ秒かかります。

しかし、これ以上の結果は得られません。行数を約 100k に増やすと、アプリケーションがほとんど使用できなくなります。レンダリングに 100 ミリ秒以上かかります。 ベクター データをレンダリングするときに、ジオメトリとペンの両方をフリーズする以外に何ができますか?

何かがひどく間違っているように見えるので、WPFに頼るよりも自分でDirectXを利用したいところです。

編集

私が何をしているのかをさらに明確にするために: アプリケーションは、地理データをリアルタイムで視覚化します。これは、ブラウザーの Google マップのようなアプリケーションと非常によく似ています: ただし、はるかに多くのデータを視覚化する必要があります。ご存知かもしれませんが、Google マップではズームとパンの両方が可能です。滑らかなアニメーションとして表示するには、25 FPS を超える必要があります。それ以下は流暢に感じません。

※申し訳ありませんが、実際の製品がリリースされる前に、このビデオをアップロードするべきではありません。ただし、大量のベクター データ (ポリゴンとポリライン) を使用する Google マップのようなものを想像することもできます。*

2 つの解決策があり、そのうちの 1 つが非常に頻繁に述べられています。

重い描画をビットマップにキャッシュする

実装はちょっと簡単に思えますが、このアプローチにはいくつかの問題があります。パンニングを適切に実装するには、フレームごとに重いものを描画しないようにする必要があるため、パンニング中にキャッシュされたビットマップを更新しないという選択肢が残されていますカメラ、またはビューポートよりもさらに大きな領域をカバーするビットマップを作成するため、キャッシュされたビットマップを頻繁に更新するだけで済みます。

2 番目の「問題」は、ズームに関連しています。ただし、これは実際の問題というより視覚的なアーティファクトです。キャッシュされたビットマップは 30 FPS で適切に更新できないため、ズームするときもそれを避ける必要があります。ズーム中にビットマップをスケーリングし、ズームが終了したときにのみ新しいビットマップを作成することはできますが、ポリラインの幅は一定の厚さではありませんが、そうする必要があります。

このアプローチは MapInfo で使用されているようですが、あまり気に入っているとは言えません。ただし、実装するのが最も簡単なようです。

ジオメトリを異なる描画ビジュアルに分割する

このアプローチは、問題への対処方法が異なるようです。このアプローチがまったく機能するかどうかはわかりません。この領域で WPF がどのように機能するかを正しく理解しているかどうかにかかっています。描画する必要があるすべてのものに対して 1 つの DrawingVisual を使用する代わりに、いくつかを使用して、すべてを RenderOpened() にする必要がないようにする必要があります。カメラのパンと移動の両方を反映するために、上記のサンプルのマトリックスなどのパラメーターを変更するだけで済みます。ただし、このアプローチにもいくつかの問題があります。カメラをパンすると、必然的に新しいジオメトリがビューポートに表示されるため、最初のアプローチと同様のことを実行する必要があります。実際には、現在表示されていないが表示される可能性があるものをレンダリングしますカメラがシフトしたため。

両方のアプローチに関連する 問題 これらのアプローチのどちらも解決できない大きな問題の 1 つは、全体的なフレームレートが安定している場合でも、キャッシュされたビットマップを更新するときに時折ヒックアップすることです (キャッシュされたビットマップがカメラがパンされなくなったときに更新される)、または RenderOpen を呼び出してジオメトリの可視チャンクを描画することは避けられないようです。

これまでの私の考え

これらは私がこれまでに見たこの問題に対する唯一の 2 つの解決策であるため (私は 1 年以上にわたってかなりの割合でグーグル検索を行ってきました)、これまでのところ唯一の解決策は、最も強力な GPU でさえフレームレートのヒックアップを受け入れることだと思います。 (1 秒あたり数億のプリミティブをラスタライズできるはずです)、ビューポートの更新の遅延 (ビューポートが移動されなくなったときにのみビットマップが更新される場合)、または WPF をまったく使用せずに DirectX に頼る直接。

お役に立ててとてもうれしいですが、これまでのところ、WPF のレンダリング パフォーマンスに感銘を受けたとは言えません。

4

1 に答える 1

2

2D WPFレンダリングのパフォーマンスを向上させるには、RenderTargetBitmap(WPF> = 3.5の場合)またはBitmapCacheクラス(WPF> = 4の場合)を確認できます。

これらのクラスはCached Composition

MSDNから:

新しいBitmapCacheクラスとBitmapCacheBrushクラスを使用することで、ビジュアルツリーの複雑な部分をビットマップとしてキャッシュし、レンダリング時間を大幅に改善できます。ビットマップは、マウスクリックなどのユーザー入力に応答し続け、他のブラシと同じように他の要素にペイントできます。

于 2013-02-11T08:06:05.337 に答える