UE4でウィンドウキャプチャーできるプラグイン(WindowCapture2D)をマーケットプレイスに公開しました

WindowCapture2Dとは Unreal Engineで使えるWindow Captureのプラグインです。 Windowsの他のアプリケーションのWindowの表示を、自分のUE4プロジェクトのテクスチャとして扱うことができるようになります。 そのためメッシュに張り付けて3D空間に配置したり、UMG上のImageに張り付けることなんかができるようになります。 リアルタイムにスキャンしてテクスチャの中身を更新しているので、キャプチャー元のWindowの表示が更新されればテクスチャの表示も更新されます。 UE4のMedia PlayerとMedia Textureを使って動画を表示するのに近い使い勝手かと思います。 ブループリントOnlyのプロジェクトでも使用可能です。 詳しくは以前の記事を参照してください。 なぜ作ることにしたのか等書いています。 UE4でウィンドウキャプチャー機能を作ってみた - AYU MAX UE4 マーケットプレイス 以下のページにて公開しています。 WindowCapture2D:ayumax:Code Plugins - UE4 マーケットプレイス 価格はFreeです。 Engineのバージョンには4.22に対応しています。(近いうちに4.20と4.21にも対応させます) また、ソース一式も以下のGitHubにてMITライセンスで公開しています。 現状の機能とこれから 今(2019/7)のところウィンドウのキャプチャーのみ行えます。 今後はこれに操作機能(VRコントローラーなどでキャプチャーしたウィンドウを操作)を作ろうと考えています。 その他、今よりもパフォーマンスの改善や使い勝手の改善なども行っていく予定です。 特にキャプチャー対象のウィンドウの解像度が上がっていくと、処理負荷が高くなっていくのでその当たりが一番の課題かなと思っています。 こんな機能を追加してほしいなどのご要望ありましたら教えてください。

2019-07-07 · 1 分 · 34 文字 · ayumax

UE4 10km以上遠くにActorを移動すると破壊される件

