【VRChat】ワールドをQuest対応させよう！　Part1：とりあえず入れるようにする

# 前書き
今回の記事は、主にワールド制作者をターゲットとしたものです。
いつものことながら間違いを含む可能性があります。もし見つけた場合には遠慮なくお知らせください。

# 挨拶
ワールド制作者の皆様、そしてこれからワールドを作ろうと考えている皆様、いかがお過ごしでしょうか。
ホームワールドやゲームワールド、イベント用ワールド、あるいは思い出の場所など、作ろうとしているものは三者三様かと思います。

時に、この記事をご覧の皆様は「Quest対応」について考えたことはおありでしょうか。
今回の内容はそんなQuest対応ワールドの制作と密接に関わってくるものになります。
それでは早速本題に参りましょう、本日もよろしくお願いします。

# 1. Quest対応とは？
「もう知ってるよ！」なんて声も聞こえてきそうですが、改めて解説をしておきます。

Quest対応、正確に言うならAndroid対応ですが、これはその名の通り
**Quest/Android版のプレイヤーがワールドに入れるようにする**作業のことです。

時にQuest単機でこの世界を巡っていると、我々単機勢は様々な場面でこれを意識することになります。

「あの人に会いたいけどPC Onlyのワールドに居る」
「Twitterで面白そうなワールドを見つけたけど、Quest対応してなかった」
「イベント会場がPC Onlyのワールドだった」
などなど...

システムという巨大な壁に阻まれるこの辛さ、単機勢の方なら分かるかもしれませんね。
「**容量少し削れば100MBに収まりそう！**」という場合は特に...

私はもう慣れましたが、今でもそのもどかしさに歯噛みすることも少なくありません。

# 2. Quest対応の要件
では実際にQuest対応ワールドを作るとなった時、どういった制約が課されるのか。
実のところ、これを知っている人はあまり多くありません。

### 1. ワールド容量は最大100MB
一番分かりやすく、かつ一番大きな制約はこれです。
そもそもワールドの容量というのは、テクスチャ、つまり画像が大半を占めています。
フォトグラメトリやミュージアムといったワールドのQuest対応が難しいのはここが絡んでくるからですね。

ご安心を、現時点で100MBを越えていても「**Quest版だけ**」削る方法がちゃんとあります。
後程説明しますので、まだこの記事は閉じないでくださいね？

### 2. ポストプロセスが使えない
皆様がきれいなワールド訪れた際、光源のまわりにうっすらとモヤがかかっているような表現を見たことはありませんか？
あれは「**ブルーム(Bloom)**」といって、ポストプロセスの一種になります。

そもそもポストプロセスというのは、通常の描画が一通り終わった後に効果を足す処理のことで、その性質上一定の負荷がかかります。

ただでさえ性能の低いスタンドアロン機にそんな処理をさせられるはずもなく...
よってAndroid版ではポストプロセスが無効化されています。
一部のナイトモードアセットがAndroid版で動かないのもここに関係してきます。

「無効化」されるだけなのでアップロード自体は出来ますよ。

### 3. "ごく一部の"カスタムシェーダーが使えない
Quest版ワールドは、アバターと違い基本的にシェーダーの制限がありません。
よってカスタムシェーダーによる特殊な表現が可能です。

...が、宿命と言うべきか、Androidで正常な描画がされないシェーダーというのは一定数あります。
多くのシェーダーがWindowsに合わせて作られている以上、こればっかりは仕方がありません。

例を挙げるなら水面シェーダーがその代表で、あるシェーダーは描画そのものがされず、またあるシェーダーは真っ黒に見える...など、何かとトラブルを抱えやすい部分です。
私が経験したものだと「旗を動かすシェーダーが正常に動かない」なんてのもありました。

解決策の一つとして、私はこちらの水シェーダーをお勧めしています

https://booth.pm/ja/items/4967253

### 4. パフォーマンスの最適化が必要
これは別にQuest対応ワールドに限った話ではありませんが、Quest対応を考える際には少しシビアな問題になってきます。
ライトベイクやメッシュの統合、バッチング、GPUインスタンシングなど
対応だけでなく「快適さ」を求めるのであれば、これらの活用が必要です。

特に問題となりやすいのは、光源処理やメッシュの多さ、パーティクルなどです。
ライトやメッシュ・パーティクルの数は描画命令の数に直結し、この最適化が不十分だと、極端な事例ではFPSが1桁まで落ち込んでしまうこともあります。

