ドット描画を高速化するには?

解決


ウデ  2011-01-27 14:57:07  No: 72271  IP: [192.*.*.*]

環境:VC2003 MFC

数万点以上ある点群のドット描画しているのですが
100万点以上になると描画が遅く改善を求められています。

どんな拡大率であろうと必ず1ドットで描画するため
OnPaintで点群数分ループさせて描画させています。

ドット描画はSetPixelVではなくPolyPolylineを使ってます。

OnPaintでの点群数分ループをやめようと、別途ビットマップ(DIB)を作成して描画しようと試みましたがOnPaintでビットマップを拡大縮小(StretchBlt)させることになるので1ドット表現ができなくなります。

何か高速化できる手段はありますでしょうか?
よろしくお願い致します。

編集 削除
maru  2011-01-27 17:28:32  No: 72272  IP: [192.*.*.*]

特にアイディアは無いんですが...
どの程度の性能を求めていらっしゃるのでしょうか?
100万回の処理は1マイクロ秒の処理でも1秒かかりますよ。PCの性能にもよるでしょうが、1マイクロ秒でできることはたかが知れているかと。

> ビットマップを拡大縮小(StretchBlt)させることになるので1ドット表現ができなくなります。
ここの意味がよく分からないのですが、説明していただけますか?

編集 削除
ryo  2011-01-27 18:40:47  No: 72273  IP: [192.*.*.*]

たぶん、
100%の倍率で「別途ビットマップ(DIB)」を最初に"一度書いたきり"、
StretchBltでずっと使いまわすため、
拡大・縮小時に、1ドットで書いたものが、でっかい点になったり
つぶれたりするんでしょう。

もし、そうなら
「別途ビットマップ(DIB)」に書くのを、拡大縮小のたびに
そのサイズで作り直せばいいだけだと思う

編集 削除
オショウ  2011-01-27 18:50:03  No: 72274  IP: [192.*.*.*]

私は3Dも含め、1億ポイントのデータ点描画をやりましたが
WM_PAINTで直接やったら、それは終わりますね!

メモリデバイスコンテキストを作って、メモリ上に描画し、あ
るタイミングでそのメモリデバイスコンテキスト上から画面上
へBitBlt(StretchBlt)させるとか・・・

マルチスレッドにしないと、できませんネ!

※  ダブルバッファリング的手法になるかな・・・

以上。参考まで

編集 削除
fuku  2011-01-28 03:09:35  No: 72275  IP: [192.*.*.*]

最近DirectXSDKから外されて使いづらくなったみたいですがDirectDrawとかで
ビットマップの直ポインタとってそこに直接書き込んでやれば
100万ピクセル程度の描画なら30FPSぐらいは狙えるかと思います。
#プライマリサーフェスをロックするとWindows7とかでAeroが切れるようなので
#手元にサーフェス作って転送した方がいいみたいです

編集 削除
ウデ  2011-01-28 09:43:24  No: 72276  IP: [192.*.*.*]

返信遅れましてすみません。

> ビットマップを拡大縮小(StretchBlt)させることになるので1ドット表現ができなくなります。

はryoさんの言っていることがズバリです。
なので現状はビットマップを保持せずOnPaintで作り直してます。
一応、裏画面に描画してからBitBltしています。

拡大縮小時に作り直す方法も考えたのですが
欲を言えば移動と拡大縮小は同等の速度を出したいです。

編集 削除
ryo  2011-01-28 12:22:07  No: 72277  IP: [192.*.*.*]

DirectXやらOpenGLを使いましょう

編集 削除
きのこ  2011-01-28 22:03:05  No: 72278  IP: [192.*.*.*]

その裏画面というのはクライアント領域と同じ大きさの
DDBビットマップ(HBITMAP)ですか?
この裏画面を32bitのDIBもしくはDIBSectionで作成して
GDIを使わずに直接色情報をDWORDで書き込む方法で少し速度が稼げるかも。

それと、SetPixelVではなくPolyPolylineを使う理由が良く分からないです。
何か特別な理由があるんでしょうか?

>拡大縮小時に作り直す方法も考えたのですが
>欲を言えば移動と拡大縮小は同等の速度を出したいです。

リソースもしくはメモリ消費に無駄がでますが、
ウィンドウ幅の拡大縮小時に裏画面を再生成したくないのなら、
あらかじめデスクトップと同じ大きさで裏画面を作っておいて、
そのうち、クライアント領域と同じ大きさの部分のみ使用する
(描画やBitBlt時、その範囲だけ使用する)というのはどうでしょうか。

編集 削除
たまにここを見る人  2011-01-28 22:10:49  No: 72279  IP: [192.*.*.*]

