概要
FirstVRでカスタムジェスチャーを登録し、利用する準備までをやってみたいと思います。
なお、FirstVRってなんやねんって人は前の記事(FirstVRでHello World)を参照ください。
カスタムジェスチャーとは、任意の手の形を登録し、その手の形になっているかどうかを判断してくれるようになるものです。
実際に試してみたところ、精度はだいぶいい感じでした。
シーンのセットアップ
まず、FirstVRデバイスとのコネクションなどは専用のPrefabがあるのでそれを配置します。
また、現在のコネクション状況などステータスを表示してくれるPrefabも用意されているので、それを配置しておくと認識しているかどうかを表示してくれるので便利です。
FVRContainer
とConnectionCheck
、ふたつのPrefabをシーンに配置します。
カスタムジェスチャの登録を行う
コードを書く前の準備
まず、FirstVRの機能を使いやすくするためにFVRlib
をusing
しておきます。
using FVRlib;
また、FVRConnection
クラスを利用してジェスチャ登録などを行うため、FVRContainer
Prefabの中に配置されているFVRConnection
をインスペクタから登録しておきます。
これで準備が出来たのでコードを書いていきます。
カスタムジェスチャ登録のフロー
まずはざっくりとフローを確認します。
-
FVRGestureManager
のRegisterCustomGesture
メソッドを通して新規のジェスチャを生成(登録)する -
FVRGestureManager
のSetTargetData
メソッドを通して、対象のジェスチャのキャリブレーションを行う -
FVRGestureManager
のSetNonTargetData
メソッドを通して、対象「以外」のジェスチャのキャリブレーションを行う -
FVRGesture
のheld
プロパティの状況で判断する
という流れになります。
もう少し具体的に説明しておくと、FVRGesture
が把握するのは任意のジェスチャ(手の形)ですが、複数のジェスチャを登録する場合は「それ以外」のジェスチャをSetNonTargetData
として登録する必要があります。
例えば「グー」「チョキ」「パー」の3つを認識させたい場合、
- 「グー」ジェスチャの
SetTargetData
には「グー」を、SetNonTargetData
には「チョキ」と「パー」を登録。 - 「チョキ」ジェスチャの
SetTargetData
には「チョキ」を、SetNonTargetData
には「グー」と「パー」を登録。 - 「パー」ジェスチャの
SetTargetData
には「パー」を、SetNonTargetData
には「グー」と「チョキ」を登録。
という具合です。
コード解説
さて、フローが分かったところでコードを見てみましょう。
フローで示した順にコード断片を見ていきます。
ジェスチャの生成(登録)
[SerializeField]
private FVRConnection _fvr;
// ... 中略 ...
private void Start()
{
_gesture = _fvr.gestureManager.RegisterCustomGesture("Gesture1");
}
Start
メソッドの中で生成していますが、他の任意のタイミングでも大丈夫です。
_fvr
はインスペクタから登録しておきます。
そしてRegisterCustomGesture
メソッドに、文字列で名称を設定して、マネージャクラスを通してジェスチャの生成と登録を行っています。
ジェスチャの設定(キャリブレーション)
これでジェスチャを登録する準備が整いました。
次に行うのは、このジェスチャオブジェクトが「どの形の手をジェスチャとして認識すべきか」の設定です。
またそれと同様にして「どの形の手がジェスチャではないか」も設定します。
private IEnumerator Calibrate(bool isTarget)
{
if (isTarget)
{
_fvr.gestureManager.SetTargetData(_gesture);
}
else
{
_fvr.gestureManager.SetNonTargetData(_gesture);
}
float time = 0;
// ここでプログレスバーの更新など
while (_gesture.registering)
{
time += Time.deltaTime;
Debug.Log(time.ToString());
yield return null;
}
}
キャリブレーション処理です。
コルーチンで動く想定で作っていますが、これは、ジェスチャの認識に若干の時間がかかるためキャリブレーション中の表示を行うための処置です。
例えば認識中のプログレスバーなどを実装する場合はここにその処理を入れるなどするといいでしょう。
また引数は(今回は)bool
型となっていますが、これは登録するジェスチャが1種類だけを想定しているため、「対象か否か」の2択で済むためです。
もし2つ以上の複数ジェスチャに対応したい場合は、どのジェスチャに対して設定を行うか、も判断する必要が出てきます。
が、今回はシンプルな例にするためこのようにしています。
このbool
の値は、例えばユーザに「ジェスチャ登録」ボタンなどを押してもらってキャリブレーションモードに入る際に設定して登録を行うような形になるでしょう。
以下のような感じです。
実際にコンテンツを作る際は、登録が終わるまでユーザに該当する手の形のままにしておいてもらう、などの表示が必要でしょう。
ジェスチャを認識して処理を分ける
以上でカスタムジェスチャの生成・登録と設定が終わりました。
あとはこれを使って実際のコンテンツを作っていくことになります。
ということで、最後は「ジェスチャの状態をどう判断するか」です。
といっても本当にシンプルで、以下のようなコードで判断することができます。
if (_gesture.held)
{
// 登録したジェスチャ状態
}
else
{
// それ以外の状態
}
UnityのInput
クラスのようなシンプルな使い方ですね。
生成したジェスチャオブジェクトのheld
プロパティを参照することで、登録したジェスチャの状態にあるか否かをbool
で返してくれます。
あとはこの状態をチェックして適切にコンテンツに落とし込んでやれば、設定した任意のジェスチャに応じて処理を分けていくことができます。
冒頭でも書きましたが、精度はだいぶ高いのでゲーム以外の用途にも全然使えるなーというのが個人的な感想です。
さらに言えば、スマホをコントローラにしてなにかの装置を操作する、みたいな使い方すらもありなんじゃないかなーと思っています。
コード全文
さて、最後に今回作成したサンプルの全文を載せておこうと思います。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using FVRlib;
public class CustomGesture : MonoBehaviour
{
[SerializeField]
private FVRConnection _fvr;
[SerializeField]
private Text _logText;
[SerializeField]
private Text _recognizedText;
private FVRGesture _gesture;
private void Start()
{
_gesture = _fvr.gestureManager.RegisterCustomGesture("Gesture1");
}
private void Update()
{
if (_gesture.held)
{
_recognizedText.text = "Target!";
}
else
{
_recognizedText.text = "Non Target!";
}
}
private void Log(string log)
{
_logText.text = log;
}
public void SetGesture()
{
StartCoroutine(Calibrate(true));
}
public void SetNonGesture()
{
StartCoroutine(Calibrate(false));
}
private IEnumerator Calibrate(bool isTarget)
{
if (isTarget)
{
_fvr.gestureManager.SetTargetData(_gesture);
}
else
{
_fvr.gestureManager.SetNonTargetData(_gesture);
}
float time = 0;
while (_gesture.registering)
{
time += Time.deltaTime;
Log(time.ToString());
yield return null;
}
}
}