せっかく綺麗なワールドでも、まともに動けたもんじゃないとなればQuest対応した甲斐もありませんよね？

___

ここまで大きく4つに分けてQuest対応の要件を説明したわけですが、いかがでしょうか。
もちろんどれにも引っかからなければそれでいいのですが、特に大きなワールドではその方が稀です。

して、これ全部を一つの記事にまとめられれば良かったのですが、あいにく私にそんな長文を簡潔に書く能力は無く...
ということで、今回はPart1と称して、以上の1~3までを解説し
「**とりあえずQuestでも入れるようにする**」ことをゴールとします。



# 3. 実際に対応作業をしてみる
では今回の目標を知って頂けたところで、ぼちぼち実際の作業に入りましょう。
まずは最初にして最重要ポイント、ワールドの容量削減に取り掛かっていきます。

## 1. ワールド容量を削り、100MBに収める
先ほども軽く触れた通り、ワールドの容量の大半を占めるのはテクスチャ、つまり画像データです。
画像データの容量を減らす方法は、
1. **画像の解像度を下げる**
2. **画像の圧縮形式を変える**

大きく分けてこの二つになります。

ただ「**どの画像の容量を減らせばいいのか**」が現時点ではまだ分かっていません。
そこで便利なツールの出番です。

### ①VCCから「VRWorld Toolkit」をプロジェクトに導入する
「VRWorld Toolkit」はワールドに使用されているデータの一覧をビルド結果として表示してくれるツールで、これを使うことで容量の大きい画像ファイルを特定することができます。
**元からVCCに入っている**ツールなので、リポジトリの追加は必要ありません。

もし正常に追加できていれば、画面上部のツールバーに"VRWorld Toolkit"というメニューが追加されているはずです。確認しておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/4d4ba75e-d5cc-1411-f18c-16c1e543fed2.png)

### ②ビルド結果を取得する
テストビルドでも、アップロードでも、どちらでも構いません。
まずはビルド結果を取得するために、Windows版で一度ビルドを走らせます。

ビルドが完了したら、先ほど確認したVRWorld Toolkitのメニューを開きましょう。
こんな感じのUIが出てくるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/86e89ede-6c33-e3a5-1c04-a2e54335038f.png)

左上にあるのがWindows版のワールド容量、右上にあるのがAndroid版のワールド容量です。
人によってはAndroid版の表示がないほか、この場合では以前にビルドした古いシーンの容量が表示されてしまっていますので、ここではひとまず無視してください

### ③容量の大きい画像を調べる
ビルド結果が取得できたところで、次はその内訳を見ていきます。
右上の方にある「Build Report」をクリックし、容量順にアセットを表示していきます。
もし容量順になっていない場合は、その下の％をクリックすることで容量順にできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/0044e9db-4e37-8b69-3c4f-150cf149fded.png)

この場合は「SunlessCirruscover4K.hdr」というアセットが22%を占めていますね。
これはワールドの背景の役割をする「スカイボックス」と呼ばれるもので、初期状態では4Kなど高い解像度に設定されていることが多いです。
が、あくまで私の感覚にはなりますが、そこまでの解像度は必要なく、1Kでも特に違和感を感じない場合が多いです。

このワールドは50MB程度に収まっていますが、後々のことを考えてAndroid版での解像度を下げておきましょう。


### ④Android版での解像度を下げる
**ここで一度、プロジェクトのプラットフォームをAndroidに変更しておきましょう。**
VRChatのSDKを開き、画面中央付近の「Switch Platform」からAndroidを選んでください。
こうすることで、この先の容量削減作業の効果が数値で見えるようになります。

それが終わったらまたVRWorld Toolkitの画面に戻り、**アセットの名前をダブルクリック**してそのアセットのある場所に飛びます。

飛んだ先のフォルダを見ると、そのアセットがこんな感じにハイライトされていて、

![スクリーンショット 2024-09-02 154712.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/c391ecb3-dc67-c5dd-2813-0fb4d642e8b9.png)

それをクリックすると、画面右の"Inspector"タブがこんな表示になります。
今回触るのは枠で囲った部分です。

![スクリーンショット 2024-09-02 162128.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/133179d7-13f5-c794-ddbf-0d3757b4b05d.png)


まずは一番右のタブのAndroidマークをクリックし、「Override For Android」にチェックを入れます。
これは「**Android版にのみ**」このテクスチャ設定を適用するという設定です。

