2010年9月27日月曜日

Win32API、DirectXでウィンドウの背景を透過させる方法

Direct3D ウィンドウ背景の透明化
> 一般のウィンドウは背景を透明にすると、背後にあるウィンドウを見たり操作した
> りできます。これと同様に、Direct3D ウィンドウの背景を透明化することは可能で
> しょうか?
> また、どのようにすればよいのでしょうか?

その、「一般のウィンドウの背景を透明にする」方法とはなにですか?
背景を透明にするというのが、非矩形のウィンドウリージョンやLayered Windowを用いた矩形ではないウィンドウを描画することだと勝手に想像して以下書きます。

Direct3DDevice*::Present()がGDIの描画関数と完全に協調して動作するわけではないという理由から、若干の注意は必要ですが、普通はDirect3Dを用いる場合でも両手法はうまく動作します。

以下はその注意点。

・ウィンドウリージョンを指定する場合
Present()は、いわゆるフレームウィンドウに設定されているリージョンでしか
クリッピングを行いません。
つまり、Present先がWS_POPUPスタイルであるウィンドウの、WS_CHILDスタイル
である子孫ウインドウのひとつである場合は、WS_CHILDスタイルで作られた
ウィンドウに設定されているリージョンではクリップされず、WS_POPUPスタイル
である祖先ウィンドウのリージョンでだけクリップされます。
まぁ、WS_CHILDなウィンドウを非矩形にしたいがためにウィンドウリージョンを
指定することはほとんど無いと思うので普通は問題にならないでしょう。

・Layered Windowを用いる場合
SetLayeredWindowAttributes()によってGDIの描画結果をLayered Window用
バッファに迂回させる手法は使えません。Present()はこの迂回対象とならない
です。
Direct3Dでの描画結果をLayered Windowに表示する場合は、
UpdateLayeredWindow()によって行う必要があります。
既存のアプリケーションをLayered Window化するというような目的でもない
かぎり、性能やソースの書きやすさを考えてUpdateLayeredWindow()を
使うと思うので、こちらも普通はもんだいにならないでしょう。
ここで言及されているレイヤードウィンドウについては●Win32API(C言語)編 第60章 ウィンドウの操作①の[○半透明ウィンドウ]項目に載っている。
CreateWindowExの第一引数にWS_EX_LAYEREDを指定して
SetLayeredWindowAttributes(hWnd, 50, 50, LWA_ALPHA);
とでもしてやれば半透明のウィンドウを作ること自体はできるのだが、これだとウィンドウの特定の部分だけを透過させることなどができない。
部分的な透過をするには半通過ウィンドウの作り方講座が参考になる。