UnityでOculus Quest2(Meta Quest2)を動かしてVRを楽しむ（準備編Tips）

はじめての投稿になります。よろしくお願いします。

Oculus Rift S、Oculus Quest2（今はMeta Quest2）とVRを手に入れて一通り遊んだ後、自分でコンテンツを作れないか情報収集して試してみました。その結果を箇条書きにまとめて記録（Tips）を残します。
また、コントローラーでの視線移動を補完するスクリプトを追加してみましたので、掲載します。視線移動があると、座ったり寝ころんだりしたまま、いろいろなアングルが楽しめます。
UnityやOculus Integrationのバージョンにより操作が変わると思いますので、最新状況を更新できればと思います。
なお、Meta Quest3での動作も確認しましたが、気になる点はありませんでした。

【更新記録】
2024.5.20  一部記事を修正しました。
2022.6.12　記事を修正しました。
2022.5.24　改造コードの掲載を修正しました。
2022.5.22　投稿しました。

# 開発環境
PC OS:Windows 10
Unity: Unity 2021.3.2f1
Device: Oculus Quest2、Meta Quest3
Oculus Integration: Version 39.0  
グラフィックボード：NVIDIA geforce RTX 2060  
※グラフィックボードはPCでAir Linkするために必須です。  
最近のRTX3050だとソフトが拒否して動きませんでした。  
ゲーミングノートPCでもRTX3060は動きました。  
もし、購入されるようでしたら、事前にメーカーサイトを確認することをお勧めします。 

# 手順概要
1　環境整備
2　プロジェクト作成
3　Oculus Integration のimport
4　build settings
5　VRの視点であるカメラの設置
6　コンテンツ作成開始

# １　環境整備
## Unityのインストール
・ダウンロードサイトからUnityを入手してインストール
https://unity.com/
## Oculus Quest2の設定
 ~~・OculusQuest2本体を開発者モードにする。
（Unityで実機テストするために必要。スマホにOculusアプリをインストールして、Wi-Fiでつなぎ、オンにして開発者登録をして設定。）
・Windowsにoculusquest用のusbドライバ（Oculus ADB Drivers）をインストール
https://developer.oculus.com/downloads/package/oculus-adb-drivers
・「設定」‐「試験中」の Air Linkの設定変更（USB経由の場合はオフ）
※Unity上で実機テストするためにはUSB接続が必須。（不便だけど、Unity上ではなく毎回ビルドしてWi-FiのAirLinkで動かすならUSB接続や開発者モードは不要。なおUSBケーブルは純正じゃなくてもOK。ただし、充電ケーブルはもちろんNG。）~~
※PCとQuestをつなぐ ~~Air~~ Quest Linkのソフトウェアをダウンロードするサイトは
https://store.facebook.com/jp/ja/quest/setup/
PCとQuestをWifiやUSBでつないで、Quest Linkでつなげれば実機テストができます。

# 2　プロジェクト作成
・UnityHubを起動して、プロジェクトを作成 ~~（無難に「３D」を選んでいる）~~
 ~~＊「VR」のテンプレがあるがOculusQuestがすぐ使える状態にはならない。~~
 最新のUnityでは「VR」のテンプレートでつながるようになります。
# 3　Oculus Integration のimport
・「VR」テンプレートを使わなかった場合、Unityのアセットストアから「Oculus Integration」をダウンロードしてインポート。（とりあえずすべてインポートしている）
Unityのメニューバーの「Window」-「Asset Store」から
# 4　build settings
## プラットフォームを選ぶ
・「Windows,Mac,Linux」はPCで起動してAirLinkでつなげるアプリ

 ~~・「Android」はOculusQuest2に直接インストールするアプリ
※「Android」を選んだ場合、「TextureCompression」は「ASTC」に設定。~~
Meta QuestのOS変更によりAndroidでのインストールはできなくなりました。