次にMax Sizeを1024に変更し、**忘れずにApplyを押します**。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/fc39d32d-e5fc-8774-868c-0291a83af9ee.png)

元の解像度は2K、容量は14.3MBだったのが、1Kに変更したことで3.6MBまで減りました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/01cd02bc-245f-3f7d-e6cc-c7c5789ab299.png)
画像の容量は解像度に依存し、1辺の長さが2倍になるとそのサイズは4倍になります。
極端な話、**1Kと4Kでは実に16倍もの容量差が生まれる**ため、無駄な部分の解像度を下げる手法は非常に有効なのです。

:::note
**まずは画像の解像度を落とす！**
:::

### ⑤Android版での圧縮形式を変える
このままでも良いのですが、今後のことを考えて更に踏み込んだ容量削減の方法もご紹介しておきます。
それが「画像の圧縮形式を変えること」です。
では詳しく見ていきましょう。

WindowsとAndroidではそれぞれ利用できる圧縮形式が異なっており、うち代表的なものとして以下が挙げられます。

**Windows**
不透過画像：**RGB Compressed DXT1/BC1**
透過画像：**RGBA Compressed DXT5/BC3**
　　　　　**RGBA Compressed BC7**

**Android**
**RGB Compressed ETC / ETC2**
**RGB(A) Compressed ASTC 4x4 ~ 12x12 Block**

このうち**ASTC**というのが便利な圧縮形式で、Windows版で使える形式より圧縮能力が高く、また圧縮度の調整もしやすいという優れものです。
4x4 ~ 12x12とありますが、**この数字が小さい形式ほど品質と容量が高い**ものになります。

例) RGB(A) Compressed ASTC 4x4 ＞ RGB(A) Compressed ASTC 6x6

一方でETCは何なのかというと、こちらは**古いデバイス向けのレガシーな圧縮形式**です。
ASTCに比べて柔軟性や圧縮率、クオリティに劣るのですが、UnityのプロジェクトではこちらのETCが既定で適用されるようになっています。
ETCが使われている場合はSDKにも警告表示が出てくるので、忘れずに直しておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/2920e3da-c8a0-62c0-26fb-0ba0265efd05.png)


ここまで説明したわけなんですが、じゃあ実際容量を減らすにはどうすればいいか。
勘のいい方ならお気づきでしょう、より数字の大きい圧縮形式を適用すればいいのです。

という訳でさっき解像度を変えたスカイボックスの圧縮形式を変更します。
「Format」の項目を「**RGB(A) Compressed ASTC 8x8 block**」にしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/ce26b51a-6409-2442-d92d-8da0abfec2d6.png)

10x10や12x12に変えてもいいのですが、そこまで行くと流石に粗さが気になりだすので、スカイボックスなど専有面積の大きいテクスチャはあまり落としすぎない方が無難です。

先ほど3.6MBだったところが、さらに減って2.0MBになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/e2bfc041-130c-5d76-3f4c-b2e3a3de9c19.png)

:::note
**必要に応じて圧縮形式を変え、さらに削る！**
既定ではASTC 6x6が使われるので、その付近で調整するとGood
:::

___

以上で、解像度削減と圧縮形式の変更についての説明は終わりです。
では実践、ということで試しにこのプロジェクトの各種テクスチャに以下の設定を適用し容量を確認してみます。
1. 4Kのカラーテクスチャは2Kに
2. 各種マスクテクスチャは1Kに
3. 圧縮形式をASTC 8x8か10x10に

圧縮形式に関してはそれなりに思い切りましたが、今回使っているような航空機関連のアセットでは多少粗くても気になることが少ないので、少し強めに圧縮をかけてます。

![スクリーンショット 2024-09-03 104225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/ab8a641a-1759-5e94-60f9-7be010e29614.png)

気になる結果は...？

![スクリーンショット 2024-09-03 104252.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/4f6bc529-5d74-e316-4e9a-37d885c7b3e8.png)

PC版が52.4MBだったのに対し、15.6MB。
1/3以下にまで落とすことが出来ました！

圧縮をかけたということでクオリティを心配される方もいらっしゃると思いますが、正直な所そこまで気になりません。
というか入れなきゃそれ以前の問題ですので、とりあえず対応させるのであれば多少のクオリティは犠牲にする覚悟で行きましょう。

