ビットマップのマルチバッファリング

概要:チラツキを抑制する

ゲームのような高速に描画するアプリケーションでは、チラツキが大きな問題になります。
それを抑制する手法がマルチバッファリングです。

■チラツキの原因

チラツキが発生する原因は二つあります。

○更新領域の背景を消去してから再描画させた

背景の消去によりウィンドウ本来の背景色(WNDCLASS のhbrBackground)が
一瞬だけ見えてしまうからです。

○一つの完成した画像を作るために、表画面に何度も描画した

表画面への描画はその都度表示されるので、
一つの完成した画像を作る過程が見えてしまうからです。

例えば、背景画像を描画してから、
その上に素材となる画像を描画する事を考えてみましょう。
更新領域の背景を消去しないで上書きさせたとしても、
背景画像だけが描画された状態、
そしてその上に素材画像が描画された状態のそれぞれが、ユーザーに一瞬だけでも見えてしまいます。
これがチラツキの原因になります。

■マルチバッファリング

マルチバッファリングなんて言われると難しく感じるかもしれませんが、
ビットマップを作ったことがある貴方なら簡単です。
以下にマルチバッファリングの考え方を示します。

完成状態を作る画像(裏画面)を用意して、
全ての描画はこの完成画像に対して行います。
そして全ての描画が終わったら、完成画像を表画面に転送します。


裏画面はそのままでは表示されないので、描画の過程は見えないというわけです。
このように複数枚の画像を用意して、段階を踏んで表示させる手法を
ビットマップのマルチバッファリングと言います。

ただし、マルチバッファリングだけではチラツキが発生してしまうので、
更新領域の背景を消去しないで上書きさせるようにしなくてはなりません。
これはマルチバッファリングの手法には含まれませんが、必ずと言っていいほどそうします。
以前の内容を消去しないという事は、
以前の内容を覆い隠すだけサイズを持った任意の背景画像で
塗りつぶす必要がある事に注意して下さい。
以前の内容が表示されては不都合だからです。
背景を消去する代わりに塗りつぶす事で以前の内容を消去しているのですね。

以上の事をまとめると、完成画像に全ての描画を行い、
たった一度の表画面への転送(上書き)によりチラツキを抑制できる。


■裏画面作成

完成画像のビットマップ形式は何でも構いませんが、
文字列の描画にGDI関数が必要なので、DDB か DIBSection を使うのが一般的です。
ここでは作成が一番簡単な DDB にしましょう。

//メモリデバイスコンテキストを作る
hdc=GetDC(hWnd);
hBitmap=CreateCompatibleBitmap(hdc,WIDTH,HEIGHT);
hMemDC=CreateCompatibleDC(hdc);
ReleaseDC(hWnd,hdc);
SelectObject(hMemDC,hBitmap);
DeleteObject(hBitmap);

■タイマー作成

高速に再描画してもチラツキが発生しないという事を示すために、
10ms間隔で再描画させてみましょう。
この速さは古いマシンなら処理限界を超えるほどです。
その時はもっと遅くしても構いません。
一般のゲームなら50ms間隔(毎秒20フレーム)くらいで十分です。

SetTimer(hWnd,1,10,NULL);    //無駄に高速に再描画させる

■タイマー処理

再描画メッセージを発行するだけです。

//再描画させる
InvalidateRect(hWnd,NULL,FALSE);    //背景を消去しない
                                    //(背景を消去するとちらつく)

ただし、更新領域の背景を消去せず上書きさせるようにします。

■描画と転送

裏画面に完成画像を作り、それを表画面に一度だけ転送します。
今回は背景画像や素材画像のつもりで四角形を描画しています。

//背景画像のつもり
SelectObject(hMemDC,GetStockObject(BLACK_BRUSH));
Rectangle(hMemDC,0,0,WIDTH,HEIGHT);
//素材画像のつもり
SelectObject(hMemDC,GetStockObject(WHITE_BRUSH));
Rectangle(hMemDC, 10,10, 40,40);
Rectangle(hMemDC,110,10,140,40);
SelectObject(hMemDC,GetStockObject(GRAY_BRUSH));
Rectangle(hMemDC, 60,60, 90,90);
Rectangle(hMemDC,160,60,190,90);

hdc=BeginPaint(hWnd,&ps);
//表画面へ転送
BitBlt(hdc,0,0,WIDTH,HEIGHT,hMemDC,0,0,SRCCOPY);
EndPaint(hWnd,&ps);

■チラツキを発生させる

故意にチラツキを発生させる実験をしてみましょう。

上記プログラムの InvalidateRect 関数の第三引数を TRUE にしてみて下さい。
更新領域の背景を消去させる指示ですが、
マルチバッファリングを使っているのにチラツキが発生してしまいます。

それでは、更新領域の背景は消去せず上書きさせるようにして、
マルチバッファリングを使わなかったらどうでしょうか?
やっぱりチラツキが発生します。

もちろん、更新領域の背景を消去して、マルチバッファリングさえも使わなければ
酷いチラツキが発生して見れたものではありません。

■マルチバッファリングは必ずしも必要ではない

マルチバッファリングは静的なオフィスアプリケーション等では必ずしも必要ではない技術です。
処理速度を重視するなら多少のチラツキは無視しても構わないでしょう。
プログラムが簡単になる事でバグの発生も軽減できるかもしれません。
でもゲームには必須です。
どんな些細なチラツキでも、大切な一瞬を見逃す事になるからです。
他人に見せても恥ずかしくない、
ちゃんとしたゲームを作りたいならチラツキ対策は万全にしなければなりません。

★☆ ソースファイル表示 ☆★


戻る / ホーム