VRChatのQuest用ワールドを雑に作る指針と、ライティングをいい感じにする話

※この記事は2019/6月時点での情報です。今後のVRChatアップデートによっては状況が変わっている可能性があります

VRChat Quest対応ワールドを増やしたい?増やしたくない?

「OculusQuestがVRChat用端末に割といいぞ。んでもってVRChatもユーザ増えてる」ということで、Quest対応VRChatワールドを作るなら今がチャンス!!!!  俺もドバーッとワールド作りたいんだけど、一人では全く間に合わんので、みんな作ってくれ…

 

VRChatワールド制作歴1カ月ぐらい、初めてのlab送りした自作ワールドjust RedFlagを作る間に得たtipsを適当に書きます。といっても、このワールドは当初からQuest対応するつもりはなかったんだけど、適当にポチポチしたらわりかしQuestで動いてしまい、見栄えもまあまあできたという経緯。

 

基本的にQuestをターゲットに書いているが、基本すべてのことはPC版でも有効になるはずなので軽量&イカしたライティングのワールドを作るときの参考になるかもしれない

 

基本コンセプト。まずQuest用に作る、PC向け表現を分ける。

公式ドキュメントに書いてある通り「PC向けを先に作って、Quest向けに軽量化する」よりは「Quest向けに作って、そのあとPC向けに最適化する」方が楽、と思われる。

 

「PC用/Quest用プロジェクトを作って云々…、って大変そう。しかもオブジェクト類は全部同じ配置じゃないといけないんでしょ?プロジェクト2つをちゃんと同じにそろえるのって大変じゃん」と思うかもしれないが、Quest用Avatar開発で言われてるのと同様、「どっちかのプラットフォームで作って、UnityプロジェクトのSwitchPlatformする」だけで2環境を切り替えて開発でき、オブジェクト配置は同じにできる。最終的には、PC用でアップ→switchPlatform→Quest用でアップ(PC/Questは逆でもよい)、の3ステップでCrossplatformなワールドがパブリッシュできる

PostProcessingStackのようなPC専用機能は、Quest向けにそのままアップロードしても無効化されるのでわざわざ切り替える必要はない。テクスチャについては、Unityのプラットフォームごとのオーバーライドという機能を使えば、自動で環境ごとにリサイズして出力ができる。

 

Quest用シェーダーはPCでも動く、のでQuest向けシェーダーでPCワールドを構築してしまえばそのまま両対応なワールドが出来上がる。

もちろんQuest基準で全部作ってしまえば、例えば透明マテリアル(Transparent)や特殊な表現シェーダー、VideoPlayerまでPCで使えなくなってしまう。そこについては切り替えるしかない。例えば、PCで作っておいてQuestでアップロードするときは該当GameObjecetのEnableを切るとか。PCのガラス表現は別メッシュにしておいて、Quest側ではMeshRenderをDisableにしておく、とか

 

ということでPCとQuest用ワールドの差異をQuestに揃えてできるだけ減らす、または自動処理に任せてしまうことで、やるべきことを単純化しておくと案外できる

 

実際作るときの作業フローは、PC/Questどちらかの環境向けでビルドして編集/確認をし、適度に途中/最後でPC/Quest両方をアップロードして最終確認することになる

自分の動作チェックは主にPCでやっているが、Questでの検証が捗るならそちら基準でもよい。ただし、UnityのSwitchPlatform操作はAssetの量によるが数分PCが使えなくなるので、頻繁に切り替えたくはないだろう。基本はPC/Questどっちかで開発をすすめ、いい感じの出来になったところで、Switchしてもう片方で動作チェックするのが良いと思われる

 

Quest向けセットアップをする。

公式ドキュメントに従う。Build Settings -> SwitchPlatformをしようとすると、UnityAndroidSDKのダウンロード&インストールが促されるのでそれに従う。インストールしUnityを再起動すると、SwitchPlatformが押せるようになる

f:id:o_mega:20190622024514p:plain

あとは普通にワールド作成をする。ミニマムだとVRC SDK内のexampleでもいいし、VRCWorld prefabをD&Dしてもいい。各種有志が公開しているワールド作成キットもいいぞ。ナルさんのStarterKitにはお世話になりました。

 

シェーダーどうすんの?

VRC SDKにVRChat/Mobile/xxxxx系シェーダーがあるので、それを使う。

ベストはDiffuseあたりのだと思われるが、色指定ができないのでStandardから移行しようとしている人は大変だ。ちゃんとやるなら、色テクスチャを用意して必要に応じてモデル側にUV割り当てたりとかして、マテリアル統合とかするべきとは思うが、しんどい。

