Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

FirstVRでカスタムジェスチャーの登録をするサンプル

More than 1 year has passed since last update.

概要

FirstVRでカスタムジェスチャーを登録し、利用する準備までをやってみたいと思います。
なお、FirstVRってなんやねんって人は前の記事(FirstVRでHello World)を参照ください。

カスタムジェスチャーとは、任意の手の形を登録し、その手の形になっているかどうかを判断してくれるようになるものです。
実際に試してみたところ、精度はだいぶいい感じでした。

シーンのセットアップ

まず、FirstVRデバイスとのコネクションなどは専用のPrefabがあるのでそれを配置します。
また、現在のコネクション状況などステータスを表示してくれるPrefabも用意されているので、それを配置しておくと認識しているかどうかを表示してくれるので便利です。

FVRContainerConnectionCheck、ふたつのPrefabをシーンに配置します。

スクリーンショット 2018-12-27 13.59.03.png

カスタムジェスチャの登録を行う

コードを書く前の準備

まず、FirstVRの機能を使いやすくするためにFVRlibusingしておきます。

using FVRlib;

また、FVRConnectionクラスを利用してジェスチャ登録などを行うため、FVRContainerPrefabの中に配置されているFVRConnectionをインスペクタから登録しておきます。

スクリーンショット 2018-12-27 14.03.41.png

これで準備が出来たのでコードを書いていきます。

カスタムジェスチャ登録のフロー

まずはざっくりとフローを確認します。

  1. FVRGestureManagerRegisterCustomGestureメソッドを通して新規のジェスチャを生成(登録)する
  2. FVRGestureManagerSetTargetDataメソッドを通して、対象のジェスチャのキャリブレーションを行う
  3. FVRGestureManagerSetNonTargetDataメソッドを通して、対象「以外」のジェスチャのキャリブレーションを行う
  4. FVRGestureheldプロパティの状況で判断する

という流れになります。
もう少し具体的に説明しておくと、FVRGestureが把握するのは任意のジェスチャ(手の形)ですが、複数のジェスチャを登録する場合は「それ以外」のジェスチャをSetNonTargetDataとして登録する必要があります。

例えば「グー」「チョキ」「パー」の3つを認識させたい場合、

  1. 「グー」ジェスチャのSetTargetDataには「グー」を、SetNonTargetDataには「チョキ」と「パー」を登録。
  2. 「チョキ」ジェスチャのSetTargetDataには「チョキ」を、SetNonTargetDataには「グー」と「パー」を登録。
  3. 「パー」ジェスチャの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の値は、例えばユーザに「ジェスチャ登録」ボタンなどを押してもらってキャリブレーションモードに入る際に設定して登録を行うような形になるでしょう。
以下のような感じです。

スクリーンショット 2018-12-28 9.29.49.png

実際にコンテンツを作る際は、登録が終わるまでユーザに該当する手の形のままにしておいてもらう、などの表示が必要でしょう。

ジェスチャを認識して処理を分ける

以上でカスタムジェスチャの生成・登録と設定が終わりました。
あとはこれを使って実際のコンテンツを作っていくことになります。

ということで、最後は「ジェスチャの状態をどう判断するか」です。
といっても本当にシンプルで、以下のようなコードで判断することができます。

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;
        }
    }
}
edo_m18
現在はUnity ARエンジニア。 主にARのコンテンツ制作をしています。 最近は機械学習にも興味が出て勉強中です。 Unityに関するブログは別で書いています↓ https://edom18.hateblo.jp/
http://edom18.hateblo.jp/
unity-game-dev-guild
趣味・仕事問わずUnityでゲームを作っている開発者のみで構成されるオンラインコミュニティです。Unityでゲームを開発・運用するにあたって必要なあらゆる知見を共有することを目的とします。
https://unity-game-dev-guild.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away