はじめに
VTuber的な、3Dモデルと画面のキャプチャを統合する方法を考えたときに以下があると思う。※実際の方法・最適解は知らない
・ モデルと画面を別撮りして、編集で合成する方法
・ 画面のキャプチャとモデルを並列して表示するアプリケーション
そんな統合方法の内、先に画面へモデルを表示しようというコンセプトがこの記事。
この方法を使うと、モデルを表示するアプリケーションは独立しつつも、キャプチャ画面と同時にモデルをディスプレイに表示できる。
動作環境
WindowsAPIを使用しているので、Windows限定
確認環境
・Windows10
・Unity(2018.3.2f1)
使用例
こんなことができますよって
(前面にUnityのアプリケーションを実行しつつも、裏のUnityも操作できる。)
使用方法
- CameraのClear FlagsをSolid Colorにする
- CameraのBackgroundを黒色にする
TransparentWindow.csを適当なオブジェクトにアタッチする
※ソースコードは(TransparentWindow.cs)からダウンロード
※Unity Editor上での動作は把握していない(WindowsAPIを使用している)ので、EXE形式にビルドしてから実行する。
解説
詳しくは、MSDNを見れば解決!! ・・・ とはいかないかも?
GetActiveWindow
IntPtr windowHandle = GetActiveWindow();
これから操作を行うウィンドウハンドルを取得する。
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
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
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
を設定する。
おわりに
使用例こそショボいけど、制限は黒色を使えないだけなので、使い方次第ではデスクトップに常駐したゲームとか作れるかもしれないし、アイディア次第ではもっと面白いアプリケーションが作れるかもしれない。