UE4のWorldの大きさ問題 最近作ってたコンテンツでおきた問題をメモしておきます。 そのコンテンツはWheeledVehicleを使って車を走らせていたのですが、最近走るエリアを大幅に広げてみました。 それでちゃんと動くかテストしたところ、10kmを超えたあたりで車が消滅してしまいました。。。。 エリアが広すぎるせいで処理が重くなったりするかなあという不安はもっていたのですが、急に車が消滅するのは想像していませんでした。 そこで色々調べたところ原因と解決策が分かりました。 WorldSettingsのEnable World Bounds Checks まず簡単にこの件を解決する方法としては、WorldSettingsのEnable World Bounds ChecksをOFFにすることです。 (色々検索しててみつけたのですが、元のページが見つからなくなってしまった。。。) この項目をOFFにするとたしかに10kmを超えても車は消滅しません。 なぜなのか?この項目は何に効いているのか?と疑問がでたのでもう少し調べてみました。 Editorでこの項目にマウスを合わせると以下の画像のようにツールチップがでます。 ん?CheckStillInWorldってなんだ?と思ってEngineのソースを検索してみると、AActor::CheckStillInWorld‘という関数が見つかりました。これは怪しい。 bool AActor::CheckStillInWorld() { if (IsPendingKill()) { return false; } UWorld* MyWorld = GetWorld(); if (!MyWorld) { return false; } // Only authority or non-networked actors should be destroyed, otherwise misprediction can destroy something the server is intending to keep alive. if (!(HasAuthority() || Role == ROLE_None)) { return true; } // check the variations of KillZ AWorldSettings* WorldSettings = MyWorld->GetWorldSettings( true ); if (!WorldSettings->bEnableWorldBoundsChecks) { return true; } if( GetActorLocation().Z < WorldSettings->KillZ ) { UDamageType const* const DmgType = WorldSettings->KillZDamageType ? WorldSettings->KillZDamageType->GetDefaultObject<UDamageType>() : GetDefault<UDamageType>(); FellOutOfWorld(*DmgType); return false; } // Check if box has poked outside the world else if( ( RootComponent != nullptr ) && ( GetRootComponent()->IsRegistered() == true ) ) { const FBox& Box = GetRootComponent()->Bounds.GetBox(); if( Box.Min.X < -HALF_WORLD_MAX || Box.Max.X > HALF_WORLD_MAX || Box.Min.Y < -HALF_WORLD_MAX || Box.Max.Y > HALF_WORLD_MAX || Box.Min.Z < -HALF_WORLD_MAX || Box.Max.Z > HALF_WORLD_MAX ) { UE_LOG(LogActor, Warning, TEXT("%s is outside the world bounds!"), *GetName()); OutsideWorldBounds(); // not safe to use physics or collision at this point SetActorEnableCollision(false); DisableComponentsSimulatePhysics(); return false; } } return true; } 関数の一番最後に答えが書いてありました。 ...

2019-07-03 · 2 分 · 268 文字 · ayumax

ObjectDeliverer Ver 1.2.1リリース UDPReceiverの不具合修正

ObjectDelivererのVersion 1.2.1をリリース 今回はユーザーの方よりご指摘いただいた以下の不具合を修正しました。 UDPReceiverで既に使われているポートを指定するとEditorがクラッシュする InnerSocket = FUdpSocketBuilder(TEXT("ObjectDeliverer UdpSocket")) .WithReceiveBufferSize(1024 * 1024) .BoundToPort(BoundPort) .Build(); Receiver = new FUdpSocketReceiver(InnerSocket, FTimespan::FromMilliseconds(10), TEXT("UProtocolUdpSocketReceiver")); Receiver->OnDataReceived().BindUObject(this, &UProtocolUdpSocketReceiver::UdpReceivedCallback); Receiver->Start(); if (InnerSocket) { DispatchConnected(this); } 上記が修正前のソースです。 BoundPortに既に使われているポート番号が指定されると、InnerSocketにはnullptrが入るためその後FUdpSocketReceiverを生成したタイミングでクラッシュしていました。 今回はこれを単純ですが以下のように修正しました。 InnerSocket = FUdpSocketBuilder(TEXT("ObjectDeliverer UdpSocket")) .WithReceiveBufferSize(1024 * 1024) .BoundToPort(BoundPort) .Build(); if (InnerSocket) { Receiver = new FUdpSocketReceiver(InnerSocket, FTimespan::FromMilliseconds(10), TEXT("UProtocolUdpSocketReceiver")); Receiver->OnDataReceived().BindUObject(this, &UProtocolUdpSocketReceiver::UdpReceivedCallback); Receiver->Start(); DispatchConnected(this); } これでFUdpSocketBuilderでの初期化に失敗した場合でも、クラッシュすることはなくなりました。 この不具合を見つけて、同じような仕組みのTCP/IP Serverは大丈夫かと思いましたが、そちらはガードが既にかかっており大丈夫でした。 単純なミスをやらかしてしまい、お恥ずかしいです。

2019-06-25 · 1 分 · 57 文字 · ayumax

UE4 WindowCapture機能をUMG対応しました

UMG対応 先日GitHubに公開しましたUE4向けのウィンドウキャプチャープラグインのWindowCapture2DにUMG対応を実施しました。 {{< x user=“ayuma_x” id=“1141689312255172608” >}} これで3D空間だけでなく、ウィンドウ内の固定位置にキャプチャー画像の貼り付けが可能になります。 使い方 UserWidgetに"WindowCaptureUMG"を配置します。 それだけです。 WindowCaptureUMGに設定するプロパティはActor版のWindowCapturePlaneと同じものになるため、ActorでもWidgetでも同じ設定方法で使えます。 Editor Widgetへの応用 応用としてEditorWidgetにも使えます。 ただし、現状EditorWidgetに使用するとコンパイルボタンを押したときに起こる終了→再初期化の処理が通常のUMGとは異なるせいでクラッシュしてしまいます。。。 現在直し方を調整中です。 ※ どうやらEditorWidgetを起動中にコンパイルすると落ちてしまうようです。一度EditorWidgetのウィンドウを閉じてからコンパイルすると落ちないことを確認しました。(2019/6/22) {{< x user=“ayuma_x” id=“1142066827872239617” >}} {{< x user=“ayuma_x” id=“1142074587980554240” >}}

2019-06-22 · 1 分 · 29 文字 · ayumax

UE4でウィンドウキャプチャー機能を作ってみた

WindowCapture2D 今回UnrealEngineで使えるウィンドウキャプチャープラグインをGitHub上に公開しました。 今はGitHubでのみ公開していますが、もう少し機能がまとまり次第マーケットプレイスにも出そうと思っています。 WindowCaptureへの思い ある時にVRコンテンツをUE4でWindows上のアプリケーションをVR空間に表示したくて色々調べてたのですが、中々ダイレクトでマッチする機能は探せず。 当時はそんなに時間もなかったのでUE4で実現するのをあきらめていました。 そんな中ネットを見ているとUnityならドンピシャの機能を作られている方がいて、試してみると普通にやりたい事ができてしまい感動した記憶があります。 Unity で Windows のデスクトップ画面をテクスチャとして表示するプラグインを作ってみた - 凹みTips 凄い凄いと思いながら、Unityでも実現できてるんだからUnrealでも作れるんじゃないだろうかと思い、トライしてみたのが始まりです。 Windowをキャプチャーする 私は25歳の時に今で言う「未経験からエンジニア」で転職したのですが、その時最初にやった業務がWindows上でのウィンドウキャプチャーでした。 C++, MFCで戦っていたのですが、当時はHDC? HWND?何それ?メモリDCってなに?って感じだったのを覚えています。 そのためウィンドウをキャプチャーするという技術には特別な思いがあります。 キャプチャー方法 私の知っているウィンドウキャプチャー方法は以下の2つです。 WindowのDCを取得してBitBlt WindowのDCを取得してPrintWindow 速度的にはBitBltの方がPrintWindowよりも早くて良いのですが、ChromeやUE4で作ったアプリケーションなどはBitBltではキャプチャーできません。 Windowを直接キャプチャーするのではなく、デスクトップのDCからキャプチャーして必要な領域をトリミングすると、どんなウィンドウでもキャプチャーできるのですが、 キャプチャーするのにディスプレイモニターのリフレッシュレート分待たされてしまう問題や、重なったウィンドウの背面側はキャプチャーできない等問題も数多くありました。 もう一つのPrintWindowも当初はChromeのキャプチャーはできないと思っていたのですが、Microsoftのヘルプに載っていない引数(PW_RENDERFULLCONTENT=2)を与えるとキャプチャーできるようになる発見がありました。 そこで今回はPrintWindowで作ってみる事にしました。 (その他にDirectXを使ってウィンドウキャプチャーする方法もあるそうですが、これはまだ試していません) UE4での実装 とりあえずTickの中でターゲットのウィンドウをキャプチャーしてテクスチャの中身を書き換えてみました。 テクスチャー(UTexture2D)の書き換えは以下のコードで実現できます。 auto Region = new FUpdateTextureRegion2D(0, 0, 0, 0, TextureTarget->GetSizeX(), TextureTarget->GetSizeY()); TextureTarget->UpdateTextureRegions(0, 1, Region, 4 * TextureTarget->GetSizeX(), 4, (uint8*)m_BitmapBuffer); TextureTargetがターゲットとなるTexture2Dで、 m_BitmapBufferはBGRA形式のピクセルバッファです。 この2行で動的にテクスチャーの書き換えができます。 実行するとうまくいったかのように見えたのですが、対象のウィンドウのサイズが大きくなるとカクツキが酷くなってしまい困りました。 {{< x user=“ayuma_x” id=“1137004503868223491” >}} そこで次はキャプチャーの部分のみTaskを使ってバックグラウンドで処理してみました。 void ACaptureMachine::Tick() { AsyncTask(ENamedThreads::BackgroundThreadPriority, [this]() { // キャプチャー処理を実施 }); } そうすると先ほどよりもフレームレートが上がり効果がありましたので、次に複数ウィンドウのキャプチャーにトライしました。 ...

2019-06-19 · 1 分 · 147 文字 · ayumax

UE4 MarketplaceにJsonパーサープラグインをリリースしました

EasyJsonParser 自作のUE4プラグイン3作目としてEasyJsonParserをリリースしました。 EasyJsonParser:ayumax:Code Plugins - UE4 マーケットプレイス これは2作目のEasyXMLParserとコンセプトは同じで、ブループリント上から簡単なアクセス方法でJson内の値を取得できます。 こちらもGitHubのほうにサンプルプロジェクトをアップロードしてますので、ご興味ある方は参考にしてください。 使い方 Json文字列 or Jsonファイルロードした後、アクセス文字列を指定して値の取得を行います。 アクセス文字列の指定 基本的には取得したい値までのパスをドットでつなげて指定します。 シンプルなケース 以下のシンプルなJsonから"prop"の値をとる場合のアクセス文字列はpropになります。 { "prop":"abc" } オブジェクトの階層になっている場合 以下のように階層になっている場合は、ドットでつなげてアクセス文字列を作ります。 以下のケースではobjというオブジェクトの中のpropプロパティを取りたいため、アクセス文字列はobj.propになります。 { "obj": { "prop":"abc" } } 配列が含まれる場合 以下のように配列になっている場合は、何番目のものを取りたいかを指定します。 例えば2個目のpropを取りたい場合は、obj[1].propとなります。 1個目のpropを取りたい場合は、obj[0].propとなります。 { "obj":[ { "prop":"abc" }, { "prop":"def" } ] } 型を指定しての値の取得 Jsonから値を取得するために、次の4つの関数が用意されます。 ReadInt(int) ReadFloat(float) ReadString(string) ReadBool(bool) 「AccessString」にはアクセス文字列を入力します。 「DefaultValue」にはデフォルト値を入力します。指定された値がJsonに存在しない場合は、デフォルト値が返されます。 オブジェクトの取得 値ではなくオブジェクトとして取得する “ReadObject"および “ReadObjects"メソッドもあります。 このメソッドで取得できるのはオブジェクトプロパティのみです。 ReadObjectは1つのノードオブジェクトを取得します。 ReadObjectsは複数のオブジェクトの配列を取得します。 ...

2019-06-15 · 1 分 · 68 文字 · ayumax

ObjectDeliverer v1.2.0リリース

ObjectDelivererのV1.2.0をリリースしました。 変更点は以下の2つです。 PacketRuleNodivisionを使用してUDPの受信を行うと無限ループしてしまう不具合修正 TCP/IPクライアントでサーバーが切断されると自動的に接続を試みるオプション追加 PacketRuleNodivisionを使用してUDPの受信を行うと無限ループしてしまう不具合修正 上記のようにPacketRuleNodivisionを使用してUDPの受信機能を使うと、一度受信したタイミングで無限ループに入ってしまう不具合が起きていましたので修正しました。 UDPの受信はPacketRuleNodivisionを使うことが一番多いと思うので、ホント致命的な不具合で申し訳ないです。 TCP/IPクライアントでサーバーが切断されると自動的に接続を試みるオプション追加 以前からTCP/IPクライアントを利用時にRetryフラグをONにすると、自動でサーバーが起動するまでConnectを繰り返す機能が実装されていました。 ただし、この機能はいったんサーバーと接続確立後にサーバー終了した場合は働かない仕様でした。 そこで今回新たにAutoConnectAfterDisconnectフラグを作成しました。 このフラグをONにすると、接続済みのサーバーとの接続がなくなった場合に自動でConnectを繰り返すようになります。 そのため、従来のRetryフラグを合わせて使うことで、サーバーとつながっていない時はいつでもConnectを繰り返すようになります。 常に接続を確立しておきたいケースに便利です。

2019-06-11 · 1 分 · 14 文字 · ayumax

UE4 MarketplaceにXMLパーサープラグインを出品しました

EasyXMLParser 本日Unreal EngineのMarketplaceにEasyXMLParserという名前でプラグインを出品しました。 前回リリースしたObjectDelivererに続いて2作品目となります。 前回は無料で出品したのですが、今回はお値段をつけさせていただきました。 使いやすさを重視して作りましたので、よろしければ是非ご検討ください。 このプラグインを使ったサンプルはGitHubに公開しています。 機能紹介 EasyXMLParserの機能を紹介します。 テキストの取得 テキストノードを取得するには、取得したい値のアクセス文字列を作成します。 アクセス文字列はタグ名をドットで結ぶことによって作成されます。 同じタグ名を持つノードが複数ある場合は、0から始まるインデックス番号を指定できます(例:[2] - > 3番目)。 インデックスを指定しないと、最初の要素が取得されます。 属性を取得するためのアクセス文字列は(アットマーク+属性名)で指定します。 型を指定しての値の取得 XMLから値を取得するために、次の4つの機能が用意されます。 ReadInt(int) ReadFloat(float) ReadString(string) ReadBool(bool) 「AccessString」にはアクセス文字列を入力します。 「DefaultValue」にはデフォルト値を入力します。指定された値がXMLに存在しない場合は、デフォルト値が返されます。 オブジェクトの取得 ノードを値としてではなくオブジェクトとして取得する “ReadElement"および “ReadElements"メソッドもあります。 ReadElementは1つのノードを取得します。 ReadElementsは複数のノードの配列を取得します。 XMLパース手法 XMLをロードする方法は2つあります。XMLファイルをロードするための “LoadFromFile"と、XML文字列をロードするための “LoadFromString"です。 バックグラウンドで解析を実行する非同期バージョンもあります。 XMLの次は 個人的にはたまにXMLをパースする機会があるので、今回プラグイン化してみました。 ただ現在はXMLよりもJsonの方が使われているような気もしています。 ということで、次のプラグインとしてJsonパーサーを出すつもりです。 このEasyXMLParserと同様の使い勝手で設計しておりMarketPlaceに現在審査してもらっています。

2019-06-10 · 1 分 · 42 文字 · ayumax

ObjectDelivererの共有メモリサンプル

共有メモリのサンプル 以前からGitHubにObjectDelivererのサンプルを用意していたのですが、共有メモリについては読み込み側しか実装しておらず処理が完結していなかったので新規で書き込み側も実装しました。 ここではサンプルの内容を簡単に紹介します。 概要 このサンプルではSceneCapture2Dで撮った画像をTexurueRenderTargetから取り出し、そこから共有メモリを経由して別のマテリアルに表示します。 まずはSharedMemoryレベルを開いてください。 全実装はBox Actorブループリント内にあります。 読み込み側の実装 共有メモリから読み込んだピクセルバッファを入れるテクスチャとマテリアルを用意します。 共有メモリの読み込み用ObjectDelivererのインスタンスを生成し処理を開始します。 共有メモリのバッファサイズは画像バッファサイズ(800x450x4 byte)を設定しています。 ReceiveDataイベント(共有メモリの中身に変化があった時におこるイベント)でテクスチャの中身を更新します。 書き込み側の実装 TextureRenderTargetから取得したピクセルバッファを入れておくバッファを用意します。 共有メモリへの書き込み用ObjectDelivererのインスタンスを生成し処理を開始します。 共有メモリのバッファサイズは画像バッファサイズ(800x450x4 byte)を設定しています。 Tickイベント時にTextureRenderTargetからピクセルバッファを取り出し共有メモリに書き込みます。 使い道 この例では1つのプロセス内で完結しているためあまり意味はないですが、 例えばUE4のプロジェクトを2つ用意して、片方は共有メモリへの書き込みを担当し、もう片方は共有メモリからの読み込みを担当することで映像の受け渡しができます。 共有メモリはTCP/IPやUDPと違ってネットワーク経由でのデータの受け渡しはできませんが、その分大容量のデータを高速に渡せるため映像などの重いデータのプロセス間通信に適していると思います。 ご興味ある方はぜひ試してみてください。

2019-06-06 · 1 分 · 25 文字 · ayumax

Editor Utility Widgetを使ってお絵かきして動的メッシュ生成機能を作った

Editor Utility Widget 今回UE4.22から利用できるようになった、Editor Utility Widgetという機能を試してみました。 Editor Utility Widgetを利用するとUMGとブループリントでエディタ拡張が簡単に作れます。 Editor Utility Widgetの基本的な説明はおかずさんの記事を参考にしました。 [UE4]エディタ上で動作するツール・エディタ拡張をUMGで簡単に作れる Editor Utility Widget について - Qiita つくったもの Editor Utility Widget上をマウスドラッグすることで線を一筆書きで書き、 書き終わった線に沿ってスプラインメッシュを生成する機能を作りました。 できたスプラインメッシュは、ボタンを押すとスタティックメッシュにできます。 {{< x user=“ayuma_x” id=“1134083916317380613” >}} Editor Scripting Utilities Pluginの有効化 このプラグインを有効にすると、Editor Utility Widgetからアセットの操作などができるようになります。 Widget上で線を引く 線を引く部分はUserWidgetを1つ作ってその中で実装しました。 まず、変数に線を引くための座標(Vector2D)の配列を用意します。 次にMouseDownで毎回座標配列を空っぽに。 MouseMoveでは座標の配列にマウスの座標をいれます。 ただし、すべてのMouseMoveイベントで処理すると点の数が多すぎるので前回格納した点から5pixel以上離れた場合のみ点を格納しています。 あとはOnPaintでDrawLinesを呼べば線が引かれます。 MouseUpでは線が引かれ終わったことを示すイベントを発火しています。 このイベントをEditor Utility Widgetが監視してメッシュ生成をこの後していきます。 Editor Utility Widgetの実装 次にEditor Utility Widgetを作成します。 先ほど作ったUserWidgetも配置します。 ComboBoxにメッシュ生成機能をもったActorの一覧を出したいので、 ComboBoxが開いたタイミングでActorの一覧を取得し追加しています。 またComboBoxの選択が変わった時にカレントのActorを設定しています。 先ほど作ったUserWidgetの線の引き終わりイベントを監視して、カレントのActorに線に沿った座標の配列を渡します。 スプラインメッシュ生成 スプラインメッシュを生成するActorを作っていきます。 SplineComponentを2つと、SplineMeshComponentの親になるSceneComponentを1つ追加しておきます。 SplineComponentは点の補正をするために贅沢に2つ使ってます。 UserWidgetの線が引き終わったタイミングで呼ばれる関数を作成していきます。 まずは、直前に生成されていたSplineMeshComponentを全て破棄し、SplineComponentの点も空にします。 次に渡されて点の配列をそのままSplineComponentの点に追加していきます。 1pixelを10cmとして設定しています。 次に1つ目のSplineComponentのラインに沿って等間隔の点を取り出し2つ目のSplineComponentへ点を追加していきます。 ここで2つ目のSplineComponentを作っているのは、等間隔に点を作ったほうがこの後作成するSplineMeshがきれいになるからです。 最後に2つ目のSplineComponentの点の位置とTangentを使ってSplineMeshComponentを作っていきます。 ...

2019-05-30 · 3 分 · 430 文字 · ayumax