[ViveProEye] SRanipal SDKで取得可能な眼球運動情報

#はじめに
ViveProEyeとUnityを使って眼球運動を計測する際に[SRanipal SDK](https://developer.vive.com/resources/knowledgebase/vive-sranipal-sdk/)を使用します。
同封されているドキュメントを参考にしながら動かしてみてまとめました。
不明な点については今後追記していきます。

#環境
SRanipal SDK 1.0.1.0
SR_Runtime 1.0.3.0

# 取得可能な情報
**EyeData : 眼球情報**

- int frame_sequence : フレームシーケンス(Unityの再生時間に関連？)
- bool no_user : HMDを被っているか (True:被っている, False:被っていない)
- int timestamp : フレームがキャプチャしていた時間(ミリ秒)(実時間に関連？)
- VerboseData verbose_data : 詳細情報

**VerboseData : 詳細情報**

- CombinedEyeData combined : 両目？
- SingleEyeData left : 左目
- SingleEyeData right : 右目
- TrackingImprovements tracking_improvements

**CombinedEyeData : 両眼情報?**

- float convergence_distance_mm : 収束距離(メートルマイル)[取得不可？]
- bool convergence_distance_validity : convergence_distance_mmのデータが有効か[取得不可？]
- SingleEyeData eye_data

**SingleEyeData : 単眼情報**

- ulong eye_data_validata_bit_mask : 計測データが有効であるか
- float eye_openness [0-1] : 目の開閉具合(0:閉じている, 1:開いている)
- Vector3 gaze_direction_normalized :　正規化された視線ベクトル(右手座標系)
- Vector3 gaze_origin_mm : 注視点の原点となる眼の中の位置(メートルマイル)(右手座標系)
- float pupil_diameter_mm : 瞳孔径(メートルマイル)
- Vector2 pupil_position_in_sensor_area : 正規化された瞳孔の位置

**TrackingImprovements : トラッキング改善**
- int count : itemsの数？
- TrackingImprovement[] items

**TrackingImprovement**
?

# 取得方法
関数などを用いて取得する方法です

## 眼球運動情報
**ViveSR.Error SRanipal_Eye.GetEyeData(ref EyeData eyeData)**

```csharp
EyeData eyeData;
if (SRanipal_Eye.GetEyeData(ref eyeData) == ViveSR.Error.WORK) {
// 取得したときの処理
}
```
眼球運動の取得ができているかが返ってくる
(DEVICE_NOT_FOUNDやTIMEOUTなど詳細な情報が返ってくるように設計されている)

 - ViveSR.Error.WORK：取得できている
 - その他：取得できていない

以下の多くの情報はこの関数で取得したeyeDataからも取得可能

## 目の開閉状態
**bool SRanipal_Eye.GetEyeOpenness(EyeIndex eyeIndex, out float eye_openness)**

```csharp
float eye_openness_L, eye_openness_R;
SRanipal_Eye.GetEyeOpenness(EyeIndex.LEFT, out eye_openness_L);
SRanipal_Eye.GetEyeOpenness(EyeIndex.RIGHT, out eye_openness_R);
```

<!-- // eyeDataから取得
eye_openness_L = eyeData.verbose_data.left.eye_openness;
eye_openness_R = eyeData.verbose_data.right.eye_openness; -->


## 瞳孔位置情報
**bool SRanipal_Eye.GetPupilPosition(EyeIndex eyeIndex, out Vector2 position)**

```csharp
Vector2 position_L, position_R;
SRanipal_Eye.GetPupilPosition(EyeIndex.LEFT, out position_L);
SRanipal_Eye.GetPupilPosition(EyeIndex.RIGHT, out position_R);
```

<!-- // eyeDataから取得
position_L = eyeData.verbose_data.left.pupil_position_in_sensor_area;
position_R = eyeData.verbose_data.right.pupil_position_in_sensor_area; -->

## 視線情報
**bool SRanipal_Eye.GetGazeRay(GazeIndex gazeIndex, out Ray ray)**
**bool SRanipal_Eye.GetGazeRay(GazeIndex gazeIndex, out Vector3 origin, out Vector3 direction)**

```csharp
Ray ray_L, ray_R, ray_C;
SRanipal_Eye.GetGazeRay(GazeIndex.LEFT, out ray_L);
SRanipal_Eye.GetGazeRay(GazeIndex.RIGHT, out ray_R);
SRanipal_Eye.GetGazeRay(GazeIndex.COMBINE, out ray_C);
```

<!-- // eyeDataから取得
Vector3 origin_L = eyeData.verbose_data.left.gaze_origin_mm;
Vector3 origin_R = eyeData.verbose_data.right.gaze_origin_mm;
Vector3 direction_L = eyeData.verbose_data.left.gaze_direction_normalized;
Vector3 direction_R = eyeData.verbose_data.right.gaze_direction_normalized; -->

Ray : 視線情報

- Vector3 origin : レイの起点
- Vector3 direction : レイの方向

## 焦点情報
**bool SRanipal_Eye.Focus(GazeIndex gazeIndex, out Ray ray, out FocusInfo focusInfo, float radius, float maxDistance)**
radius, maxDistanceは省略可
焦点がColliderがついたオブジェクトに当たったときのみ取得でき, 戻り値がtrueになる

```csharp
Ray ray_L, ray_R, ray_C;
FocusInfo info_L, info_R, info_C;
SRanipal_Eye.Focus(GazeIndex.LEFT, out ray_L, out info_L);
SRanipal_Eye.Focus(GazeIndex.RIGHT, out ray_R, out info_R);
SRanipal_Eye.Focus(GazeIndex.COMBINE, out ray_C, out info_C);
```

FocusInfo : 焦点情報

- Vector3 normal
- float distance : 焦点までの距離?
- Vector3 point : 焦点位置
- Collider collider : 衝突したオブジェクトのCollider
- Rigidbody rigidbody 
- Transform transform

## その他
**ViveSR.Error SRanipal_Eye.GetEyeParameter(ref EyeParameter parameter)**
anipal's Eye moduleのparameterを取得する

EyeParameter

- GazeRayParameter gaze_ray_parameter
    - double sensitive_factor

**bool SRanipal_Eye.GetVerboseData(out VerboseData data)**
anipal's Eye moduleのVerboseDataを取得する

**bool SRanipal_Eye.IsViveProEye()**
HMDがViveProEyeか

**int SRanipal_Eye.IsUserNeedCalibration(ref bool need)**
キャリブレーションが必要か

**bool SRanipal_Eye.LaunchEyeCalibration()**
キャリブレーションをおこなう

**ViveSR.Error SRanipal_Eye.SetEyeParameter(EyeParameter parameter)**
anipal's Eye moduleのparameterを設定する

**bool SRanipal_Eye.TrayGaze(SingleEyeDataValidity validity, out GazeIndex gazeIndex);**
視線情報の検証をおこなう

# その他メモ
- Unityは左手座標系([座標系変換](http://k-key.hatenablog.com/entry/2016/08/18/141830))
- サンプリングレートは計測してみた結果, おおよそ120Hzだった

以下, 公式フォーラムでの回答の内容を一部掲載

- キャリブレーションの設定などは開発者が弄ることができない <br>
-> キャリブレーションの精度はヘッドセット位置とIPDに大きく依存

# 関連リンク
[開発者フォーラム](https://community.viveport.com/t5/Vive-SRanipal-SDK/bd-p/Vive-SRanipal-SDK)
[公式のスライド](https://developer.download.nvidia.com/video/gputechconf/gtc/2019/presentation/s91047-vive-pro-eye-tracking-and-foveated-rendering-with-vrs-presented-by-htc-vive.pdf)