そこでVRC公式は移行しやすいよう、StandardLiteシェーダーを用意してくれたので、とりあえずはそれを使ってしまうが楽だ*1。特にCube並べ勢にはこのシェーダー追加は朗報だった。パフォーマンス改善は悪くなってから考えても遅くない*2

f:id:o_mega:20190622044018p:plain

(PC含め)Questでもイケるイカしたライティングをする

雰囲気をよくするにはライトを使え、ということでざっくりお勉強してきましょう。まずはUnityで一般的なライトの把握。参考記事 Unity、入門ライティング設定! - Qiita

 

Quest版VRChatではDirectionalLightぐらいしかリアルタイムライトは使えません。他を詰めていきます。あと、Environment(Ambient)も行ける(と思う)。

  • といっても影要らなかったらDirectionalLightも要らん
  • PointLightやEmission付きオブジェクトをばらまいて、ベイクすると(レンダリング軽いのに)シックでエモくなる。オススメ
  • Lightprobe付けると、アバターとかにちゃんと明るさが反映される。オススメ
  • PC用ならReflectionProbeを置くとテカテカした人たちが良い感じになる

のでこれをやっていく。やっていき!

ライトをベイクしろ?

公式は言っている「ベイクは必須です。リアルタイムライトは激重だ。Lightmapとprobe使え。Lightmapも低解像度で十分綺麗だから」「大丈夫だ。問題ない」

一般的にライトをリアルタイム処理すると重い。でもほとんどのワールド内のものは動かないじゃん? じゃあ光の当たり方を事前に計算して、テクスチャに"焼き込んで"おくと、リアルタイムじゃないのにそれっぽい陰が作れる!というのがベイク処理(bake:焼く)。詳しくは「Unity ライト ベイク」とか「アンビエントオクルージョン」とかググって

 

 Lightingウインドウ*3を開いて。Realtime GIをオフに、Baked GIをオンにする。これでリアルタイムライトは機能しなくなり、負荷が軽くなる

f:id:o_mega:20190727095648p:plain

動かないオブジェクトのinspectorを開いて、右上のstaticをチェックする。ライトは全部Modeをbakedにする。これによって、オブジェクトやライトがベイクの対象になる。逆に動くオブジェクト、PickupやAnimatorで動くものはチェックしないこと。

f:id:o_mega:20190727100027p:plain

Lightingウインドウへ戻って、Generate Lightmapを押そう。するとちょっと待たされた後、ベイクされる。Sceneウインドウのワールドがシックになってるはずだ。Unity便利ですごい

AmbientOcclusionをオンにしてもいいだろう。凹みとかの陰が追加されるが、Lightmap解像度が低いと陰が回り込んでしまって、却って汚くなるかもしれない。この辺は様子を見て選ぼう

 

内部的には影のテクスチャ画像を生成して持つため、データサイズが大きい。雑にベイクするとあっさり10MBオーバーのワールドになる。しょうがないにゃあ…

f:id:o_mega:20190622041347p:plain

とりあえずできたがQuest用は汚いし、データサイズもデカくてひどい*4

ベイク情報(Lightmap)を軽くする&&縞々で汚いのを対処する。

LightmapSettingsを詰めよう。

 

なんで縞々かというと、画像の圧縮ノイズだ。どうもPCとQuest/Androidではテクスチャ圧縮方式が違う(追記 ASTC形式にすればマシのようだ)ようで、今回ほしいベイクテクスチャ(Lightmap)では特性が合わず、いい見た目にならないようだ*5。ので圧縮Compressionのチェックを外す。ただし、これは未圧縮になるためデータサイズが大きくなるので、併せて以下も行う

 

なんでサイズが大きいかというと、Unityがめっちゃ細かい影テクスチャを吐いていることに他ならない。なだらか~に明るい/暗いのが付けば雰囲気として今回はいいので、解像度を下げよう*6。今回はLightmap resolutionを40→10とした。これでサイズは理屈の上では1/16になるはずだ

なお、影解像度の低下が目立つ場合は、目立つGameObjectのLightmapだけ解像度を上げる手がある。RendererのLightmap - scale in lightmapを大きくすると、そのRendererだけLightmapの解像度があがる、とのこと。Unity公式ドキュメント

 

Lightmap sizeは… 正直よくわからん。ほどほどに小さい方が細切れになってメモリを効率よく使えそうだが、収まるなら少ない枚数のテクスチャに収まった方がいい気がする*7。極端に小さかったり大きかったりしなければいいのかな?

