Unity2021.2.4f1のURPで、OpenXRのみでVRアプリ開発をする

#概要
こんにちは！
VRChatを中心にXR関係の活動をしているサックーと申します。
これはUnity2021.2.4f1のURPで、OpenXRのみでマルチプラットフォームVRアプリ開発をした記録になります。
[Iwaken Lab.「好きな技術・コト」 Advent Calendar 2021](https://qiita.com/advent-calendar/2021/iwakenlab)の11日目の記事です。
動機としては、買ったけど眠らせてた[HDRP・URP限定のインタラクティブな水アセット](https://assetstore.unity.com/packages/vfx/shaders/simple-interactive-water-for-urp-hdrp-vr-162033)をVRで使いたいというものです。
ついでに色々整ってきた[OpenXR](https://www.khronos.org/openxr/)だけを使って、SteamVR PluginやOculus Integration抜きでマルチデバイスなアプリにしてみようと欲張ってみました。

### 使用する技術

- Unity2021.2.4f1
- OpenXR Version 1.2.8
- XR Interaction Toolkit Version 2.0.0-pre.5

# 流れ
- OpenXRを使って基本のVRアプリセッティング
- アセットを使って中身を作る
    - アバターのセットアップ
    - おまけ

# とりあえずVRアプリにする
OpenXRでVRアプリを作る基本については、こりんさんのこちらのページ
[Unity VR開発メモ（XR Interaction Toolkit + OpenXR Plugin）](https://framesynthesis.jp/tech/unity/xr/)
を参照してください。情報が早くて網羅的な神ページです。

「Oculus Questで実行できるようにする」というところまで設定を進めてください。
一部写真を追加して補足します。

### プロジェクト作成の補足
Unity2021.2から？URPのコアテンプレートが追加されました。
サンプルシーンはないので余計なデータなしで簡単にURPプロジェクトを開始できます。
と思ってコアで作ったらAndroidビルドで件の水シェーダーがうまく動かなかったので、まだサンプルのテンプレートの方がいいかもしれません。
![スクリーンショット 2021-12-04 133827.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/830fb8e5-0fb5-1be5-5e86-975c9c17ebd4.png)

### XR Interaction Toolkitのインストールについて補足
Package Manager右上の歯車からAdvanced Project Settingsをクリックして、Enable Pre-release Packagesをオンにするところ。
![スクリーンショット 2021-12-10 194327.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/1bdd22b4-6472-c5ff-f7c2-da5a9d0f7f40.png)
Package Manager左上の＋ボタンからAdd package from git URL…で「com.unity.xr.interaction.toolkit」を追加するところ
![スクリーンショット 2021-12-04 133839.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/706186bd-98ee-1771-2098-712e6c495112.png)

ここまででおそらくとりあえずHMDをつないで実行したら6DoFで動いてくれるとは思います。
一点注意として実際にビルドするときはScene in Buildにビルドするシーンを追加し忘れないようにしましょう！！！
当たり前のことなんですがVRChatのワールド開発ばかりやってたせいですっかり忘れてました(2時間くらい溶かした…)
![スクリーンショット 2021-12-10 214047.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/8d49d87d-9b4d-bf4f-c373-7f6985933875.png)

## コントローラーで動けるようにする
最後にコントローラーで空間を動けるようにしましょう。
適当なオブジェクトにLocomotion Systemと移動と回転のコンポーネントを追加すればよいです。
![スクリーンショット 2021-12-11 133635.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/f8ff047e-7222-501a-0e70-76c58ac6d9f2.png)
移動は連続とテレポート、回転は連続とスナップの二種類ずつあります。
僕はどちらも連続(Continuous)を選びました。
スナップ回転はコンポーネントを変えるだけですが、テレポート移動は移動範囲などの設定が必要になります。

どちらのコントローラーを使うかのチェックをUse Referenceのところにいれ、適切なInput Action Referenceを選択します。
回転のInput Action Referenceを選ぶときにRotate ではなくRotation(おそらくコントローラー自体の回転)を選んでしまうと動かないので気を付けてください(1敗)
個人的にはMove Speedは2がちょうどよかったです。

ちなみに見た目上邪魔なのでXR Interactor Line Visualはオフにしました。

# 中身を作ってみる
ではここから実際に中身を作っていきます。
やりたいことは水と戯れることですが、せっかくなのでアバターを入れて動かしたいと思います。
使用するアセットは以下の通りです。

### 使用アセット

- [Simple Interactive Water for URP HDRP VR](https://assetstore.unity.com/packages/vfx/shaders/simple-interactive-water-for-urp-hdrp-vr-162033)
- [Shader Graphs MToon for URP VR](https://github.com/simplestargame/ShaderGraphsMToonForURPVR)
- [Final IK](https://assetstore.unity.com/packages/tools/animation/final-ik-14290)
- [UniVRM](https://github.com/vrm-c/UniVRM/releases)
- [【3Dモデル】Shaclo -Winter- v2.0.0](https://booth.pm/ja/items/1572472)

アバターは導入が簡単だろうということでVRMを入れましたが、あまり意味なかったかもしれません。
揺れ物がこれだけでセッティングできるのは便利ですね。
水アセットのサンプルシーンをベースに作っていきます。

## アバターモデルのセットアップ
まずはVRMのPrefabをシーンに出してみるとまっピンクでした。
![スクリーンショット 2021-12-11 113746.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/83bef154-4740-95c2-996d-f4f442f00714.png)

マテリアルエラーですね。
VRMの標準シェーダーMToonは現在URPに対応していません。
そこで前述の水アセットの作者さんが[URP対応のMToon互換シェーダー](https://github.com/simplestargame/ShaderGraphsMToonForURPVR)を公開していたので、それを使わさせてもらいます。
※最新のUniVRMを使う場合は[こちら](https://github.com/simplestargame/SimpleURPToonLitOutlineExample)が良いようです 2022/4/7追記
解凍してShaderGraphsMToonForURPVR-master\Assets\SimplestarGame\ShaderGraphsMToon以下をプロジェクトにD&Dして導入しました。
後は元のMToonのマテリアルを選択して、Shader Graph/MToonにシェーダーを変更します。
![MToon互換.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/26b5bcfc-dd24-eef6-dcc6-6ca15ad9915c.png)
__かわいい__
__シャーロちゃんはいいぞ__

ちなみに標準で用意されているURP用のシェーダーの中だとUnlitがいい感じでした。
![UnLit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/0c3fa7cb-6cdb-34a6-85d1-4bcfe1805fbf.png)
あと今回は使いませんでしたが、Standard等のBuilt-inシェーダーの変換には、公式のツールであるRender Pipeline Converterが使えます。
![スクリーンショット 2021-12-10 174847.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/8dfe7df9-74b8-f29c-6bba-d51618e90674.png)
下記ページを参照してください。

https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@12.1/manual/features/rp-converter.html

## 3点トラッキングで動かせるようにする
今回は定番FinalIKのVRIKを用います。
まず前準備として、頭と手の位置が来るオブジェクトの下に子要素を追加しておきます。
![スクリーンショット 2021-12-11 114809.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/daa88026-c154-ebe3-68f7-8e240004c371.png)
次にXR Originの配下にアバターのモデルを入れます。
![スクリーンショット 2021-12-11 105901.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/a73c0ab7-414e-39b7-e5fd-fa078a3bc634.png)
そしてモデルのルートにVRIKのコンポーネントを追加し、SolverのHeadとLeftHand、RightHnadを埋めます。
![スクリーンショット 2021-12-11 115245.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/443d9bdb-960a-5f61-c2d5-ca45af6378b5.png)
これでひとまずアバターとして動かせるようになりました。
しかし実際に実行してみると色々不都合があります。
手の角度や位置がおかしかったり、カメラにアバターの頭が映りこんだりしたりしていると思います。
手などのトラッキング位置の問題は先ほど追加した子要素の位置や角度を調整します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/9c19b859-5118-24e4-3708-69bd2325a6a3.png)
後はVRIKのパラメーターを頑張って調整しましょう…僕もよく分かってないです。
カメラの問題は前述の位置調整や、カメラのClipping PlanesのNearを大きくすると改善すると思います。
![スクリーンショット 2021-12-11 133237.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/a3b11951-9767-bc40-c126-44303e6a19f2.png)
それでも移動時に映りこんでしまったので、顔と髪の毛のメッシュのレイヤーを分けて、メインカメラではカリングしました。

## ちょっと遊べるようにする
最後にアバターで水と戯れられるようにします。
とは言えこの仕組みはアセット特有のものなので割愛します。
ざっくり手の位置にコライダーとRigidbody入れてエフェクトなどの設定をしました。

せっかくなのでそれに加えて物を持って投げられるようにしました。
これも簡単で、持ちたい物にコライダーとXR Grab Interactableというコンポーネントを追加するだけです。
![スクリーンショット 2021-12-11 135652.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/ee5a08b7-5cf5-124a-8d5b-ecb89476e3d8.png)

あとカメラとレンダーテクスチャで鏡っぽいものを作りました。
![スクリーンショット 2021-12-11 140015.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341187/d083f9ab-4842-bc4f-780c-bfd82278aa0b.png)

さらにせっかくのURPなのでポスプロも使ってます。
適当にBloomとか入れました。

# 完成
そうした完成したものがこちらになります。
<iframe width="560" height="1500" src="https://www.youtube.com/embed/a51WvDpv-48" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
Quest2上で撮影しましたが、もちろんPCVRでも同様に見えます。
Quest単体でこんなきれいな水が扱えて、ポスプロまで使えるのはURPすごいなぁと素直に感動します(コナミ)
そしてやはり各HMD会社のSDKを入れずに、マルチデバイス対応ができるOpenXRも楽ちんで良いですね。
まだまだ変化の激しいUnity上でのVR開発ですが、段々と簡単になってきている気がするのでこれからも楽しみです。