始めに
Vive Pro Eyeを購入したので、Unityでアイトラッキングを試してみようと思います。
セットアップ
基本的なセットアップはフェイシャルトラッカーと同じなのでこちらを参照してください。
アイトラッキングを試す
始めにVive Pro Eyeを起動し、次に「SRanipalRuntime」を起動します。
無事起動できた場合はタスクバーにあるSRanipalRuntimeのアイコンの目が付きます。
次にVive Pro Eyeをつけてメニューの左から3番目を選択して、アイトラッキングのキャリブレーションを行います。
無事アイトラッキングが完了したら、SDKファイル内にある「FaceGym」で動作するか確認して問題無ければアイトラッキングできます。
もし、キャリブレーションの時点でエラーが出た場合はデバイスのアップデートが必要になると思うのでタスクバーのSRanipalRuntimeからアップデートをしてください。
アイトラッキングで使用されるデータについて
EyeData_v2
始めにEyeData_v2
についてまとめます。
frame_sequence
とtimestamp
についてですが、調べてみたところサンプルで使われていないのでそこまで重要ではないかもしれません。
変数名 | 型 | 解説 |
---|---|---|
no_user | bool | HMDを被っているか(trueの場合被っている) |
frame_sequence | int | 再生してからのフレーム数? 公式サンプルでは未使用。 |
timestamp | int | サンプリングしたときの時間(ms)。 公式サンプルでは未使用。 |
verbose_data | VerboseData | 後述 |
expression_data | EyeExpression | 後述 |
VerboseData
VerboseData
には左右の目それぞれの情報と両方を合わせた情報、TrackingImprovements
があります。
TrackingImprovements
についてですが、こちらもまたサンプルでは使われていないので解説は省きます。
変数名 | 型 | 解説 |
---|---|---|
left | SingleEyeData | 左目の情報 |
right | SingleEyeData | 右目の情報 |
combined | CombinedEyeData | 両目合わせた情報 |
tracking_improvements | TrackingImprovements | 謎。公式サンプルでも未使用 |
SingleEyeData
SingleEyeData
では目の詳細な情報が入っています。
変数名 | 型 | 解説 |
---|---|---|
eye_data_validate_bit_mask | System.UInt64 | SingleEyeData.GetValidity で使用される。直接触ることはないと思う。 |
gaze_origin_mm | Vector3 | ローカル空間での目の位置(右手座標系) |
gaze_direction_normalized | Vector3 | ローカル空間での視線ベクトル(右手座標系) |
pupil_diameter_mm | float | 瞳孔径(瞳の大きさ) |
eye_openness | float | まぶたが開いているか(0 ~ 1) |
pupil_position_in_sensor_area | Vector2 | 瞳の位置を0~1に正規化したもの 右->左でxが増加、上->下でyが増加 |
また、SingleEyeData.GetValidity
でこれらの値が正しいかどうか判断できます。目を閉じている状態では、gaze_direction_normalized
やpupil_position_in_sensor_area
が正しく取得できないので使用する際は確認した方がよいかもしれません。
public enum SingleEyeDataValidity : int { /** The validity of the origin of gaze of the eye data */ SINGLE_EYE_DATA_GAZE_ORIGIN_VALIDITY, /** The validity of the direction of gaze of the eye data */ SINGLE_EYE_DATA_GAZE_DIRECTION_VALIDITY, /** The validity of the diameter of gaze of the eye data */ SINGLE_EYE_DATA_PUPIL_DIAMETER_VALIDITY, /** The validity of the openness of the eye data */ SINGLE_EYE_DATA_EYE_OPENNESS_VALIDITY, /** The validity of normalized position of pupil */ SINGLE_EYE_DATA_PUPIL_POSITION_IN_SENSOR_AREA_VALIDITY }; public struct SingleEyeData { . . . . . . . . . . public bool GetValidity(SingleEyeDataValidity validity) { return (eye_data_validata_bit_mask & (ulong)(1 << (int)validity)) > 0; } }
CombinedEyeData
こちらは両目合わせたデータです。
eye_data
ですが、gaze_origin_mm
とgaze_direction_normalized
しか値を取得できませんでした。 (SRanipal_Eye_v2.GetGazeRay
向けと思われる)
また、convergence_distance_validity
ですがずっとfalseの状態でconvergence_distance_mm
が無効でした。サンプル内でも使われている個所はありませんでした。
変数名 | 型 | 解説 |
---|---|---|
eye_data | SigleEyeData | 両方合わせたデータ |
convergence_distance_validity | bool | 収束距離。ずっとfalse |
convergence_distance_mm | float | 収束距離。値を取得できず |
EyeExpression, SingleEyeExpression
これらはv2から追加されたデータです。
始めにEyeExpression
についてです。こちらは右目と左目それぞれのSingleEyeExpression
を保持しています。
変数名 | 型 | 解説 |
---|---|---|
left | SingleEyeExpression | 右目 |
right | SingleEyeExpression | 左目 |
次にSingleEyeExpression
です。
変数名 | 型 | 解説 |
---|---|---|
eye_wide | float | 目の開き具合 |
eye_squeeze | float | 目をギュッと閉じた具合 |
eye_frown | float | しかめっ面具合(値取得できず) |
EyeShape_v2
こちらはenum
型で目を開いているか、閉じているか、右を見ているかなどを表しています。こちらは後述するSRanipal_Eye_v2.GetEyeWeightings
で使われます。
名前 | 意味 |
---|---|
Eye_Left(Right)_Blink | 目を閉じているか |
Eye_Left(Right)_Wide | 目を開けているか |
Eye_Left(Right)_Right | 目が右を見ているか |
Eye_Left(Right)_Left | 目が左を見ているか |
Eye_Left(Right)_Up | 目が上を見ているか |
Eye_Left(Right)_Down | 目が下を見ているか |
Eye_Frown | しかめっ面しているか |
Eye_Left(Right)_Squeeze | 目をギュッと閉じているか(v2のみ) |
トラッキング情報を取得する
SRanipal_Eye_API.GetEyeData_v2
こちらはAPIを呼び出し、EyeData_v2
の情報を取得することができます。
返り値のError
からはアイトラッキングが動作しているか、アイトラッキングが出来るHMDであるかなどが得られます。
/// <summary> /// Gets data from anipal's Eye module. /// </summary> /// <param name="data">ViveSR.anipal.Eye.EyeData</param> /// <returns>Indicates the resulting ViveSR.Error status of this method.</returns> [DllImport("SRanipal")] public static extern Error GetEyeData_v2(ref EyeData_v2 data);
SRanipal_Eye_v2.WrapperRegisterEyeDataCallback
こちらはAPI側にトラッキング情報を取得した際に呼び出すメソッドのポインタを渡します。あとはAPI側がトラッキング情報を取得するたびに自動的にメソッドが呼ばれ、そこでトラッキング情報を受け取ることができます。
注意として呼び出すメソッドはstaticでなければいけません。(staticでない場合はUnityが落ちる)
void Start() { SRanipal_Eye_v2.WrapperRegisterEyeDataCallback( Marshal.GetFunctionPointerForDelegate<SRanipal_Eye_v2.CallbackBasic>(EyeCallback)); } private static void EyeCallback(ref EyeData_v2 eye_data) { _eyeData = eye_data; }
逆に、自動的にメソッドが呼ばれるのをやめるにはSRanipal_Eye_v2.WrapperUnRegisterEyeDataCallback
を使います。
SRanipal_Eye_v2.WrapperUnRegisterEyeDataCallback( Marshal.GetFunctionPointerForDelegate<SRanipal_Eye_v2.CallbackBasic>(EyeCallback));
追記
SRanipal_Eye_API.GetEyeData_v2
と SRanipal_Eye_v2.WrapperRegisterEyeDataCallback
の差についてまとめました。
SRanipal_Eye_v2.GetEyeWeightings
こちらはDictionary<EyeShape_v2, float>
を取得できます。EyeShape_v2
の各要素を0~1の範囲で表します。
関数は2つありまして、1つはEyeData_v2
から計算してそれぞれの値を求める関数です。もう一方はAPIから値を直接受け取る関数です。
/// Gets weighting values from anipal's Eye module when enable eye callback function. public static bool GetEyeWeightings(out Dictionary<EyeShape_v2, float> shapes, EyeData_v2 eye_data) /// Gets weighting values from anipal's Eye module. public static bool GetEyeWeightings(out Dictionary<EyeShape_v2, float> shapes)
最後に
取得できるデータについてまとめると長くなってしまいました。
触ってみての感想ですが、目を動かす・目を開ける閉じるなどは問題なく出来ましたが、ギュッと閉じる・大きく開くなどをするとHMDがずれてしまうのでどこまでトラッキングするか少し考える必要があるのかなと思いました。
少し意外だったことが眼鏡をつけたままでも問題なくトラッキング出来たことです。眼鏡をつけない場合と比べて精度が落ちるかはわかりませんが、特に違和感はありませんでした。
トラッキング情報を取得する以外にもRayを飛ばす機能などもあるので、のちのち触ってみようかなと思います。
追記
SDKに用意されているメソッドについてまとめました。