Edited at

Unity で Windows の透過ウィンドウを作る(操作も透過)


はじめに

VTuber的な、3Dモデルと画面のキャプチャを統合する方法を考えたときに以下があると思う。※実際の方法・最適解は知らない

・ モデルと画面を別撮りして、編集で合成する方法

・ 画面のキャプチャとモデルを並列して表示するアプリケーション

そんな統合方法の内、先に画面へモデルを表示しようというコンセプトがこの記事。

この方法を使うと、モデルを表示するアプリケーションは独立しつつも、キャプチャ画面と同時にモデルをディスプレイに表示できる。


動作環境

WindowsAPIを使用しているので、Windows限定


確認環境

・Windows10

・Unity(2018.3.2f1)


使用例

こんなことができますよって

wa.gif

(前面にUnityのアプリケーションを実行しつつも、裏のUnityも操作できる。)


使用方法



  1. CameraClear FlagsSolid Colorにする


  2. CameraBackgroundを黒色にする


  3. TransparentWindow.csを適当なオブジェクトにアタッチする

※ソースコードは(TransparentWindow.cs)からダウンロード

※Unity Editor上での動作は把握していない(WindowsAPIを使用している)ので、EXE形式にビルドしてから実行する。


解説

詳しくは、MSDNを見れば解決!! ・・・ とはいかないかも?


GetActiveWindow


GetActiveWindow

IntPtr windowHandle = GetActiveWindow();


これから操作を行うウィンドウハンドルを取得する。


SetWindowLong


SetWindowLong

const int GWL_STYLE   = -16;

const int GWL_EXSTYLE = -20;
const uint WS_POPUP = 0x80000000;
const uint WS_EX_LAYERD = 0x080000;
const uint WS_EX_TRANSPARENT = 0x00000020;

SetWindowLong(windowHandle, GWL_STYLE, WS_POPUP);
SetWindowLong(windowHandle, GWL_EXSTYLE, WS_EX_LAYERD | WS_EX_TRANSPARENT);


変数名
意味合い

GWL_STYLE
ウィンドウスタイルの設定

GWL_EXSTYLE
ウィンドウ拡張スタイルの設定

WS_POPUP
ポップアップウィンドウにする

WS_EX_LAYERD
マウスイベントを貫通させる

WS_EX_TRANSPARENT
ウィンドウの裏にある画面の描画


SetWindowPos


SetWindowPos

IntPtr HWND_TOPMOST = new IntPtr(-1);

const uint SWP_NOSIZE = 0x0001;
const uint SWP_NOMOVE = 0x0002;
const uint SWP_NOACTIVE = 0x0010;
const uint SWP_SHOWWINDOW = 0x0040;

SetWindowPos(windowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVE | SWP_SHOWWINDOW);


HWND_TOPMOSTでウィンドウを最前面に表示し続けるように設定する。


DwmExtendFrameIntoClientArea


DwmExtendFrameIntoClientArea

MARGINS margins = new MARGINS()

{
cxLeftWidth = -1
};

DwmExtendFrameIntoClientArea(windowHandle, ref margins);


ウィンドウのフレームをクライアントエリアに拡張させる。

cxLeftWidth = -1の時はクライアントエリア全体に影響が及ぶ。


試した所感

上の説明はMSDNから概要(自己解釈)を取ってきただけで、実際にその通りに動く感じはなかった(少なくとも自分の環境では)。


ウィンドウのフレームを消し、透明にする

WS_POPUP + DwmExtendFrameIntoClientArea

ポップアップウィンドウで消えたフレームを、クライアントエリアに拡張するイメージ。

自分の場合、この設定でウィンドウを透明にできた。


ウィンドウのマウスイベントを透過する

WS_EX_LAYERD + WS_EX_TRANSPARENT

WS_EX_LAYERDだけでもよさそうだが、どちらも設定しないとマウスイベントをウィンドウが吸ってしまっていた。

マウスイベントを拾わないようになったのですぐに非アクティブになるが、非アクティブ時でも前面に表示するためにHWND_TOPMOSTを設定する。


おわりに

使用例こそショボいけど、制限は黒色を使えないだけなので、使い方次第ではデスクトップに常駐したゲームとか作れるかもしれないし、アイディア次第ではもっと面白いアプリケーションが作れるかもしれない。