#7「ヘッドマウントディスプレイとコントローラの位置座標と回転を取得する」【初心者】HTC VIVE Pro Eyeを使ってUnityでVRの開発を行ってみる．

#はじめに

[前回](https://qiita.com/RyoyaHase/items/81fa026f68aee02fa5d4)まででコントローラの入力を取得したので今回はコントローラとHMDの位置と回転を取得していきます．プログラムの書き方などに関しては前回の記事を読んでください．

環境一覧
[SteamVR](https://store.steampowered.com/app/250820/SteamVR/?l=japanese) 1.16.10
[Unity](https://unity3d.com/jp/get-unity/download) 2019.4.27f1 or 2020.1.17f1（動作確認済み，非対応なSDKあり）

[SteamVR Plugin](https://assetstore.unity.com/packages/tools/integration/steamvr-plugin-32647) 2.7.3
[Vive SRanipalRuntime Plugin](https://hub.vive.com/en-US/download) 1.3.2.0


追加アクセサリー
[VIVEトラッカー2018](https://www.amazon.co.jp/dp/B0748ZY323/ref=cm_sw_r_tw_dp_QDZSM4A3844PSM33DB3R?_encoding=UTF8&psc=1)
[Ovrvision Pro（ステレオカメラ）](https://www.amazon.co.jp/dp/B01N7H8YUM/ref=cm_sw_em_r_mt_dp_6TGRDF5BWQPW2PJ1H4WN)
[Leap Motion](https://www.amazon.co.jp/Leap-Motion-Controller/dp/B075T4MH77/ref=asc_df_B075T4MH77/?tag=jpgo-22&linkCode=df0&hvadid=342463500927&hvpos=&hvnetw=g&hvrand=13721783060484696807&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009320&hvtargid=pla-945077929421&psc=1)


使用PCスペック
インテル® Core™ i7-7700K
NVIDIA GeForce GTX 1070

- **環境作成編**

 #1 [Unityのセットアップをする](https://qiita.com/RyoyaHase/items/5a173b7acbdf9aa2cfff)　2021年 1月更新

 #2 [プロジェクトを作ってみる](https://qiita.com/RyoyaHase/items/7b2148e9034584db7420)　2021年 1月更新

 #3-α [Unity2019でVR開発のための環境を整える（SteamVR Plugin2.7.Xをインストールする）：推奨](https://qiita.com/RyoyaHase/items/36910ec8a0b3d8122f8c)　2021年 6月更新

 #3-β [Unity2020でVR開発のための環境を整える（SteamVR Plugin2.7.Xをインストールする）](https://qiita.com/RyoyaHase/items/b7b5f8a7110810c1c0f1)　2021年 5月更新

 #3-おまけ [UnityでVR開発のための環境を整える（SteamVR Pluginの最新版をインストールする）：非推奨](https://qiita.com/RyoyaHase/items/f8b4fb5b04d9f02aae49)　2021年 2月更新

 #4 [SteamVRのダウングレードと自動アップデートの停止（上級者向け）](https://qiita.com/RyoyaHase/items/0dab278b080f517032a0)　2021年 5月更新


- **コントローラの入力やトラッカー，HMDの位置座標，回転座標を得る＋α**

 #5 [VIVEコントローラのボタン入力を取得する](https://qiita.com/RyoyaHase/items/89ffc9d134b784b8ae50)　2021年 2月更新

 #6 [トリガーの押し具合やトラックパッドの位置情報の入力を取得する](https://qiita.com/RyoyaHase/items/81fa026f68aee02fa5d4)　2021年 2月更新

 #6-おまけ [VIVEコントローラを使った開発をする時のおすすめ設定（独断と偏見）](https://qiita.com/RyoyaHase/items/d622e1bb0e345cf78f4f)　2021年 5月更新

 #7 [__ヘッドマウントディスプレイとコントローラの位置座標と回転を取得する（この記事）__](https://qiita.com/RyoyaHase/items/325e7250c01f47e7e63b)　2021年 2月更新

 #8 [VIVEトラッカー2018を有効化してUnity上で位置座標と回転を取得](https://qiita.com/RyoyaHase/items/015bbb8671833ef8e740)　2021年 5月更新

 #9 [VIVEコントローラの振動機能を開発してみる](https://qiita.com/RyoyaHase/items/0690761fed2e71f6d517)　2021年 4月更新


- **VIVE Pro Eyeのアイトラッキングを使ってみる**

 #10 [VIVE Pro Eyeの視線トラッキングを有効化（セットアップ）する](https://qiita.com/RyoyaHase/items/024f3589547d1af84a92)　2021年 4月更新

 #11 [VIVE Pro Eyeのアイトラッキングを使ってUnity上で瞬きや視線のデータを取得する](https://qiita.com/RyoyaHase/items/5af948666a039d48a68d)　2021年 4月更新

 #11-おまけ [VIVE Pro Eyeのアイトラッキングで計測できるデータについて（適宜更新）](https://qiita.com/RyoyaHase/items/044826488e763f896a0f)　2021年 4月更新


- **VIVE Pro Eyeのカメラを使ってみる**

 #12 [VIVE Pro Eyeのフロントカメラの解像度（性能）とAR機能を有効化について](https://qiita.com/RyoyaHase/items/853938ec7c8745ec811c)　2021年 5月更新


- **小技**

 [プレイエリアの境界線（シャペロン境界）が表示されないように設定を変更する](https://qiita.com/RyoyaHase/items/57296d7753877afc6f34)　2021年 6月更新

 [Unity上でカメラを複数台追加してHMDやコントローラの動きを見る](https://qiita.com/RyoyaHase/items/4b4733503d53c8387db4)　2021年 6月更新


- **Ovrvision Pro（ステレオカメラ）を使ってAR開発してみる**

 ＄1-1 [Ovrvision Pro（ステレオカメラ）のセットアップをして実際に動かしてみる](https://qiita.com/RyoyaHase/items/262ad2133ee89d00b3cb)　2021年 6月更新

 ＄1-2 [Ovrvision Pro（ステレオカメラ）とHMDを使ってARアプリ開発する](https://qiita.com/RyoyaHase/items/4abcd90f0f2319c89114)　2021年 6月更新

- **Leap Motionを使ってハンドトラッキングしてみる**

 ＄2-1 [Leap Motion（ハンドトラッキング）のセットアップをして実際に動かしてみる](https://qiita.com/RyoyaHase/items/6891c21c8c21dcb08b2f)　2021年 6月更新

 ＄2-2 [Leap Motion（ハンドトラッキング）とHMDを使ったインタラクティブなアプリ開発する](https://qiita.com/RyoyaHase/items/b0f6cd1d7474286f99ed)　2021年 6月更新

- **アプリを作ってみる**

  [VR（仮想空間）上に曲面ディスプレイを作成して大画面で広角WEBカメラ映像を見る](https://qiita.com/RyoyaHase/items/cc57e67799c1b14ef15d)　2021年 5月更新



今回の記事では，

1．ヘッドマウントディスプレイとコントローラの位置座標と回転を取得する．
2．位置座標の基準について（どこが起点になっているのか）．
3．取得したデータを使ってエリア内を移動する．


という流れ．

#1．ヘッドマウントディスプレイとコントローラの位置座標と回転を取得する．

前回までと違ってUnityEngine.XRを使って値を取っていきます．
SteamVR Pluginのバージョンが上がって仕様が変わったらしく，きれいに書き直すのに苦労しました．

前回と同様にposという名前でC#スクリプトを作成して適当なオブジェクトに追加します．この辺の操作は前回記事を見てください．
回転の値はなぜかQuaternionというx,y,z,wという4つの値で入っています．Quaternion 型は x,y,z,w の4軸値で回転を表現する型ですが基本的に中身を見ても意味が分かりません．
なのでオイラー型に.eulerAnglesを使って変換し，内容を触ったらクォータニオンに戻して代入します．
各機器が動いてるかをしっかりと確認する場合にはDebug.Logを適宜コメントアウトして確認してください．

```C#:pos.cs
using System;
using UnityEngine;
using UnityEngine.XR;
using Valve.VR;


public class pos : MonoBehaviour
{
    //HMDの位置座標格納用
    private Vector3 HMDPosition;
    //HMDの回転座標格納用（クォータニオン）
    private Quaternion HMDRotationQ;
    //HMDの回転座標格納用（オイラー角）
    private Vector3 HMDRotation;

    //左コントローラの位置座標格納用
    private Vector3 LeftHandPosition;
    //左コントローラの回転座標格納用（クォータニオン）
    private Quaternion LeftHandRotationQ;
    //左コントローラの回転座標格納用
    private Vector3 LeftHandRotation;

    //右コントローラの位置座標格納用
    private Vector3 RightHandPosition;
    //右コントローラの回転座標格納用（クォータニオン）
    private Quaternion RightHandRotationQ;
    //右コントローラの回転座標格納用
    private Vector3 RightHandRotation;

    //1フレーム毎に呼び出されるUpdateメゾット
    void Update()
    {

        /*InputTracking.GetLocalPosition(XRNode.機器名)で機器の位置や向きを呼び出せる*/

        //Head（ヘッドマウンドディスプレイ）の情報を一時保管-----------
        //位置座標を取得
        HMDPosition = InputTracking.GetLocalPosition(XRNode.Head);
        //回転座標をクォータニオンで値を受け取る
        HMDRotationQ = InputTracking.GetLocalRotation(XRNode.Head);
        //取得した値をクォータニオン → オイラー角に変換
        HMDRotation = HMDRotationQ.eulerAngles;
        //--------------------------------------------------------------


        //LeftHand（左コントローラ）の情報を一時保管--------------------
        //位置座標を取得
        LeftHandPosition = InputTracking.GetLocalPosition(XRNode.LeftHand);
        //回転座標をクォータニオンで値を受け取る
        LeftHandRotationQ = InputTracking.GetLocalRotation(XRNode.LeftHand);
        //取得した値をクォータニオン → オイラー角に変換
        LeftHandRotation = LeftHandRotationQ.eulerAngles;
        //--------------------------------------------------------------


        //RightHand（右コントローラ）の情報を一時保管--------------------
        //位置座標を取得
        RightHandPosition = InputTracking.GetLocalPosition(XRNode.RightHand);
        //回転座標をクォータニオンで値を受け取る
        RightHandRotationQ = InputTracking.GetLocalRotation(XRNode.RightHand);
        //取得した値をクォータニオン → オイラー角に変換
        RightHandRotation = RightHandRotationQ.eulerAngles;
        //--------------------------------------------------------------


        //取得したデータを表示（HMDP：HMD位置，HMDR：HMD回転，LFHR：左コン位置，LFHR：左コン回転，RGHP：右コン位置，RGHR：右コン回転）
        Debug.Log("HMDP:" + HMDPosition.x + ", " + HMDPosition.y + ", " + HMDPosition.z + "\n" +
                    "HMDR:" + HMDRotation.x + ", " + HMDRotation.y + ", " + HMDRotation.z);
        Debug.Log("LFHP:" + LeftHandPosition.x + ", " + LeftHandPosition.y + ", " + LeftHandPosition.z + "\n" +
                    "LFHR:" + LeftHandRotation.x + ", " + LeftHandRotation.y + ", " + LeftHandRotation.z);
        Debug.Log("RGHP:" + RightHandPosition.x + ", " + RightHandPosition.y + ", " + RightHandPosition.z + "\n" +
                    "RGHR:" + RightHandRotation.x + ", " + RightHandRotation.y + ", " + RightHandRotation.z);
    }
}
```

全てなんらかの値が入っていれば問題なく動いてます．検知されてないと0, 0, 0となります．
起動直後は値が入ってないことがありますが少し待てば機器が検知されて値が取得されます．（1～5秒ぐらい）

![01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758746/48587b84-a8a4-fa8d-a512-5b079f96b42e.gif)

#2．位置座標の基準について（どこが起点になっているのか）．

ここで出力されている座標は最初に自身で設定したルームセットアップを基に出力されています．
![04.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758746/ac05d219-ccac-e42b-b6c2-6e61196c05eb.jpeg)

もうセットアップが完了しており，設定したプレイエリアの確認をした場合にはSteamVRを起動します．
SteamVRホームが開くのでメニューを開き左下のタブから「STEANVRホームを終了」を選択します．
![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758746/11a24018-1c12-b6e6-7f17-a3948a75702d.png)
![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758746/d819e263-a9bb-ce4b-6278-74b8bb93f17c.png)

初期設定では背景が夕焼け空の世界が表示されます．
![07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758746/0941b011-ceee-5520-9e2e-7b14344438a0.png)

足元を見ると設定したプレイエリアの中心から放射状に線が伸びており，放射線の中心が座標の起点（0,0）となっています．
また，矢印のある線が正面を表しているのでこれに従ってローカルの座標は変化しています．
Unity上の座標もこの設定に従っているのでUnity上での開始位置がずれる時はこの画面から正面と向きを確認して立ち位置をテープ等で印付けしておくといいと思います．
![08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758746/a5ced05d-60d4-0beb-2ed0-09e97bcef3be.png)

もし向きや中心位置を変更したい場合はプレイエリアの設定時に編集できるので再度セットアップしてください．
![09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758746/e2336725-166d-5e50-bffb-c231e1e4be9e.png)



#3．取得したデータを使ってエリア内を移動する．

今回はトリガーの入力とHMDの回転を使ってエリアを歩き回ります．
いつも通りwalkという名前でC#スクリプトを作成して[CaneraRig]に追加する．
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758746/fac73eab-d81d-066c-ce00-a72aa8013b00.png)

this.transform.を使うとスクリプトを追加したオブジェクトの位置や角度を変更できます．
若干角度がずれることがありますので調整しといてくだい．ゲームを作成して配布する時は初期位置を取得して調節してください．

```C#:walk.cs
using System;
using UnityEngine;
using UnityEngine.XR;
using Valve.VR;

//クラス名はファイル名（今回はTrigerPull）
public class walk : MonoBehaviour
{
    //HMDの位置座標格納用
    private Vector3 HMDPosition;
    //HMDの回転座標格納用（クォータニオン）
    private Quaternion HMDRotationQ;
    //HMDの回転座標格納用（オイラー角）
    private Vector3 HMDRotation;

    //トリガーがどれだけ押されているのかを取得するためのtriggerpullという関数にSteamVR_Actions.default_TriggerPullを固定
    private SteamVR_Action_Single triggerpull = SteamVR_Actions.default_TriggerPull;
    //結果の格納用floot型関数
    private float pullleft, pullright;

    //1フレーム毎に呼び出されるUpdateメゾット
    void Update()
    {
        //結果をGetLastAxisで取得してpullleftに格納
        //SteamVR_Input_Sources.機器名（ここは左コントローラ）
        pullleft = triggerpull.GetLastAxis(SteamVR_Input_Sources.LeftHand);
        //pullleftの中身を確認
        Debug.Log("Left:" + pullleft);

        //Head（ヘッドマウンドディスプレイ）の情報を一時保管-----------
        //位置座標を取得
        HMDPosition = InputTracking.GetLocalPosition(XRNode.Head);
        //回転座標をクォータニオンで値を受け取る
        HMDRotationQ = InputTracking.GetLocalRotation(XRNode.Head);
        //取得した値をクォータニオン → オイラー角に変換
        HMDRotation = HMDRotationQ.eulerAngles;
        //--------------------------------------------------------------

        Debug.Log("Left:" + pullleft);

        Debug.Log("HMDP:" + HMDPosition.x + ", " + HMDPosition.y + ", " + HMDPosition.z + "\n" +
            "HMDR:" + HMDRotation.x + ", " + HMDRotation.y + ", " + HMDRotation.z);

        //トリガーの情報をVector3で入力
        Vector3 changePosition = new Vector3(pullleft, 0, 0);
        //HMDのY軸の角度取得して90度ずらす
        Vector3 changeRotation = new Vector3(0, HMDRotation.y - 90, 0);
        //[CameraRig]の位置変更
        this.transform.position += this.transform.rotation * (Quaternion.Euler(changeRotation) * changePosition / 50);
    }
}
```

これで左コントローラのレバーを押せば向いた方向に歩いて行けます．レバーの押し込み具合でスピードも変わります．あまりやりすぎると酔うので注意してください．
![03.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758746/10689c28-d281-e898-ea21-882a0e9d7947.gif)

これでVR開発の基礎的な入力をすべて取得できました．あとは普通のゲーム開発の資料を見ながら開発できるようになるので資料がたくさんあってだいぶ楽になります．
 [次回](https://qiita.com/RyoyaHase/items/015bbb8671833ef8e740)は機能拡張用のトラッカー2018を実際にペアリングして位置情報を取得します．