UE4+Leap Motion+VRで空を飛ぼう!
本記事は「Unreal EngineでLeap Motionを使ってみよう」の続きとなります。
1.ハングライダーをLeap Motionで操作する
Windows8.1 Pro
Unreal Engine 4.11.2
利用サンプルプロジェクト:ランドスケープマウンテン
1.1 ハングライダーに移植
ランドスケープマウンテンプロジェクトでは、「Assets>Blueprints>HangGlider_Gameinfo」を開いてみると分かりますが、Default Pawn Classに「Assets>Blueprints>BP_Hang_Glider(以下、BP_Hang_Gliderと呼びます)」が設定されています。ゲームをプレイした時のキーボードからの入力も「BP_Hang_Glider」内のイベントグラフで処理されているようです。キーボード入力のイベントは「Input events for steering and camera」マクロになっているので、その中にUnreal EngineでLeap Motionを使ってみようで作成したLeap Motionの処理を移しましょう。また、ランドスケープマウンテンプロジェクトをVRプレビューするとデバッグハンドが正しく表示されないので、前回作成した「Draw Debug Sphere at Actor」については削除しました。
1.2 相対的な位置をトラッキング
1.2.1 相対的な位置
本章での「相対的な位置」というのは、Leap Motionのトラッキング開始時の位置を初期位置とする考え方です。伝わりにくいと思うので下図を参照してみて下さい。Leap Motionが手を検出した位置がどの高さであっても、必ず座標を0にするといった意味合いに捉えて頂ければ大丈夫です。それでは、最初にLeap Motionが手を検出した位置を初期位置として、その位置からどの程度ずれたかを計算しながら動作を行うBlueprintを実装していきます。
1.2.2 手のIDを保持
先ほど移してきたノードに「Set Hand ID」を追加して、検出した手のIDを「Right Hand ID」と「Left Hand ID」に保持しておきます。
「Set Hand ID」の内容は下図のようになっています。現在のIDと検出したIDが異なっていれば新しくIDと座標を設定します。
「Leap Motion Move Pattern」の内容も修正しました。
1.2.3 座標の計算
座標の計算は「Two Hand Relative」で行います。最終的なBlueprintは下図のようになりました。大部分は前回の記事と同様なので移してきても問題ありません。
まず、最初に検出された左手と右手の位置がBaseZ(定数値)からどれだけ離れているかを「BaseZ – OrizinZ」という計算で求めます。この計算結果を、「イベント RightHandMoved」と「イベント LeftHandMoved」で設定した手の位置と加算すると、常に最初に検出された手の位置を初期位置とした計算結果が得られます。
手の状態設定についてはほぼ変わりはないですが、パラメータを多少調整しています。
最後に手の状態から進む方向と上昇、下降値を設定していきます。Blueprintが長いので3つに分けて紹介します。
こちらも前回とそこまで変化はないですが、「MoveForward」の値を設定するために「Relative Right Position」に「-0.02」を乗算しているので注意です。また、「Right Strength」は定数値で0.8を設定しています。これはハングライダーの曲がる強さに影響してきますので、ゲームをプレイしながら調整してみてください。
左手に関しては「Relative Left Position」に「0.02」を乗算していることを除けば、右手と同様の処理を実装しています。
1.2.4 キーボード入力を除去
1.2.3章で設定した「Move Forward」と「Move Right」をハングライダーに設定します。
1.3 手を表示する
動画のようにハングライダーから手の表示に切り替える実装をしていきます。「BP_Hang_Glider」のビューポートを開き「Hang glider body」を選択すると詳細ウィンドウが表示されるので、「Rendering」項目にあるビジブルのチェックをはずしてハングライダーを非表示にします。次に、コンポーネントウィンドウの「コンポーネントを追加」から「Child Actor」を選択して名前を「LeapHands」に変更しておきました。
「LeapHands」を選択すると「Child Actor Class」が選択できるのですが、これにはLeap Motion Plugin内のBlueprintを指定します。コンテンツブラウザの表示オプションから「プラグインコンテンツを表示」にチェックを入れます。LeapMotionコンテンツの内容が表示されたので、「LeapRiggedEchoHandsActor」を選択しましょう。私は直接プラグイン内のBlueprintを指定したくなかったのでコピーしました。
1.4 手のマテリアルを修正
「LeapRiggedEchoHandsActor」に付けられているマテリアルは、ベースカラーに白を繋いでいるだけなので少し修正しました。ブレンドモードを「トランスルーセント」に変更し「オパシティ」を変更します。あとはFresnelを使って手の周囲は白に、内側は緑に設定しました。「Fresnel」ノードのパラメータである「Exponent」は1.0、「Base Reflect Fraction」は0.001です。(透過しすぎると手が見えなくなるので、オパシティの値は高めの方が良さそうです)
1.5 VRプレビューで表示
1.4章までの実装が終わると動画のように、空を飛び回ることが可能です。ところが、Leap Motionを下図のように配置してVRプレビューを実行すると手の挙動が逆になってしまったり、手の表示位置がずれてしまうことがあります。どうやらこれはLeap Motionプラグイン内の「Optimize for HMD」ノードが影響しているようです。
調べたところ修正対象のBlueprintは、Leap Motionのプラグイン内にある「LeapAnimBodyConnector」でした。
「Begin Play」から追っていくと、「Handle HMDMode Change」という関数でHMDモードの設定をしており、ここで「Optimize for HMD」ノードに「Leap Facing Mode Is HMD」の値が入力されています。
この部分を少し修正して「UseTopdownFlag」を繋げることで、「Optimize for HMD」の設定を外部から行えるようにします。Unreal Engineをアップデートするとこの設定は元に戻ってしまうので、毎回修正しなければならないという面倒臭さがあります。
設定をするBlueprintは「LeapAnimBodyConnector」を継承している、1.3章でコピーしておいた「LeapRiggedEchoHandsActor」になります。下図では「コンストラクションスクリプト」内で、「Is Head Mounted Display Enabled」ノードによりHMDモードの判定をしています。
また、それぞれ「Init HMD Mode」と「Init Default Mode」はどのプロジェクトでも使いまわせるように「ブループリント関数ライブラリ」として作成しておきました。今回の場合は、「UseTopdownFlag」をfalseにしておく必要があるのでチェックを入れていません。HMD手の位置も外部から調整できるように「Hand Position」としてパラメータを渡しています。
ブループリント関数ライブラリとは(ドキュメント参照)
「Init HMD Mode」
「Init Default Mode」
2.まとめ
今回はLeap Motionを使って空を飛んでいるようなサンプルを作ってみました。既存のサンプルプロジェクトの出来が素晴らしいので、Leap Motionへの操作変更が非常に楽でした。後半で紹介したように、VRプレビューをするからといって必ず「Optimize for HMD」ノードの「UseTopdownFlag」をtrueにする必要がないというのは新しい発見でした(実は何か良い方法がある?)。