## 2. ポストプロセス、シェーダーまわりの対策 
まずは容量削減、お疲れさまでした。
うまく行けばこの時点で「Quest対応出来た！」という方もいらっしゃるかもしれません。

では次、ポストプロセスとシェーダーまわりの対策に入ります。

### ①ポストプロセスとは？
ではまずこちらから。
上の方でも軽く触れましたが、「ポストプロセス」というのは
「**一通り描画が終わった後に効果を足す**」処理のことを指します。
その性質上無視出来ない負荷が発生するため、Android版では無効化されるようになっています。

うちVRChatで一番よく使われるのは「**Bloom**」と呼ばれる種類のエフェクトで、ざっくり言えばきれいなワールドで光源がエモく光ってる感じのあれです(語彙力-3)

では実際この有無でどう見え方が変わるのか。
分かりやすい資料をご用意しましたので、ご覧ください。

**Windows (ポストプロセス有効)**
![VRChat_2024-09-03_11-02-41.589_1920x1080.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/6463ade6-6038-5a40-466e-11d7b1bb20fd.png)


**Quest/Android (ポストプロセス無効)**
![590f28595fac4d358e2b2aade86bad05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2016616/1f9f5921-0e7a-7ef9-7c61-ef8f9ee6dfc6.jpeg)

...身も蓋もないことを言ってしまうと「なんかショボく見える」というのが正直な感想ではないでしょうか。
ライトの周りに注目すると分かりやすいほか、空気感も違うのが見て取れるかと思います。

ただ、無効化されたからと言って壊れるわけではない、というのもお分かりいただけると思います。
全部のポスプロ表現が壊れない、という保証は出来ないのですが、システム側でも「無効化」という扱いであることから「ただ見えない・動作しないだけ」という場合がほとんどになります。

### ②Quest版での見え方を確認する
ポストプロセスを無効化したとして、自分のワールドは大丈夫なのか。
一番分かりやすい確認方法は「Questで入ってみる」ことです。

Unityのプレイモードでは大丈夫でも、実際に入ってみたらまた違って見えた...なんてことが割とあるので、これに勝る確認方法はありません。
お手元にAndroid系デバイスが一つも無ければ、フレンドに頼るのもアリでしょう。

___

### ③カスタムシェーダーとは？
続いてシェーダーの方に目を向けてみましょう。
そもそもシェーダーとは描画時の処理を書いたもので、皆様がよく目にするものとしては**lilToon**が代表例になるかと思います。

正確なデータがないので「どのシェーダーがうまく動かないのか」についてはここでの言及ができないのですが、少し特殊な描画をするシェーダーだと壊れやすいように感じます。
その代表例が、上の方で言及した水面のシェーダーな訳です。

正常に描画されていない時の見え方は何種類かあり

・真っ黒に見える
・そもそも見えない
・メッシュの形状が大変なことになっている

などが挙げられます。

### ④Quest版での見え方を確認する
...もう私が何を言うかはお分かりでしょう。
そうです、Questで入ってみましょう。

正常に描画されない事例はいくつか挙げましたが、だいたいは真っ黒に見えているため結構分かりやすいです。
加えて通常のシェーダーではまずそういったことは起こらないので、あまり血眼になって探す必要もありません。
綺麗なワールドを作る時は少し注意してみると良いかもしれませんね。


# 4. まとめ
ここまで作業を進めてきた皆様、まずはお疲れさまでした。
パフォーマンスはともかく「ひとまずQuest対応はできた」という方も多いのではないでしょうか。

今回の記事で知って頂きたかったのは、
「別にPC版で100MB超えていてもQuest対応は出来る」ということです。
勿論相応に見た目を下げる必要は出てきますが、言ってしまえばそれを見るのは我々Quest単機勢だけです。

かくいう私も一時期250MB近い容量を持つワールドを抱えていたことがあるのですが、削れるところをしっかり削った結果現在まで一貫してQuest対応を維持できています。
~~流石に骨の折れる作業ではありましたが...~~

そんな所で、今回の記事は終わりです。
次回はパフォーマンスの改善に着手していきますので、よければそちらもご覧ください。

https://qiita.com/Hellcat_152/items/cc4d77ffac8ba3d8a619

# あとがき

今回使わせて頂いたアセットはこちらです。

https://booth.pm/ja/items/4387005

本来は適切な設定がなされていて元から軽量なアセットなのですが、今回は解説のためにクランチ圧縮を解除した際の値を使いました。