>100万点以上になると描画が遅く改善を求められています。
との事ですがその 100万点分の座標はほぼ一瞬で求まっていると考えてよいのでしょうか?

つまり
>OnPaintで点群数分ループさせて描画させています。
とのことですのでその都度 演算(座標決定)→描画を繰り返していると思うのですが
例えば OnPaintから点の描画コードをコメントアウトすれば OnPaintはほぼ一瞬で抜けてますか?

編集 削除
ウデ  2011-01-31 10:16:30  No: 72280  IP: [192.*.*.*]

たびたび返信遅れまして申し訳ありません。

>DirectXやらOpenGLを使いましょう

OpenGLのディスプレイリストで高速化できることがわかりました。
少し試してみましたが、背景が必ず塗りつぶされてしまいます。
塗りつぶさない方法ってありますでしょうか?
「要素①->点群->要素②」
と描画して行くのですが要素①が消えてしまいます。
諸事情により要素①はOpenGLで描画することはできません。


>GDIを使わずに直接色情報をDWORDで書き込む方法で少し速度が稼げるかも。

この方法を試させて頂きました。
かなり速度は向上しました。


>それと、SetPixelVではなくPolyPolylineを使う理由が良く分からないです。

SetPixelVよりもPolyPolylineで点を描画した方が速かったので
こちらを使用していました。


>あらかじめデスクトップと同じ大きさで裏画面を作っておいて

拡大縮小でスケールが変わるのでBitBltでは表現できないと思います。


>100万点分の座標はほぼ一瞬で求まっていると考えてよいのでしょうか?
>点の描画コードをコメントアウトすれば OnPaintはほぼ一瞬で抜けてますか?

座標計算は一瞬で求まっています。

編集 削除
きのこ  2011-02-01 00:33:28  No: 72281  IP: [192.*.*.*]

>SetPixelVよりもPolyPolylineで点を描画した方が速かったので

なるほど比較した上で速かったわけですね。納得しました。

>拡大縮小でスケールが変わるのでBitBltでは表現できないと思います。

BitBltは引数の座標や大きさ指定を工夫すれば、画像の一部だけを
転送することが可能ですよね? 大きな裏画面のうち、その時必要な
大きさ分のみ使用(描画)し、使用した範囲をBitBltで切り取るなら
>拡大縮小時に作り直す方法
の作り直すコストを省く代替手段になるかなと思ったのです。
(思いつきだったので、無理そうならスルーしてください)

拡大縮小をした際に、StretchBltを使用して1ドットが表現できなくなる
問題を解決する為、一度「拡大縮小時に作り直す方法」を試してみて、
速度がどの程度でるのか(ロスするのか)を確認してみてはいかがでしょうか。

編集 削除
仲澤@失業者  2011-02-02 11:40:08  No: 72282  IP: [192.*.*.*]

まだ、ふれられていない手法としては、DIBセクションを使用して
そのビットマップデータを直接いじるという方法もありますね。

編集 削除
ロマ  2011-02-02 21:04:40  No: 72283  IP: [192.*.*.*]

私の所の貧弱なビデオカードで試してみました(1000*1000点)
WM_PAINTでSetPixelする --> 3800[ms]
DDBにSetPixelする --> 830[ms]
DibSectionにSetPixelする --> 440[ms]
DibSectionに直接書き込む --> 20[ms]
* いずれもピクセルを書き込む時間のみ計測しました。

皆さんが書いているビットマップは
ウデさんの思っているビットマップと違い、
クライアント領域と同じ大きさのビットマップ、
言い換えれば、見えている部分のみのビットマップのことです。

ズーム時は、ビットマップを書き直します。
WM_PAINTハンドラはビットマップ全体をBitBltするだけです。

編集 削除
ロマ  2011-02-02 21:37:38  No: 72284  IP: [192.*.*.*]

> 皆さんが書いているビットマップは
> ウデさんの思っているビットマップと違い、
> クライアント領域と同じ大きさのビットマップ、
> 言い換えれば、見えている部分のみのビットマップのことです。

> ズーム時は、ビットマップを書き直します。
> WM_PAINTハンドラはビットマップ全体をBitBltするだけです。

すみません、この部分取り消します。
ウデさんは、OnPaintで裏画面をBitBltしていましたね。

編集 削除
ウデ  2011-02-03 13:13:22  No: 72285  IP: [192.*.*.*]

ロマさん、チェックありがとうございます。

>DibSectionに直接書き込む

今回はこの方法で落ち着こうと思います。
試した中でOpenGLを利用するのが一番早いのがわかりましたが
理解が曖昧の中でOpenGLを利用するのは危険かと思い断念しました。
また時間がある時にでもチャレンジしてみたいと思います。

皆様色々とアドバイスありがとうございました。

編集 削除