f:id:o_mega:20190622033616p:plain

最初に比べて解像度は1/4、Lightmapテクスチャは1/16になったが、なだらかできれいな影が付いた。データサイズも半分になり快適。ぶっちゃけ、PCでもこの解像度でいいやと思う程度には十分な品質だ*8*9

LightProbeって何?

LightProbe/LightProbeGroupというのは、Quest版VRChatでは「その空間明るさ情報」を事前計算した点、とそれをまとめたグループ。これがあると、ワールドの明るいところにいるアバターやモデルは明るく、暗いところにいるアバターやモデルは暗くなる*10。色が付いたライトがあればその色が付く。probeから離れた場所では、周辺のrobeから平均をとって明るさを計算してくれる。詳しくは【Unity】モバイル向けのライトマップTipsと、ライトマップを動的に更新するHack - テラシュールブログあたりで詳細を

 

内部的な話をすると、データはprobeごとに色情報の数値として保存されるらしく、データサイズは非常に小さい。ので極端に多くなければ、ぽこぽこprobeを置いてやって良いと思われる。*11

基本的には「周辺の光がつよいところ(光源の近くやEmission付きマテリアルが光ってる近く)」と「暗いところ」と「光の強さが急に変わるところ(光線が遮蔽されてる壁)」に置くといいらしい。自動化ツールもあるらしいので、それを使うのもよさそうだ(が、自分は手配置した)

f:id:o_mega:20190622040121p:plain

Unity上ではLightProbeごとに線が引かれ、LightProbeの範囲が表示される。この空間内/近くなら、それっぽく明るさが決まるということだ

ReflectionProbeって何?(Quest不要/PC専用)

ReflectionProbeはReflection、つまり反射の表現に使われる。鏡のように磨かれた鉄球に周囲の風景が映る、みたいなのをそれっぽく表現するための技術。これがあると、ワールド内に反射するものがあるか、反射するシェーダー付きのアバターがいるときにちゃんと風景が映って見える。フルフルにこれも計算すると重いので、ワールドの一部領域ごとに事前に360°撮影したテクスチャを用意しておき、その場所に来た時反射物にペタっと張ってそれらしく表現する。

 

が、これはシェーダー制限によってQuestにはないはず。PC版でのみ有効。

内部的には、前述のように360°画像テクスチャを持っているのでデータサイズは大きくなりがち。といっても、らしく反射すればいいのでそんな大きな解像度は割り当てなくていいんじゃないかな。部屋などの、周辺の風景がガラッと変わる場所ごとにProbeを設置する、ことが重要と思われる。

f:id:o_mega:20190622035951p:plain

反射オブジェクトがなければ作らなくてもいいモノだが、中には反射マテリアルを付けたアバターがあなたのワールドを訪問するかもしれない。という時はとりあえず1個置いてあると、極端に変にならないのではないか?(消極的対応)

ちなみにReflectionProbeがない場合、反射マテリアルはSkyboxなどの背景を使うようだ。Probeがないと「部屋の中にいるのに、反射マテリアルには空が写ってる」ということが起きうる

オクルージョンカリングって?

まだ自分は手を出せてない。詳しくはUnity公式説明を読んで。視界外かどうかを事前計算しておいて、GameObjectごと消すことで処理を軽くする。

広いワールドや、部屋がたくさん分かれたワールドを作るときに思い出すとよさそうだが、現行小さめのワールドが多いQuestでそういうワールドが来る機会はあるのだろうか?探索して遊ぶワールドとかにはいいかもしれない?

モデルのテクスチャサイズをプラットフォーム毎に自動的に縮小する&&テクスチャ圧縮をASTC形式にする

Unityのプラットフォームごとのオーバーライドという機能を使えば、自動で環境ごとにリサイズして出力ができる。テクスチャのinspectorを見て、PC用(Default)はこういう設定、下枠に環境ごと設定がある

f:id:o_mega:20190622151737p:plain

ぱっと見よくわからないがコレはタブになっているので、右のAndroidアイコンを押して、Override for Androidを押すと、環境ごとに自動で設定が切り替える機能が有効になる。あとはSizeなりFormatなりCompressionQualityをいじる。

f:id:o_mega:20190622151926p:plain

もう一つ、ASTC形式にする話はページを分けた。VRChat Questのテクスチャ形式はASTCにしよう - おめが?日記_(2) ASTCはAndroidで使える(比較的)新しいテクスチャ圧縮形式でQuestは対応している、RGB Crunched ETC/ETC2と比べてかなりキレイなので何も考えずFormatはASTC*12にしてよいと思う

