日本のMR元年ともいえる2017年ももうすぐ終わりですね。早いものです。
HoloLensを入手して以来様々なアプリを作成してきましたが、アプリデモの際の鬼門といえば。。。そう、エアータップのジェスチャーですね。
標準で使える代替入力手段として考えられるのは音声入力ですが、これも英語しか対応していないので辛いところです。
ジェスチャー、音声がダメとなると残されているのは視線入力なので、これで何とかできるか考えてみました。
記事が長いので先に結果の動画を見たい方はこのリンクをクリック
#この記事の前提事項
- 対象読者想定はHoloToolKitでエアータップイベントを実装できるくらい
- HoloToolKitのバージョンは1.5.8(それ以上でも多分同じ)
#温故知新~VRでのインタラクション~
VRでのインタラクションは同じHMDなので使えそうなものがありそうです。というわけで探してみるといい感じのUnityのチュートリアルがありました。
https://unity3d.com/jp/learn/tutorials/topics/virtual-reality/interaction-vr
このページのSelectionRadial と SelectionSliderのところはまさに探していたものですね。
このUIは視線を対象に向けつつ一定時間の「長押し」で選択ゲージが満ちるとアクションが実行されます。
HoloLensにも視線入力のためのカーソルがあるので、今回は円形のゲージがカーソルの周りに出るSelectionRadialのUIをHoloLensに移植、改造してみます。
#SelectionRadialの移植
チュートリアルのソースはGitHubから入手できます。
修正作業は修正用のプロジェクトを作成することをおすすめします。
###UI部品の移植
SelectionRadialのUI部品はAssets\VRSampleScenes\Prefabs\UtilsのMainCamera.prefabの子要素であるUISelectionBarなので一旦別のプレハブとして切り出してUISelectionBarに使われているアセットと一緒にエクスポートします。
エクスポートした部品は別途作成したHoloToolKitをインポート済みのプロジェクトにインポートします。
###SelectionRadial.csの変更
次にAssets\VRSampleScenes\Scripts\UtilsにあるSelectionRadial.csのソースをHoloToolKitに合わせて以下のように変更します。(修正部分だけ抜粋)
using HoloToolkit.Unity; //Singletonのために追加
public class SelectionRadial : Singleton<SelectionRadial> //使いやすくするためにSingletonを継承
{
//[SerializeField] private VRInput m_VRInput; //不要なので削除
private void OnEnable()
{
//m_VRInput.OnDown += HandleDown; //不要なので削除
//m_VRInput.OnUp += HandleUp; //不要なので削除
}
private void OnDisable()
{
//m_VRInput.OnDown -= HandleDown; //不要なので削除
//m_VRInput.OnUp -= HandleUp; //不要なので削除
}
public void HandleDown() //private→publicに変更
{
//省略
}
public void HandleUp() //private→publicに変更
{
//省略
}
}
修正したスクリプトは別途作成したHoloToolKitをインポート済みのプロジェクトにインポートします(インポート後に修正のほうがベターかも)。
###Focusイベントとの紐づけ
選択対象のオブジェクトを見つめたときにSelectionRadialが動作するように、オブジェクトにアタッチするスクリプト(GazeInputTarget.cs)を作成します。
別途作成したHoloToolKitをインポート済みのプロジェクトで以下のようなスクリプトを作成します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HoloToolkit.Unity.InputModule;
using System;
using VRStandardAssets.Utils;
public class GazeInputTarget : MonoBehaviour,IFocusable {
public void OnFocusEnter()
{
//オブジェクトに視線が当たったらゲージがいっぱいになった時のイベントを登録
SelectionRadial.Instance.OnSelectionComplete += OnSelectionComplete;
SelectionRadial.Instance.Show();
SelectionRadial.Instance.HandleDown();
}
public void OnFocusExit()
{
//オブジェクトに視線がはずれたらゲージがいっぱいになった時のイベントを解除
SelectionRadial.Instance.OnSelectionComplete -= OnSelectionComplete;
SelectionRadial.Instance.HandleUp();
SelectionRadial.Instance.Hide();
}
private void OnSelectionComplete()
{
//ここにゲージがいっぱいになったら実行される処理を書く。今回は色を青に変更
gameObject.GetComponent<Renderer>().material.color = Color.blue;
}
}
###カーソルとの統合
アセットとスクリプトがそろったら実際にHoloLensアプリのカーソルに今回のUI部品を統合します。
以下のようにDefaultCursorの子要素としてUI部品を追加し、シーンビューで見え方を調整してください。
(DefaultCursor以外のカーソルの場合は試してませんが、試行錯誤すればできると思います。)
SelectionRadialUIはUIのためのCanvasとSelectionRadial.csをアタッチしておくためのオブジェクトです。
参考までにSelectionRadialUIとUISelectionBarの設定値は以下のような感じです。
#デモ用シーンの構成
今回はシーンにCubeとSphereを追加し、それぞれにGazeInputTargetをアタッチしました。
#デモ
上記のシーンビルド・デプロイしてみるとこんな感じです。結構イケてますね!
#まとめ
今回のUIはいかがだったでしょうか?
エアータップを使わずにインタラクションするための手段としては結構使えると思います。
ただ、これを使う場合はユーザを混乱させないためにジェスチャー入力は併用しないといった一貫性を持ったUI設計の工夫が必要だと思います。
また、選択に時間がかかる、複雑な操作はできないという点もあるので、用途としてはオブジェクトを動かしたりする操作の多いアプリには向かず、メニューの選択ぐらいの操作が要求されるビューワーとしての用途のアプリに使うべきかと思います。
まだまだHoloLensのUIのベストプラクティスというものはないので、色々試行錯誤しながらUI・UXの向上を図っていきたいですね。
(正直このくらいはToolKitに入ってくれるとうれしいな)