## Player Settingsでの設定（「VR」テンプレートを使わなかった場合）
・「XR Plug-in Management」をクリックして有効にし、「Plug-in Providers」を「Oculus」に設定する。（※Android Settingだけではなく、Windows,Mac,Linux settingも「Oculus」にしないと実機テストができない。）
・「Oculus」の設定で「StereoRenderingMode」は「MultiPass」に設定（SinglePass...だと２体目のモデルが表示されないことがあった。）
・「Player」の「CursorHotspot」のタブを選び、OtherSettingsの項目を設定（テンプレ等により初期設定が異なるため、ポイントだけ列記）
→RenderingのColorSpace・・・「Linear」にする
→IdentificationのOverrideDefaultPackageNameのチェックとPackageName　・・・デフォルトでよければチェックを外す。
→ConfigurationのScriptingBackend・・・「IL2CPP」にする
→ConfigurationのTarget Architectures・・・「ARM64」をチェック（「IL2CPP」を選択した場合必須）
※プロジェクト作成の折、最初に微調整している。この時点で実行して実機に写るか一度確認します。
# 5　VRの視点であるカメラの設置
カメラのPrefabs「OVRPlayerController」または「OVRCameraRig」をHierarchyに設置・調整する。
UnityでProjectのAssetsの「Oculus」‐「VR」‐「Prefabs」から「OVRPlayerController」または「OVRCameraRig」をHierarchyにドラッグアンドドロップする。簡単に要約すると「OVRPlayerController」は視点移動が可能で「OVRCameraRig」も含まれているが、「OVRCameraRig」だけだと固定点で動かせない。
## 設置した「OVRCameraRig」の設定の調整
→OVR ManagerにあるTrackingのTrackingOriginTypeを「FloorLevel」にする（床から測るので、UsePositionTrackingのチェックをしているとき正確な視点になる。）
→OVR ManagerにあるDisplayのColorGamutを「Quest」にする。
## 設置した「OVRPlayerController」の設定の調整
OVR PlayerControllerを調整することで、コントローラーの操作が変更できます。デフォルトでは、左コントローラーで位置の移動、右コントローラーの左右で視点左右移動ができます。
右コントローラで視線の方向やA・Bボタンで目線の高さを変更するスクリプトの改造のコードを下記に載せます。

### 右のコントローラーAとBで視点位置を上下するコード改造
１　目線の位置を記憶する関数を定義

~~~OVRPlayerController.cs(抜粋 162行に追加)
	private bool playerControllerEnabled = false;

//User Add Code 目線の高さ　定義
	public float HighPos;
//ここまで

	void Start()
~~~
~~~OVRPlayerController.cs(抜粋 170行に追加)
		CameraRig.transform.localPosition = p;

//User Add Code 目線の高さ　初期化
		HighPos = 0.0f;
//ここまで
	}
~~~
２　目線の高さを調整するための修正
~~~OVRPlayerController.cs(抜粋 264行を変更)
			if (OVRManager.instance.trackingOriginType == OVRManager.TrackingOrigin.EyeLevel)
			{
				p.y = OVRManager.profile.eyeHeight - (0.5f * Controller.height) + Controller.center.y + (HighPos * Controller.height);//User Change Code 目線の高さ 修正
			}
			else if (OVRManager.instance.trackingOriginType == OVRManager.TrackingOrigin.FloorLevel)
			{
				p.y = -(0.5f * Controller.height) + Controller.center.y + (HighPos * Controller.height);//User Change Code 目線の高さ 修正
			}
			CameraRig.transform.localPosition = p;
~~~
３　入力の追加の定義
~~~OVRPlayerController.cs(抜粋 348行を追加)
			bool moveBack = Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow);
			bool moveK = Input.GetKey(KeyCode.K) || OVRInput.Get(OVRInput.Button.One);		//User Add Code
			bool moveL = Input.GetKey(KeyCode.L) || OVRInput.Get(OVRInput.Button.Two);		//User Add Code
			bool moveO = Input.GetKey(KeyCode.O) || OVRInput.Get(OVRInput.Button.Three);	//User Add Code

			bool dpad_move = false;
