この記事はVRChat Advent Calendar 2021の19日目の記事です。前回はbd_さんの「ShaderFes2021にいろいろと投稿した話」でした。
はじめに
こんにちは!
VRChatワールド制作や、ギミックの販売などをしているサックーです。
この記事はPC版VRChatワールドを作れる人を想定した、Quest対応ガイドです。
基本的なワールド制作については触れないので、他記事を参考にしてください。
一番伝えたいのは、ワールドはアバターと違ってQuest版の制限はかなり少なく、おおむねそのままアップロードできるということです。
Standardシェーダーとか全然そのままで問題ないです。
ワールド作者さんにはぜひ軽率にQuest対応してもらって、Quest対応ワールドが増えれば良いなと思います。
目次
1:最低限の手順
2:Quest版の表現上の制限
3:最適化について
4:Pickup Objectの同期について
※Quest用のシーンをどうするかについては
- PC版と共通のものPlatformごとに調整する
- 同一プロジェクト内でPC版シーンをコピーしてそれを調整
- Quest用に別プロジェクトを用意してそこにシーンをコピーして調整
の3パターンがあると思いますが、この記事では一番簡単な1を用います。
#1:最低限の手順
1-0:Android Build Supportなどのインストール
QuestはAndroidで動いているので、Andoroid用のビルドをしてあげる必要があり、そのためのモジュールをインストールします。
Unityバージョンごとに一度で大丈夫なので、もう入れてある人は飛ばしてください。
最初のUnityインストール時に一緒に入れることができますが、後からでも簡単に追加ができます。
Unity Hubのインストール
メニューから、使うUnityバージョンのところで3点ドットのところを押します。
モジュールを加える
を選んで
Android Build Support
の配下全てにチェックを付けて実行
を押します。
利用規約に同意してダウンロード、インストールまで済めば完了です。
1-1:Switch Platformする
ここからはすでにPC用に用意されたワールドがある前提で進めていきます。
該当プロジェクトを開き、File > Build Settings
を開きます。
Platform > Android
を選び、Texture Compression > ASTC
を選びます。
これはテクスチャの圧縮方式の指定で、ASTCは品質と容量のバランスが良く、おすすめの形式になります。
しかし変換時にかなりCPU負荷がかかり、時間がかかるため、使用していないテクスチャなどは削除しておくことを推奨します。(BakeryのExampleフォルダなど)
それでは実際にSwitch Platformをしていきますが、初回のみ、テクスチャの数とCPUの性能によってはかなり時間がかかるので、それを理解したうえでSwitch Platform
ボタンを押してください。
2回目以降はキャッシュが残っているため割とすぐ終わるので安心してください。
1-2:アップロード
Switch Platformが済んだら基本的にはもうQuest用にアップロードできる状態になっています。
このシェーダーはパフォーマンス低下を引き起こしますよ!ってめっちゃ警告されてますが無視してアップロードできます。
VRChat SDK Control PanelからBuild & Publish for Android
を押してアップロードしましょう。
ただし、次から説明するQuest版のシェーダー制限だけ確認するようにお願いします。
さもないとQuestから右目の視界がおかしくなるなどの深刻な問題が発生します。
また、ワールド容量が100MBを超えているとアップロードできないため、容量削減の項目を参照してください。
PC版が100MB以下でも、テクスチャの変換によって容量が増えていることがあります。
#2:Quest版の表現上の制限
先述の通りアバターと比べればかなり制限はゆるいのですが、
- シェーダー制限(一部透過シェーダー・Hiddenシェーダー・GPUシェーダー)
- ポストプロセッシングが使えない
- リアルタイムライトの影が落ちない
の3点のみ表現上の制限があります。
1は別シェーダーへの置き換え、2はあきらめ、3はライトベイクする(アバターの影はあきらめ)といった対応になります。
2-1:シェーダー制限について
透過シェーダーの制限
あまり正確なことは分からないのですがグラブパスを用いたシェーダーを使うと、右目の視界の描画がおかしくなるようです。
おおよその見分け方としては、透過シェーダーで屈折表現があるものが当てはまると思われます。
より具体的には一部の水シェーダーやクリスタルシェーダーが当てはまります。
一番手っ取り早いのはQuest版をアップロードしてQuestから確認することです。
もし自分で持っていない場合は知り合いのQuestユーザーにお願いできたらよいかもしれません。
もしQuestに対応していないシェーダーを使用していた場合は、類似の対応シェーダーに置き換えるか、そのオブジェクト(メッシュ)をアップロードしないなどの対応が必要となります。
これを怠ると右目の描画がおかしく、非常に気分が悪くなりやすい危険なワールドとなってしまうので、これだけは確認をお願いします。
また有難いことに、にこまるさんがQuestで動作確認をしたシェーダーをまとめてくださったスプレッドシートとそれを実際に配置したワールドがありますので、それを参照するとそのまま使えるかや変更先シェーダー選びの参考になるかもしれません。
Hiddenシェーダーの制限
これはおそらくUnity2019からだと思われますが、Hiddenに分類されるシェーダーを利用していると超高負荷となってまともに動作しなくなるようになってしまったようです。
僕の場合はAsset Storeで購入した植物系のマテリアルがHidden/Nature
シェーダーを使用しており、大変な負荷となって何も操作できない状態となってしまいました。
HiddenでないNature
カテゴリに対応シェーダーがあるのでそれに置き換えると良いと思います。
おそらくPC版でも負荷が高くなってそうなので普通に変えたほうがいいでしょう。
GPUシェーダーの制限
これはリーフルさんから聞いて初めて知ったのですが、一部のGPUシェーダー(DirectX11に非対応のもの)を用いたパーティクルなどもQuestではうまく描画できないことがあるようです。
2-2:ポストプロセッシングの制限について
これはどうあがいても使えないのであきらめるしかないです。
またポスプロではないですがLens Flare
も使えないです。
アップロード時はそのままでも勝手に非適応となるだけなので問題なさそうですが、Editor Only
にするなどで除外した方がいいかもしれません。
Color Gradding
など一部の表現はUI等を視界に追従させて再現できるかもしれませんが、一般的なことは言えないので割愛させてもらいます。
VRChatがURPに対応したらQuestでもポスプロ使えるようになるのになあという感じです。(その際の破壊的変更には目をつぶる)
2-3:リアルタイムライトの影の制限について
これもUnity2019からなのですが、Questワールドではリアルタイムライトの影が落ちなくなりました。
ワールドオブジェクトの影はベイクすることで補完出来ますが、アバターの影は本当にどうしようもないです。
シェーダーを頑張ればできる気もしますが僕にはできないので割愛します。
しかしリアルタイムライトは負荷の点からもできるだけ使用は避けたいので、どちらにしろライトベイクを推奨します。
ライトベイクについてはまた後述します。
2-4:お役立ちツール
上記で紹介した対応をSwitch Platformするたびに手作業でやるのは面倒ですし、し忘れも発生すると思います。
そこでJordoさんのEasyQuestSwitchというツールをお勧めします。
こちらを使うとSwitch Platformするたびに自動で、事前に登録したオブジェクトのオンオフやマテリアル変更を行ってくれます。
オブジェクト自体であったりコンポーネント単体での操作もできます。
しかし逆に子オブジェクトをまとめて変更のようなことはできないので、すべてのマテリアルをStandard Lite
に置き換えようとかはやめた方がいいです。
自分は水のマテリアルだけ変更しています。後はナイトモードはQuestで使えないのでEditorOnly
に変えたりしてます。
#3:最適化について
ここまでのことを行えばひとまず人を入れても大丈夫なワールドとなっていることが多いと思います。
しかしワールド容量が100MBを超えてしまってアップロードできなかったり、負荷が高くて快適ではない可能性があります。
それらを解消するために各種最適化の作業を行うことができます。
この章では大きく分けて
- 容量の最適化
- 負荷の最適化
について書きます。
これらはQuestワールドのみならずPC版でも役立つことだと思います。
また、ここら辺の話はネット上に多くの情報があるとは思うのでそれらを参照してもらってもいいと思います。
今回のワールドQuest対応という点からすると、容量についてはともかく負荷に関しては、
リアルタイムのPoint Lightを置かない
事だけ守ってもらえればひとまず大丈夫だと思います。
Point Lightは本当に重くて、一つ置いただけでFPSがガタ落ちするので基本的にベイクするようにしましょう。
3-1:容量の最適化
現在Questワールドの容量制限が100MBに緩和されたので、気にすることは減ったかもしれませんが、ローディング時間の短縮や間接的に負荷軽減にもつながるので、できるのであればやった方が良いと思います。
ワールド容量の合計はウェブサイトなどから見れますが、その内訳を見る方法が以下の通りです。
1,アップロード後にConsole
ウィンドウの右上3点ドットから、Open Editor Log
を押す。
2,検索でcustomscene.vrcw
を探し、一番最後のそれっぽい容量のやつを見つける。その下にも0kbとかのやつがありますが無視してください。
最初にカテゴリ別の容量と割合が表示され、その下に個々のファイルの容量と割合が表示されます。
分かりにくいものとしてはカテゴリの、Levels
が後述のOcclusion Cullingの設定などによるデータです。
多くのワールドではテクスチャが容量の大半を占めると思いますので、その削減を重点的に見ていきます。
テクスチャ容量の削減
テクスチャの容量は、大きさ(ピクセルサイズ)と圧縮具合によって決まります。
これらはインポートした元画像のものがそのまま適用されるわけではなく、Unity側で様々な設定が上書きされることになります。
適当なテクスチャを選んでInspectorを見てみましょう。
青い四角で囲んだところにUnity内で適用される設定欄があります。
ここにはおそらく3つのタブがあって、Default
とPC
とAndroid
となっています。
何も設定していなければ全てのプラットフォームでDefault
の設定が適用されます。
Andoroid
タブを選ぶとOverride for Android
というチェックボックスがあり、ここにチェックを入れることでAndroidビルドの時にこちらの設定を適用することができるようになります。
僕はPC側はDefaultの設定を使い、Quest側は設定をOverrideして使っています。
この機能を使うことでPC側は高解像度、Quest側は少し画質を落として容量削減といったことが簡単にできるのでお勧めです。
Android側の設定項目としてはMax Size
とFormat
だけ見てもらえればいいです。
Max Size
はそのまま解像度なので大きく見え方に影響します。
小物に使われているテクスチャだけ小さくするなどがいいかもしれません。
Format
ではもう少し細かく設定ができます。
形式も選べるのですが前述の通りASTCがおすすめで、後はその圧縮具合を選ぶことになります。
〇×〇の数字部分が小さいほど高品質で重く、大きいほど低品質で軽くなります。
デフォルトでは6×6になっていますが、これだとPC版より容量が大きくなってしまっていることが多いです。8×8程度がちょうどよいかなと個人的には思います。
これも見た目と相談しながら変えてみましょう。
Inspectorの下にはテクスチャのプレビューとピクセルサイズ、圧縮フォーマット、容量が見られるので参考にしてください。
最小化していることがありますが、引っ張って伸ばすと出てくると思います。
オーディオの容量削減
オーディオはそんなに容量を食うことはないかもしれませんが、品質を犠牲にすることなく削減できることがあるので紹介します。
適当なオーディオファイルを選んでInspectorを見るとForce To Mono
というチェックボックスがあると思います。
これにチェックを入れるとステレオ音源をモノラル音源に変換し、大幅に容量を減らすことができます。
もちろんステレオがモノラルになるので品質が下がることになるんですが、それが関係ない場合が3D音源として使用する場合です。
通常Audiosourceの立体音響では自動的にモノラル音源に変換されてしまうので、Force to Mono
を利用しても問題はないでしょう。
その他の容量削減
これら以外に容量を食うものはワールドによってさまざまだと思います。
自分の経験だとフォントがすごい容量を食っていたこともありました。
適宜それらを削るなどの対応を取ってください…
そしてはまりがちなのは、次に紹介する負荷の最適化によって生まれるデータの容量です。
詳しくはそこで書きます。
お役立ちツール
正直使用してるテクスチャを一つ一つ探して設定するのは大変ですし、まとめてやるにも処理に時間がかかってしまいます。
そこで山兔さんの私の世界はなぜこんなに大きいのですか?というツールをお勧めします。
これを使うとシーンで使われてるテクスチャを容量の大きい順に並べてくれて、クリックするとInspectorで表示されるので効率よく容量削減ができると思います。
3-2:負荷の最適化
最初に言っておくと、これは正解のない作業になります。エンドコンテンツです。
定番のところだけ抑えられれば良いと思います。
影響の大きい順に書いていくので参考にしてもらえればと思います。あくまでPCワールドをQuest対応するときに効果的な順番となるのでご了承ください。
また、負荷の基準とは何かというと実機でのFPSが一番ですが、Unityエディタ上ではGame
ビューのStats
というところで見れる値が参考になります。
おおむねメッシュの数などと対応しているBatches
と、マテリアルの数やシェーダーの種類と関係するSetPass calls
を減らせれば負荷が減ったとみていいかと思います。
ライティング
まず大体のワールドに関係があって影響が大きいのはライティングになります。
リアルタイムライト、特にPoint Light
は非常に負荷が高いので基本的にライトベイクするようにしましょう。
ライトベイクのやり方については黒猫洋品店さんのこちらの記事が非常にわかりやすくきれいに焼くコツが描かれているのでお勧めです。
Unity2018と書かれていますが、2019でもほとんど同じです。
個人的にはBakeryという有料アセットを利用していて、簡単で高速に綺麗に焼けるのでおススメです。
しかしライトベイクにおいては注意事項があります。
全ての光源をベイクしてしまうと、ベイクしていないオブジェクト(=Pickup Object、アバター)を照らすものが無くなってしまい、シェーダーによっては真っ暗になってしまうのです。
この解決策としては
- 動的オブジェクト専用のリアルタイムライトを追加する
-
Light Probe
を使用する
があります。
専用のリアルタイムライトとはDirectional
でNo Shadows
の、当てるレイヤーを制限した以下のようなものになります。
負荷の増加を最低限に抑えられます。(画への影響も)
多くの水シェーダーはリアルタイムライトがないと反射等が失われてしまうので、この手法を使うしかないと思います。
とはいえリアルタイムライトなことに変わりはないので負荷はそれなりに増えます。
一方Light Probe
を用いると負荷も容量もほとんど増えない上に、ベイクしたライトの光の影響を受けることができるようになります。
非常におススメです。やり方などはこちらの記事などが参考になるかと思います。
難点として配置作業が面倒というのがありますが、こちらの記事のようなスクリプトを使ったりこちらの有料アセットなどを使うことで自動化ができます。
が、なんとなく手置きした方がいい感じになっている気がします…どうして…
最後にもう一つ注意事項としてライトマップ分の容量が増えてしまうという点があります。
ライトマップはただのテクスチャなのでその数と大きさの分だけ容量が増えます。
ベイク時の設定で解像度を低めにしておくのがおすすめですが、品質とトレードオフになります。
ミラーについて
VRChatワールドに欠かせないミラーですが、Questで通常のミラーを付けるとガクッとFPSが下がることが多いです。
表示するレイヤーをPlayerなどのみに絞ったLowミラーも選択できるようにすると親切かもしれません。
また、スポーン地点でいきなり目の前にミラーがあるような構造だと、Questで最初のロード負荷に耐えられなくなる可能性があるのでご注意ください。
Lowミラーに関してはTemporalさんのVRCPlayersOnlyMirror (背景なし No background)が雰囲気を壊さずに負荷を下げられるかもしれません。
テレイン
使わない場合も多いと思いますが、地形を簡単に作れるテレインは設定に注意が必要です。
こちらの記事を参考にすると良いと思います。
個人的な気づきとしては、Terrain Height
の値を小さくすることで、Height Resolution
を小さくしても滑らかな地形を作ることができるということです。全体で取りうる値の幅が小さくなれば、段階が減っても刻み幅自体は十分な細かさを保てるという寸法です。
デフォルトだとTerrain Height
が600もあるので、高い山を作るのでもなければ小さくすれば、品質を保ったまま負荷を下げることができます。
あと、草木に関しては次に紹介するGPU Instancing
で軽量化が図れます。
Occlusion Cullingとか
カメラの画角には入っているけど、他のもので隠れてるから描画しないという風に負荷を下げてくれるOcclusion Culling
同一メッシュとマテリアルを持つオブジェクトをまとめて描画して負荷を下げるStatic Batching
とGPU Instancing
などについて解説してくれている記事を紹介します。
Occlusion Culling
は細かい部屋に分かれたワールドなどに、Static Batching
は同じモデルを多く複製して配置しているワールドに、GPU Instancing
はPickup Objectが多い場合とTerrainの草木に効果があります。
またOcclusion Culling
については容量が増える原因となるので注意が必要です。
メッシュとマテリアルを減らす
この節の最初に書いたように、メッシュの数とマテリアルの数はダイレクトに負荷に直結しています。
方法としてはモデリングソフトを通すか、MeshBakerなどのアセットを利用することになると思います。
単一のモデルのメッシュ・マテリアル結合はおおむね問題ないですが、複数のモデルを結合する際は注意が必要です。
ライトベイクの結果が汚くなったり、逆に負荷が高くなってしまう可能性があります。
さらにあまりに広範囲のモデルを結合してしまうと、前述のOcclusion Culling
が効かなくなったり、標準の画角外Cullingすらも効かなくなり常に描画されるようになったりしてしまいます。
それを避けるために、エリアごとに区切って結合すると良いと思います。
ポリゴンを減らす
メッシュやマテリアルの数ほどではないですが、やはりポリゴン数も負荷に影響してきます。
特にQuestの場合は一度に100万ポリゴン以上を描画しようとすると限界を迎えてしまうようです。
しかしもちろんその限界は他の要素によっても大きく変動すると思います。
Occlusion Culling
を適切に使うなどで改善できるかもしれませんが、無理であればモデルを変えるなどの対応が必要になるでしょう。
軽量なシェーダーを使う
PC版ワールドをQuest対応するときは、正直ここまでする必要はないと思います。
Standard
をVRC/Mobile/Standard Lite
に置き換えるのは、大変な上にベイクがきれいにできず、あまりに見た目が落ちてしまうと思います。
逆に最初からQuest向けに作るならこうした軽量シェーダーを使うのもありかもしれません。
マテリアル一つ当たりのSetPass calls
を減らして大幅に負荷の軽いワールドを作れると思います。
Udonの最適化
一昔前のUdonは同期変数を使うとめっちゃ重かったですが、今はマシになりました。
後の部分はUnityC#の軽量化の話とかになると思うので割愛します。
#4:Pickup Objectの同期について
個人的にはQuest対応における一番の沼ポイントです。
基本的にはObject Sync
のコンポーネントが付いていればPCとQuest間でも問題なく同期するはずなんですが、何らかの理由で同期しなくなることがあります。
明確な原因は解明されていないのですが、ヒエラルキーの順番や数が変わると同期しなくなるのではというのが有力な説です。
そのためPCとQuestそれぞれをビルドする間でヒエラルキーをいじらないようにしています。
それもあって今ではPCとQuestどちらも同一シーンを使うようにしています。
それでも時々どうしても同期しなくなって、適当にオブジェクト増やしたり減らしたりしたら同期したなんてこともあります。
冷静に考えて異なるビルド同士で同期させようとするの自体がよく分からないですよね…
誰か根本的な原因や解決策を知っている方がいたら教えてください<(_ _)>
まとめ
いかがだったでしょうか。
Quest対応記事のはずが半分くらい最適化の話をしていた気がします。
逆に言うとQuest対応にそこまで特別なことはしなくてもよいという証左ですよね。
せっかく作ったワールドを、Questユーザーの人に見てもらわないのはもったいないなと思います。
この記事でQuest対応ワールドが少しでも増えたらうれしいです。