MagicLeapOneでEyeTracking

こんにちは。HoloLensチームの老田です!

前回の記事「MagicLeapOneで2つのコントローラを使う方法」に引き続き、EyeTrackingができるようなので検証してみました。

なにができるの?

  • 両目での視線のトラッキング
  • 片目の視線のトラッキング
  • 視線のステータスの取得
  • 瞬きの検出(左右別々に判定可能)

視線のトラッキングについて

Holo2のような視線のトラッキングが可能になっています。
前提としてかぶり方次第ではずれているように感じますので頑張っていい位置を探してください。

Holo2と比べるとそこまで正確にトラッキングできているわけではなさそうでした。
誤差や精度についての話はここでは割愛します。

ある程度ずれていても両目でトラッキングしている場合はそれなりに動いてくれます。
片目の場合はしっかりかぶっていないとカーソルが視界にすら入ることもままなりません。

視線のステータスの取得

MLEyes.CalibrationStatusから以下が取得できます。

  • MLEyeTrackingCalibrationStatus_None(未検出の状態)
  • MLEyeTrackingCalibrationStatus_Bad(1度検出した後に検出できなくなった状態)
  • MLEyeTrackingCalibrationStatus_Good(検出できている状態)

ちなみに瞬きをした場合はMLEyeTrackingCalibrationStatus_Badと判定されます。
また、瞬きだけではなくMLを外した時にも上記と同様の扱いになります。

瞬きについて

以下のbool型のフィールドで取得できます。
MLEyes.LeftEye.IsBlinking
MLEyes.RightEye.IsBlinking

精度はよいです。
普通の一瞬だけの瞬きでも取得でき、ウィンクでも行けます。
ただし、ウィンクしなれてないのでウィンクだけ難しく感じました。

サクッと動かす(両目の視線のトラッキング)

特にあれこれする必要もなく上記のInspectorの設定に合わせるだけで動作します。
MaterialやSharder、Scriptに関してはMagicLeapのExamplesを入れていればすべてそろっています。

実行すると視線の先にカーソルが表示されるようになります。

ざっくりと解説するとWorldRaycastEyes内でUpdateごとにOnRaycastHitが呼ばれています。
ここでオブジェクトのTransformを変更しています。

もう少し深掘りしてみる(ウィンクで何か操作する)

右ウィンクしたときに0.5秒たったら何かするものを実装してみました。
あとは豆腐の色変えたりお好きに使ってください。

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.MagicLeap;

public class EyeTracking : MonoBehaviour
{
  bool isBlink = false;
  float count = 0f;
  [SerializeField] float threshold = 0.5f;

  private void Start()
  {
    StartCoroutine(BlinkCheck());
  }
  private IEnumerator BlinkCheck()
  {
    MLEyes.Start();
    while (true)
    {
      // 右目のウィンクだけを判定
      if (!isBlink && MLEyes.RightEye.IsBlinking && !MLEyes.LeftEye.IsBlinking)
      {
        count += Time.deltaTime;
        // 右ウィンクしている状態で0.5秒たったらコマンドと認識
        if (count > threshold)
        {
          isBlink = true;
          Debug.Log("is Blink Command");
        }
      }
    }

    // 両目を開いたらリセット
    if (!MLEyes.RightEye.IsBlinking && !MLEyes.LeftEye.IsBlinking)
    {
      count = 0f;
      isBlink = false;
    }
    yield return null;
    }
  }
}