~~~
４　入力による高さの変数の値を変更
~~~OVRPlayerController.cs(抜粋 399行を追加)
			if (moveRight)
				MoveThrottle += ort * (transform.lossyScale.x * moveInfluence * BackAndSideDampen * Vector3.right);
//User Add Code 目線の高さ入力
			if (moveK)
				HighPos -= 2.0f * moveInfluence * BackAndSideDampen;
			if (moveL)
				HighPos += 2.0f * moveInfluence * BackAndSideDampen;
			if (moveO)
				HighPos = 0.0f;
//ここまで

			moveInfluence = Acceleration * 0.1f * MoveScale * MoveScaleMultiplier;
~~~

### 右コントローラーで目線の方向を変えるためのコード改造

~~~OVRPlayerController.cs(抜粋 467行から修正・追加)
			if (SnapRotation)
			{
				if (OVRInput.Get(OVRInput.Button.SecondaryThumbstickLeft) ||
					(RotationEitherThumbstick && OVRInput.Get(OVRInput.Button.PrimaryThumbstickLeft)))
				{
					if (ReadyToSnapTurn)
					{
						euler.y -= RotationRatchet;
						//ReadyToSnapTurn = false;　スムーズにするためコメントアウト
					}
				}
				else if (OVRInput.Get(OVRInput.Button.SecondaryThumbstickRight) ||
					(RotationEitherThumbstick && OVRInput.Get(OVRInput.Button.PrimaryThumbstickRight)))
				{
					if (ReadyToSnapTurn)
					{
						euler.y += RotationRatchet;
						//ReadyToSnapTurn = false;　スムーズにするためコメントアウト
					}
				}
//User Add Code 右コントローラー上下で目線移動
				else if (OVRInput.Get(OVRInput.Button.SecondaryThumbstickUp) ||
					(RotationEitherThumbstick && OVRInput.Get(OVRInput.Button.PrimaryThumbstickUp)))
				{
					if (ReadyToSnapTurn)
					{
						euler.x -= RotationRatchet;
					}
				}
				else if (OVRInput.Get(OVRInput.Button.SecondaryThumbstickDown) ||
					(RotationEitherThumbstick && OVRInput.Get(OVRInput.Button.PrimaryThumbstickDown)))
				{
					if (ReadyToSnapTurn)
					{
						euler.x += RotationRatchet;
					}
				}
//ここまで
				else
				{
					ReadyToSnapTurn = true;
				}
			}
~~~

※なお、右コントローラーの視点移動をスムーズにするためには、RotationAmountとRotationRatchetを小さく（0.1～0.5）に設定します。

※この時点でも実行して実機に写るか確認します。
# 6　コンテンツ作成開始
コンテンツの作成を開始します。

## 試してみたコンテンツ
1 『Oculus Riftでオレの嫁と会える本 UnityとMMDモデルで作る初めてのバーチャルリアリティ』（ISBN 978-4-7981-3746-9） 翔泳社  
![pri_sc_MMD.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2608747/37848c80-eb7f-da77-d073-b1d9bab4da9e.png)
2014年出版の書籍（Unity4の時代）ですが、MMDモデルを使ってVRを楽しむソフトが作れました（Unity 2021.3.2f1にて作成。著者ホームページ https://aichina3.com/ でご確認いただけます。）
ただ、開発の肝であるMMD4Mecanim 2020/01/05 版(β)の更新が止まっているため、新しいバージョンのUnityでうまく作成できない現象が起きています。（例：Unity 2022.3.29f1ではピンク一色になる）

2 Oculus　Questアプリ開発　Unityで作るVR　Questで３Dモデルを眺める方法」HONDAsoft Kindle版
HONDAsoft http://hondasoft.com/  
![pri_sc_Fureai.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2608747/21db79f8-7e9d-6699-37a3-4ec6b1b22d0d.png)

※体を動かしてそこに実物があることを表現するVRの趣旨からしたらこの改造は反則気味ですが、頭で考えた通り＝思い通りに画面が動く方が案外酔わないと、VR酔いの酷い私だけかもしれませんが思いました。