Oculus Rift/HTC Viveでジェスチャー入力

2013年12月11日

(更新)プロジェクトファイルをUnity 2017に対応し、Unity標準のVRサポート機能で動くようにしました。また、諸々のリファクタリングを行いました。

Oculus Rift Advent Calendar 2013の11日目の記事です。また、新しいブログおよび活動名での初めての記事になります。よろしくお願いいたします。

*

さて本題です。Oculus Riftのことを初めて知ったときに、ヘッドトラッキングを使って、うなずいたらYes、首を振ったらNoというのができるんじゃないかと思ったんですが、実際にやってみました。実アプリケーションにおいては、このような活用ができます。

実行ファイルはこちらです。

また、UnityのプロジェクトファイルをGitHubに公開していますので、興味がありましたら自由にお使いください。ただ、調整は必要だと思います。

WikipediaのNodHead shakeの項目によると、うなずきで肯定、首を振ると否定というのは多くの国で概ね通じるジェスチャーだそうです(全世界共通ではないんですね)。ゲームなどで、NPCが通常の入力だけではなく、こうしたジェスチャーや、またもっと微妙な顔の動きにも反応してくれると幅が出たりするんじゃないでしょうか。

仕組み

どうやって作ったかについてですが、まずとにかくトラッキングの生データを見てみることにしました。InputTracking.GetLocalRotationでヘッドセットの向きを毎フレーム取得して、タイムスタンプと一緒に以下のようなFIFOバッファに突っ込みます。

struct Sample
{
    public float timestamp;
    public Quaternion orientation;
    public Vector3 eulerAngles;
    ...
}
...
LinkedList<Sample> samples;

UnityのGL.LINESを使ってテクスチャにグラフを描き、眼前に表示します。するとこのようなグラフが見られます。

これを眺めながらしばらく考え込んだんですが、X軸とY軸それぞれの一定範囲の平均値や最大変化量などをいくつかチェックするだけで、とりあえず今回の目的は達成できるんじゃないかと思いました。もう少しきちんとパターン認識のようなことをしないといけない気もするんですが、そうした知識はないので手抜きです(いい情報源があれば教えてください)。実際のうなずき判定コードがこんな感じです(VRGesture.cs)。

IEnumerable<Sample> Range(float startTime, float endTime)
{
    return samples.Where(sample => (sample.timestamp < Time.time - startTime &&
                                    sample.timestamp >= Time.time - endTime));
}

void RecognizeNod()
{
    try
    {
        float basePos = Range(0.2f, 0.4f).Average(sample => sample.eulerAngles.x);
        float xMax = Range(0.01f, 0.2f).Max(sample => sample.eulerAngles.x);
        float current = samples.First().eulerAngles.x;

        if (xMax - basePos > 10f &&
            Mathf.Abs(current - basePos) < 5f)
        {
            if (NodHandler != null) { NodHandler.Invoke(); }
            waitTime = recognitionInterval;
        }
    }
    catch (InvalidOperationException)
    {
        // Range contains no entry
    }
}

あとは、せっかく判定ができるようになったので応用してみようということで、簡単なスクリプトエンジンを書いて、時期柄こういうスクリプトを動かしてみました。

delay 500

*start
わたしを お城まで 連れて
帰ってくださいますのね?
riftgesture *yes, *no

*yes
delay 300
うれしゅうございます。
ぽっ…。
delay 1500
goto *start

*no
delay 300
そんな ひどい…。
delay 1500
goto *start

ちなみにこのループの実物を再確認するためにドラゴンを倒すところまで進めようと思ったんですが、結局、竜王も倒しました。

まあ、そんな感じで、ずっと眠ってた小ネタを試せたので満足しています。締め切りがあると進捗があるという例です(笑)。あと、ジャンピングフラッシュのようなものを作るつもりだったのに手をつけてないので、来年以降なんとかしたいです。

Oculus Rift Advent Calendar 2013の記事でした。他の方もすごいネタの数々を披露されてますので、興味を持たれた方はぜひチェックしてみてください。

(書いた人: こりん

ブログトップへ