UE4+ARKitで作る遠隔タッチディスプレイ
先日頭の中にあったアイデアを形にしたくて、↓こんなものをつくりました。 {{< x user=“ayuma_x” id=“1210122895520718849” >}} iPadの上を指でなぞると、iPadの中のディスプレイに線が引かれているのですが、iPadを取り除くと実際のディスプレイにも同じ線が引かれています。 これは初見だと混乱するかもしれませんが、実はiPad側には何も表示は加えていません。iPadのディスプレイにはカメラの映像のみ表示しています。 何をしたかったのか? 少し前に仕事でiPad使ってARのコンテンツを作っていたのですが、その時に感じた「AR=[何か表示を重ねる]以外の使い方を考えてみたいな」と思ったのがきっかけです。 今回行った内容も多分誰かが似たようなことはやっているのだとは思いますが、「自分で考えてアイデアを形にすることに意味がある」ということでやってみました。 今回の実験においてiPadは入力機器として使います。 ARKitには画像検知や物体検知の機能があり、これをうまく使うことで遠隔タッチディスプレイを作ろうというアイデアです。 やるべきこと このアイデアを形にするためにやるべきことを以下にまとめました。 今回iPadのアプリケーションはUE4(4.24)のHandheld AR ブループリント テンプレートをベースに作ります。 iPadに映っているディスプレイの位置、角度を知る iPadに触れた指の位置をディスプレイの相対座標として知る iPadからPC側に座標を送る PC側で送られた座標にしたがって線を引く iPadに映っているディスプレイの位置、角度を知る まずはディスプレイの位置を知る必要があります。 位置を知る方法として「画像を利用したマーカー方式」と「物体検知」の2通りを考えましたが今回は物体検知を選びました。 UE4+ARKitでの物体検知の使い方は以前記事にしているので、興味ある方はみてください。 UE4でARKitの物体検出機能を使う - AYU MAX まずはディスプレイをスキャンして検知するためのデータづくりを行ったのですが、ディスプレイの形状に特徴点が少なく満足する結果が得られませんでした。 そこでディスプレイ横のごちゃごちゃした所の検知データを作成し、ディスプレイの位置、角度はそのポイントからの相対位置で判断するようにしました。 当然ですが、この方法ではディスプレイとの位置関係を変えてしまうと破綻します。 ↓スキャンしているところ スキャン後にディスプレイの位置、角度を知るのは上記した以前の記事の内容そのままです。 iPadに触れた指の位置をディスプレイの相対座標として知る 次にiPadに触れた指の位置を知るにはどうすれば良いか考えます。 今回使っているUE4のARテンプレートの中の実装には、タッチしたポイントにActorがあるかどうか調べるロジック(BP_ARPawnのWorldHitTest関数)があります。 これをちょっといじってディスプレイの位置を知ることを考えました。 まず現実世界のディスプレイと同じ大きさになるような板メッシュを用意してレベルに配置しておきます。このメッシュは見える必要はないので透明なマテリアルをつけときました。 次に毎Tick, ARKitが現実のディスプレイを検知した位置、角度にこのメッシュを移動させます。 次にWorldHitTest関数の中を見ると、LIneTraceForObjectsというノードが使用されているのが分かります。 LIneTraceForObjectsは指定した2点の間に3Dオブジェクトがあるかどうかの判定ができます。 このノードと直前に配置されているDeproject Screen to Worldを組み合わせると、タッチしたときのiPad上のスクリーン座標(x, y)から触れている場所に配置してある3Dオブジェクトが特定できます。 この仕組みを使うと、先ほど配置したメッシュを指で触れているかどうかということが分かります。 ただし、今回知りたいのはディプレイのどこを触れているかなので、もう少し詳細な情報が必要です。 そこでLIneTraceForObjectsで返される値をFind Collision UVに入れる部分を足してみました。 これで触れた3Dオブジェクトの表面のどの部分(UV座標)という情報までとれます。 ※ Find Collision UVを使うにはProject SettingsでSupport UV From Hit ResultsのチェックをONにする必要があります。(多分ONにすると処理負荷は上がっちゃいます) iPadからPC側に座標を送る iPadからPC(Windows)へはソケット通信(UDP)で座標を送ることにします。 UDP送信にはObjectDelivererを使います。 ObjectDelivererについては過去記事みてください。 まずは送信するための入れ物を作ります。といっても簡単で以下のようなブループリントを定義します。TouchPositionというオブジェクトの名前にしました。 ...