最終的にどうなる

基本的には

  • シェーダーをQuest用にする

だけでQuest不可なものを除いて、Questワールドは動くはず

加えて

をするだけでサイズは劇的に小さく、かつ軽く、イカした見た目になるはずだ

自作ワールドjust RedFlagは当初10MB程度あったものが、4MB以下になってる。もともとモデルでのテクスチャ利用がほとんどないマップだったとは言え、Lightmap改善だけで半分以下になった。見栄えをそこまで犠牲にせず、ロードも早くなって実によい。

VRC_xxx系コンポーネントはVideoPlayer以外制限が緩い

そう、気づいてる人はそれなりにいそうだが、VRC_xxxx系コンポーネントや許可されたUnityコンポーネントはだいたいが動く。そこにチャンスはある、と思う。

のでギミックやゲーム作る人には朗報ではないだろうか?というか今作ってる。Vケット3までには見せられる形にしたい

他雑多な話

  • 当たり前だが、QuestにVRCミラーは重い*13。が、Questは現状自撮りができないのでミラーは欲しい。ので離れたら消えるミラー、ON/OFF切り替えできるローカルミラー等を配置しよう
  • レンダーテクスチャを使うカメラ(例・ナルさんのStarterKit付属のSimpleCameraなど)は割とすんなり動く。が、Quest相手にテクスチャサイズはあまり大きくない方が良いだろう。自分は1024pxにしている
  • Questでは距離に応じてテクスチャ解像度が切り替わるため、細かい文字を遠くから見る場面はつらい。配置するときは注意、近づいて読めるようにしよう
  • 他、CrossplatformAvatarワールドや、あたらしいHubやHomeなどVRChat運営が作ったワールドを見て、何となく察する(ミラーの挙動とか解像度とか)
  • 究極的にはQuest買って自分で見に行く。自分はそうした。いいぞ

f:id:o_mega:20190622152838p:plain

↑はPC版での見栄え、背景のLightmap書き込みも悪くない質感だが、これでもQuestあわせの低解像度。カメラのフラッシュを見るとPostProcessStackの効果でぼやっとしているのがわかる。これもポチポチするだけで視界がエモくなるので、オススメだぞ

いかがでしたか?

StandardLiteシェーダーをはっつけたCubeを並べ、Lightばらまいて綺麗で軽量なベイクができるだけで、なんかそれらしいQuestワールドは作れる。作れるんですよ。ほんとほんと。ワールドはアバターと違ってボーンだのアニメーションだのは必要ないし、アバター作るより絶対楽だぞ。

あとデータサイズがでかいのはだいたいテクスチャのせいなので、テクスチャサイズを小さくしましょう。まずはASTC形式にして、それでも足りなければプラットフォームオーバーライドで自動縮小させよう。圧縮は場面に応じて使い分けるとgood

*1:パフォーマンスはDuffuseなどのシェーダーと比べると良くないようだが、それでもQuestで十分速度が出て、かつStandardシェーダーと似たような設定ができる

*2:ほんとか?多分もっと抜本的な修正が必要なぐらい重くなってそう?

*3:UnityのメニューからWindow-Lighting-LightingSettingを開く

*4:platform PCだとこの時点で綺麗にでてしまうので、スルーしている人も多いと思う。自分はした

*5:圧縮方式を切り替える手もあるかもしれない。未調査

*6:もともとUnityのデフォルト値が細かすぎるというのもある

*7:一般的に、テクスチャ枚数が少ない方がGPUに優しい

*8:逆に考えると、Lightmapが1/16になったのにデータサイズは1/2にしかなっていない。Compressionは1/8サイズに圧縮をかけていたことがわかる

*9:どうも現行のテクスチャ圧縮でGPUが対応している圧縮は、圧縮状態でVRAMに格納され、VRAMの使用量削減になるようだ。さらに読み出しも早いそうなので、画質が若干下がる以外は圧縮にはメリットしかないようだ

*10:当然明るさを見てくれるシェーダーでないと効果はないが、VRC SDKの推奨シェーダーはこれを見ている。少なくともToonLitやStandardLiteは見ているし、Arktoonのような一般的にVRCで使われるシェーダーは見ているので安心しよう。逆に明るさを見ないシェーダーにはUnlitとかがある

*11:厳密には、多くなるとCPUパワーが食われる?ので管理できる程度に配置しよう

*12:ATSC 6x6 blocksとかASTC 8x8blocksあたりから試してみる

*13:数人で集まってオンにするとフレームが半分になるぐらい重い