#前書き
Unity Technologies社の無料公開中のVR用サンプルプロジェクトのVR Samplesはとてもよく出来たサンプルです。このサンプルは、新規にVR系のコンテンツを作る人なら丸ごとインポートしても問題ないくらいに、よく出来ています。
このUnity VR SamplesはUnity5.3以上推奨となっています。
しかし、実際はUnity5.3で新しく導入されたSceneManager周りを書き換えればUnity5.2でも動きます。
#MainMenu.unity
視線入力によるMenu選択式のUIです。
##選択対象のボタン的な部分
MenuItemFlyerを見てみます。MenuButton.csと言うコンポーネントが付属していて、これはVR InteractiveItem.csを参照しています。
VRInteractiveItem.csの中身はイベントハンドラの塊です。
GearVRで言うタッチパッドクリック(PCだとマウスクリック)や、ダブルクリック、OverやOutは視線が載る時と外れる時に呼ばれます。
MenuButton.csはVRInteractiveItemのイベントデリゲートに追加しています。
後述のSelectionRadial (グルッと視線カーソルを取り巻く一周のピンク帯)の動きをイベントと結びつけることと、シーンのロードを追加しています。このSelectionRadialはMainCameraにアタッチされています。
SelectionRadialは一周になったらOnSelectionCompleteイベントが生まれるので、このMenuButton.csでは、このイベントに対してシーンのロードを行うように指示しています。
m_SelectionRadial.OnSelectionComplete += HandleSelectionComplete;
とやっていて、
こんな風にコルーチンを呼んでいます。
private void HandleSelectionComplete()
{
// If the user is looking at the rendering of the scene when the radial's selection finishes, activate the button.
if(m_GazeOver)
StartCoroutine (ActivateButton());
}
コルーチンの中身は、大雑把に言って次のシーンを呼んでいます。
private IEnumerator ActivateButton()
{
//略
SceneManager.LoadScene(m_SceneToLoad, LoadSceneMode.Single);
//後略
}
MenuItemPopoutなども、基本的にVRInteractiveItemのイベントを検知して動作させています。
(うーん、個人的にはMenuButton.csはRequireComponentでVRInteractiveItemを強制した方が良い気がする…)
##選択するためのMainCamera部分
VREyeRayCaster.csはこのシーン構成のキモです。
毎フレームEyeRayCast()を呼んでいます。また、VRInput.csのイベントハンドラにデリゲートで追加しています。
この辺りの関係はVRInput→VREyerayCastというのがVRInteractiveItem→VRMenuItemというのと対になっています。
EyeRayCast()の中でPhysics.Raycast()を呼んでいます。レイヤーマスク指定も出来ますが、デフォルトではIgnoreRaycastになっています。これでヒットしたオブジェクトにVRInterativeItemコンポーネントが存在しているかどうかを調べて、存在した場合は、イベントを呼び出すpublicな関数を呼んでいます(例:VRInteractiveItem::Over()など)
こういった風に入力側は相互作用がある相手のイベント発火だけを呼ぶようにしておいて、呼ばれる相手側はイベント発火に合わせてデリゲートを追加しておく。という作り方は、疎結合に作る上で大切ですね。
SelectionRadialのUseNormalのチェックボックスは、チェックを入れるとVRInteractiveItemをアタッチしたオブジェクトに対して、コライダの接線方向に沿って傾けることが出来ます。
また、このスクリプトは内部でSelectionという変数に入れたuGUIのImageを操作しています。
(UISelectionBarを読んでいます)
VRInput
Update内でChekInput()と言う関数だけを呼んでいます。このCheckInput()内でキー入力を監視して、
public event Action OnClick; // Called when Fire1 is released and it's not a double click.
public event Action OnDown; // Called when Fire1 is pressed.
public event Action OnUp;
などのイベントを、こんな風に呼んでいます。
if (OnDown != null)
OnDown();
DetectSwipeだけは、クリック時にスワイプしているかどうかの分岐のために呼ばれて、上方向なのか、右方向なのか、などを判定しています。
VRcameraUI
これはuGUIで作っている視線マーカー部分のUIを、ソートレイヤーの最後に回すという処理をしています。これを怠ると、なぜだかカーソルが描画されない、みたいな事になります。
別にこのスクリプトはMainCameraにアタッチする必要はなく、空のゲームオブジェクトにアタッチして、UICanvasだけインスペクタ上で設定すれば同じです。
##その他
VRDeviceManagerというスクリプトを空のGameObjectに付けておくと、RenderScale(昔で言うところのNativeTextureResolution)を変更できます。これはそのままにするより、設定ファイルに書き出せるようにしておくと、スペックが低いPCで実行する時に変更出来たりして便利かもしれません。
Serialize Fieldを多用しているのは「ここはヒエラルキービュー上で設定する必要があるが、publicしておくと、スクリプトを使う人が誤ってアクセスしてしまうかもしれない」という思想が見えて良いですね。
ヒエラルキービュー上で言うところの、UISelectionBarImageのImageコンポーネントは、一周をグルリとするUIになっていて、FillAmountを0から1にするとグルリとして楽しいです。
#最後に
一番簡単なメニューセレクトのシーンだけを追っても、こんな感じに読むと(僕には)勉強になりました。他のシーンも読もうと思いました、
#おすすめURL
Unity5.3のVR機能(インタラクション) タオバイザーさんのblog
http://taovisor.com/news/unity-interaction-vr/