AYU MAX

プログラミングとか作ったもの

UE4+ARKitで作る遠隔タッチディスプレイ

先日頭の中にあったアイデアを形にしたくて、↓こんなものをつくりました。

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での物体検知の使い方は以前記事にしているので、興味ある方はみてください。

www.ayumax.net

まずはディスプレイをスキャンして検知するためのデータづくりを行ったのですが、ディスプレイの形状に特徴点が少なく満足する結果が得られませんでした。

そこでディスプレイ横のごちゃごちゃした所の検知データを作成し、ディスプレイの位置、角度はそのポイントからの相対位置で判断するようにしました。

当然ですが、この方法ではディスプレイとの位置関係を変えてしまうと破綻します。

↓スキャンしているところ f:id:ayuma0913:20191228115323j:plain

スキャン後にディスプレイの位置、角度を知るのは上記した以前の記事の内容そのままです。

iPadに触れた指の位置をディスプレイの相対座標として知る

次にiPadに触れた指の位置を知るにはどうすれば良いか考えます。

今回使っているUE4のARテンプレートの中の実装には、タッチしたポイントにActorがあるかどうか調べるロジック(BP_ARPawnのWorldHitTest関数)があります。

これをちょっといじってディスプレイの位置を知ることを考えました。

まず現実世界のディスプレイと同じ大きさになるような板メッシュを用意してレベルに配置しておきます。このメッシュは見える必要はないので透明なマテリアルをつけときました。

次に毎Tick, ARKitが現実のディスプレイを検知した位置、角度にこのメッシュを移動させます。

f:id:ayuma0913:20191228115926p:plain

次にWorldHitTest関数の中を見ると、LIneTraceForObjectsというノードが使用されているのが分かります。

LIneTraceForObjectsは指定した2点の間に3Dオブジェクトがあるかどうかの判定ができます。

このノードと直前に配置されているDeproject Screen to Worldを組み合わせると、タッチしたときのiPad上のスクリーン座標(x, y)から触れている場所に配置してある3Dオブジェクトが特定できます。

この仕組みを使うと、先ほど配置したメッシュを指で触れているかどうかということが分かります。

ただし、今回知りたいのはディプレイのどこを触れているかなので、もう少し詳細な情報が必要です。

そこでLIneTraceForObjectsで返される値をFind Collision UVに入れる部分を足してみました。

これで触れた3Dオブジェクトの表面のどの部分(UV座標)という情報までとれます。

f:id:ayuma0913:20191228120122p:plain

Find Collision UVを使うにはProject SettingsでSupport UV From Hit ResultsのチェックをONにする必要があります。(多分ONにすると処理負荷は上がっちゃいます)

f:id:ayuma0913:20191228121500p:plain

iPadからPC側に座標を送る

iPadからPC(Windows)へはソケット通信(UDP)で座標を送ることにします。

UDP送信にはObjectDelivererを使います。 ObjectDelivererについては過去記事みてください。

まずは送信するための入れ物を作ります。といっても簡単で以下のようなブループリントを定義します。TouchPositionというオブジェクトの名前にしました。

X座標とY座標を入れる変数のみ定義しただけです。

f:id:ayuma0913:20191228122246p:plain

このオブジェクトをObjectDelivererを使って送るための初期化を行います。

↓こんな感じ。

f:id:ayuma0913:20191228122845p:plain

そしてFind Collision UVで板メッシュのUVを取得している箇所で、以下のようにしてUDPを使ってPCに座標を送ります。

f:id:ayuma0913:20191228122159p:plain

これでiPadに映るディスプレイをタッチする度にPCにディスプレイのどこを触っているのかの座標を送り続けます。

PC側で送られた座標にしたがって線を引く

PC側が難しいことは何もしていなくて、ObjectDelivererを使ってUDPの受信を行い、送られてきたX, Y座標を取り出した後、UMGで線を引いているだけです。

この部分は今回重要な部分ではないので割愛します。

やってみた感想

考えた通りの動きを実現することができました。

iPadにはカメラ映像以外のものは何も表示していませんが、ARKitの機能を利用して面白いものができました。 こういった使い方はいろいろな可能性をひめているような気がします。

また新しいアイデアが湧いたら形にしてみようと思います。