見出し画像

静的なワールドをある程度なんとなくいい感じにするためのメモ(VRChat想定)

最近、晴れときどき猫団という団に入団した。ここはVRでイマーシブシアターをすることを目指して猫日和きゃりこ団長(ひとりじゃないよ~)が創設した団で、血の盟約によって結びついた団員が固い決意のもとで団長の厳しい指導に従って夜な夜な謎めいた儀式をVRの深奥で行・・・ってはおらず日々すてきなイマーシブシアターをVRで行うために団員それぞれの得意またはやってみたいを生かして体験型VR演劇を創造している
最近、この団では「鏡の外の晴れ猫学園」という公演を行ったが、ここで使われた学校のワールドのベース部分を僭越ながらぼくの方で作成させていただいた。この記事はその時にむぎせんにん団員(まぢで)のご指導の下で、ワールドをお客様に入っていただけるレベルにまで最適化していった時の記録をもとにして、アセットを置くことによって構築した静的なワールドの「プレハブの利用」「軽量化」「ライティング」などについての基礎的なやり方についてまとめたものである
(図として用いた写真はむぎせんにんさんからご提供いただきました)

本記事の主要な想定読者はぼく自身であるため、記事に用いられるターミノロジー等は独自のものがある可能性があることをお断りしておく
また、猫日和きゃりこ団長(ひとりじゃないよ~)とむぎせんにん団員(まぢで)のご許可を得て本記事は公開されているものの、文責は Dr.Nyao にあり、したがって本文中に間違い等があった場合はその責はすべてぼくにあることを明示的にお断りしておくし、まちがってんなーっつっておもったらだまってねーで教えろくださいありがとうございますありがとうございますありがとうございます in advance

晴れときどき猫団については目次の上にあるリンクより基礎的な情報を学習することができます
また、「鏡の外の晴れ猫学園」の公演については同じく目次の上にあるリンクよりドコカノうさぎさん・華蓮ちゃん(かわいい)(茶)と甘野氷さんによる2本の公式体験配信のアーカイブがあるので追体験してみると良いでしょう
また、メタシアター演劇祭で行われた人間の意識の闇に迫る異色のイマーシブ演劇「SELECT」についても公式中継番組のアーカイブがあるので是非ご覧になってみてください


1.

ぼくのワールド制作はこれまで我流で、出来上がったワールドはとても人様に入っていただけるようなものではなかった。基本的な方向性としては売り物のアセットを Unity 上で配置して、VRChat なり cluster なりで必要なコンポーネントを置いただけのワールドで、売り物のアセットのサンプルシーンをそのまま使ったり、場当たり的に草や木を生やしたりするために、入ると身動きすら取れないとか、高速でワールド全体が左右に振動しているとか、一定頻度で暗黒が訪れるなど、それはそれはひどいものが多かった
その多くはプライベートワールドとして VRChat のサーバーの奥でひっそりと眠っているが、やはり作ったワールドは見せびらかしたいもの。そこで今回の猫団での公演では勝手連で学校ワールドを作って「どやっ!」ってしてみたものの、あれこれダメなところがてんこ盛りでむぎせんにん団員(まぢで)のご指導のもとで最適化を行った

このような背景があるため、本記事では Unity Asset Store で購入したアセットを配置済みで、かつ、VRC World などのプラットフォーム特異的なコンポーネントも導入済みである状態の Unity プロジェクトがあることを前提とし、その最適化のプロセスをできるだけ簡便に記載する
すなわち本記事では、この記事を上から下までなぞることで、クソ重ワールドをある程度軽めにし、何日もかかっていたライトベイクもそこそこの時間で終わらせることができ、身動きすら取れなかったワールドの中でまあまあ動き回れるようになることを目指す
なお、booth などで購入したアセットを用いる場合はライセンスに注意すること
ぼくはライセンスのことを考えるのがめんどくさいので基本的に Unity Asset Store の Standard Unity Asset Store EULA のアセットを中心に使うようにしている

2.ワールドに配置されているオブジェクトをプレハブとして扱う

2-1.繰り返し使うひとかたまりのオブジェクト群をプレハブとしてまとめる

例えば学校の場合、教室には机やいす、黒板や壁、まど、ドアなどがある。これら個々のオブジェクトがバラバラのままでは、たくさんの教室にそれぞれたくさんのオブジェクトを手作業で配置しなくてはならずとても大変である。そこでこの「教室」のような繰り返し使う一連のオブジェクトの集合体は一体化して管理すると良い。これがプレハブ(Prefab)である

手順
0.まとめたいオブジェクトがすでにプレハブにまとまっている場合(上位の階層に青色の立方体が示されている場合)は直上の青色立方体を右クリックし「Unpack Prefab」を選択する

1.Hierarchy ウインドウで右クリックし、出てくるドロップダウンメニューから「Create Empty」を選ぶ

2.「Game Object」というオブジェクトができるのでここにプレハブとしてまとめたいオブジェクトを全てドラッグドロップする(この事を「Game Objectの子にする」または「Game Objectを親にする」と言う)

3.「Game Object」を適当な名前(それがプレハブの名称となる)に変え、Project ウインドウの Assets フォルダ内に適当なサブフォルダを作成して「Game Object」だったものをドラッグドロップする。ここで生成されるものがプレハブである

4.出来上がったプレハブは、格納したフォルダから Scene 上にドラッグドロップすることで配置することができる

・Assetsフォルダのウインドウからプレハブをダブルクリックすると Scene とは別にプレハブの内容のみを編集できる

・ここで「GameObject」のプレハブ内での位置を調整し(そこがハンドルになる)、Inspector ウインドウ上で座標を 0, 0, 0 にしておくこと

・CreateEmpty で空っぽのGameObjectを生成せず、プレハブにしたいオブジェクトのうちのひとつを親しても同様にプレハブ化できる

・3でドラッグドロップした時に Original Prefab にするか Prefab Variant にするかを聞かれたら Original Prefab を選ぶ
これはすでに Asset の中でプレハブになっているものを自前でプレハブ化するときに聞かれる

*オリジナルの Asset 内のプレハブをいじって最適化すると、それを他のプロジェクトで利活用することができない(他のプロジェクトでそのアセットを Asset Store などから導入するとオリジナルのものが導入されるため)。そこで、元のアセットとは独立した独自の Assets サブフォルダに自前のプレハブとして保存しておくと、それを流用することで別のプロジェクトに改変したプレハブを持ち込むことができる(5-1も参照のこと)

2-2.プレハブを入れ替える

作成・保存したプレハブは、ツール(kan.kikuchi様のReplacingPrefabWindow.cs)を用いることでプレハブ単位で入れ替えることができる。例えば教室を職員室に変えたい場合、同じサイズ・形状の「教室プレハブ」と「職員室プレハブ」があれば、それらを入れ替えることで任意の教室を職員室に変えることができる
プレハブのサイズや形が同じもので、例えば色や構成が異なるものを作っておくと、これを自在に入れ替えることができるので非常に簡単にワールドの構成を調整できる

手順
1.Project ウインドウの Assets フォルダに「Editor」というサブフォルダを作る

2.このページから「Download ZIP」ボタンを押してzipファイルをダウンロードして展開する

3.1で作った「Editor」サブフォルダに展開した.csファイルをドラッグドロップする

4.Unityの上部ドロップダウンメニューの「Tools」メニューから「ReplacingPrefabWindow」を選び、出てきたウインドウを「Inspector」があるウインドウに入れておく(別に入れなくてもいいけど入れておくとそのプロジェクトではいつでも使えるので楽)

5.4のウインドウにある「差し替え元のPrefab」へ上の例なら職員室プレハブをドラッグドロップし、差し替えたい教室プレハブを Hierarchy 上で選択する(「差し替えるオブジェクト一覧」に表示される)

6.差し替え実行ボタンを押す

手順1~3はひとつのプロジェクトについてツール導入時の一回のみ必要。一旦導入したら手順4~6または「ReplacingPrefabWindow」タブを選んで手順5~6を行えばプレハブを入れ替えられる

2-3.プレハブを使う時に留意すべき点

・プレハブに使われているオブジェクトはそのソースとなるアセットが導入されている場合に限って表示される

・プレハブが入れ子状態になっている場合、プレハブ内での変更の保存場所の決定は複雑なので、高位のプレハブはUnpackして入れ子構造のないプレハブとして扱う方が間違いが少ない

・プレハブが多くなると親子関係などがわかりづらくなるので、必要なアセット名は記録しておくこと。また、早いうちにサブフォルダ分けして整理しておくこと

3.ワールドの軽量化

3-1.テクスチャー解像度の調整

ワールドの容量自体が重くなる原因の一つとして、3Dモデルの表面の模様であるテクスチャファイルの解像度が高いことがあげられる
そこでまずはこれらテクスチャファイルの解像度を下げる

手順
1.Project ウインドウにある各アセットのフォルダからテクスチャファイルがまとまっているフォルダを開く

2.テクスチャファイル(アイコンは四角い形をしている)を選択し、Inspector 上の Max Size を512に、Compression を Low Quality にセットし、Apply ボタンを押す(図1)

図1:テクスチャファイルを選択して解像度と品質を下げる (by むぎせんにん)

3.これをアセットごとに繰り返す

・球状のアイコンはテクスチャファイルではない(マテリアルファイル)ので選択しないこと

・アセットによってはテクスチャファイルがいろいろな場所に散在していることがあるが頑張って全部処理すること

・この方法の場合、アセットの中身自体を書き換えているので別のプロジェクトに処理の結果を流用できないことに注意

・他のプロジェクトで流用したい場合はテクスチャファイル自体を Assets フォルダ配下の自前のサブフォルダにコピーして使用する必要があるがいろいろめんどくさい

*独自のテクスチャに改変して使う場合など、どうしても自前の Assets サブフォルダにテクスチャを置きたい場合は、一旦 Unity を閉じ、テクスチャファイルを Windows 上でコピー・適当な場所(Assets フォルダ下に専用のフォルダを作る)に配置したのち、必要に応じてイラストソフトなどで修正などを行い、その後 Unity 上でその内容を反映させる(同様に Windows 上でコピペしたマテリアルに改変したテクスチャを貼り付けて、その後オブジェクトに貼り付ける)

3-2.オクルージョンカリング

ワールドを作ったはいいが、入ってみたら身動きが取れないとかカックカクになってしまったりする場合がある。これは見える見えないにかかわらずプレイヤーの視線上にあるすべてのオブジェクトを描画しているためである。壁などに遮られて見えない部分などまで全て描画されるために計算量を圧迫し、それによって重いと感じる原因になる
この問題を解決するためには、壁などの視線を遮るオブジェクトの向こう側にあるものを描画しない設定を導入すると、描画量を圧倒的に少なくすることが可能となる。これがオクルージョンカリングである

一般的にはオブジェクトを選択されたときにInspector上に出てくる「Static」にチェックをつけることが推奨されていると思うが、その場合だと遮蔽物(Occluder)の設定と被遮蔽物(Occludee)の設定両方がなされる(Occluder static, Occludee static)。そのように設定した場合、細かいものまで大量に遮蔽物として設定されていることによってオクルージョンカリングの処理自体がプレイヤーの計算量を圧迫する可能性がある
そのためここでは遮蔽物と被遮蔽物を区別して設定を行う

手順
A:Occludee staticの設定
(図2)
1.Hierarchy の検索窓で「meshrenderer」を検索する

2.出てきた全てのオブジェクトの Inspector ウインドウで Static にチェックを入れる(子にも設定する)

3.Static の右横にある小さな三角をクリックし、出てきたドロップダウンウインドウ中の「Occluder static」のチェックを外す

図2:Occluder staticの設定

B:Occluder staticの設定(図3)
0a.まず遮蔽物としてなにを設定するかを定義する。多くの場合は壁、天井、床、建物の外壁、塀、岩などがそれにあたる。これらのオブジェクトまたはプレハブの名前に統一性を持たせ、検索でまとめて抽出できるようにする

0b.壁などに Occluder static を設定した場合、プレイヤーのアイポイントが接近するとカリングがかかってちらつく場合がある。なので、プレイヤーがかなり近づく可能性のある遮蔽物の場合はその内部に薄いキューブを仕込んでそれを遮蔽物とする。例えば部屋の壁の場合、壁にコライダーを入れてそれより先にプレイヤーが進めないようにしておいたうえで、部屋の壁と別の部屋の壁の間にキューブで作った板を置き、それを遮蔽物とする。これについても検索しやすい名前を付ける(例えば「Occluder」など)

1.遮蔽物と定義されたオブジェクトのキーワードを Hierarchy の検索窓に入力して一覧を得る

2.それらを全て選んだうえで Static にチェックを入れる(または Static の右横の三角をクリックして Occluder static にチェックを入れる)

図3:Occluder staticの設定 この場合floorをキーワードとしている

C:オクルージョンエリアの設定とベイク
1.Hierarchy ウインドウ上で右クリックをしてCreate Emptyを選び、できた Game Object の名前を「Occlusion Area」とする(名前はなんでもよい)

2.Inspector ウインドウの一番下にある「Add Component」ボタンを押し、検索窓に「occlusion area」と入力して出てくる「Occlusion Area」を選択する(アタッチする:Inspector に Occlusion Area という項目ができる)

3.Hierarchy 上で「Occlusion Area」をダブルクリックし、出てきた薄緑色の四角のエリアをオクルージョンを設定したいエリアを覆うようにサイズ調整する:サイズは立方体の各面にある円柱をドラッグすることで変えることができる

4.全ての遮蔽物と被遮蔽物を覆うように「Occlusion Area」を設定できたら、Inspector のあるウインドウの Occlusion タブ(無い場合は上部ドロップダウンメニューから「Window>Renderring>Occlusion Culling」で出てくるので Inspector の横にタブ化しておく)を開き、その中のBakeを開き「Smallest Occluder」の数字を1にする

5.右下にある「Bake」ボタンを押す

6.結果は Bake タブのとなりにある Visualizetion タブを開いた状態で、Hierarchy にある「MainCamera」を操作すると確認できる(図4)

図4:オクルージョンの確認

4.ライティング

VR空間内では光の陰影にも計算資源を使う。このためリアルタイムで影を描画する設定になっているとプレイヤーの計算量が増大し、重く感じる原因になる。このため、動きがない影についてはあらかじめ計算しておいてワールドに画像として(ライトマップ)貼り付けておくことで計算量を大幅に減らす作業を行うことがある。これをライトベイクという。
ライトベイクに当たっては、いくつか独立して設定しておくべき項目がある。ライトそのもの、ライトが当たるオブジェクト、そしてライティングそのものである

本項においてはオクルージョンカリングの設定が行われており、Static にチェックか横棒が入っていることを前提とする。入っていない場合はチェックを入れ、必要に応じて Occluder のチェックを外しておくこと

4-1.ライトの設定

ライトにはいくつか種類がある。Directional Light(太陽)、Point Light、Spot light、Area Lightの4種で、このうちArea Lightはライトベイクをしないと使えない
それ以外についてはライトのモードをReal Time 、Mixed(基本ライトベイクして動くものだけリアルタイム)、Baked(影は動かない:全部ライトベイクする)の3種類から選べる

手順
1.Hierarchy上で右クリックをし、「Light」から希望するライトを選んで適当な位置に配置する

2.Inspector の「Light」の項目で Mode を選ぶ。Shadow Type は「Soft Shadow」または「No shadow」、Resolution という項目がある場合は「Low Resolution」を選んでおく

・Light の Inspectorにある「Layer」ドロップダウンメニューで特定の Layer のみを選ぶとアバターだけに当たるライトを作ることができる。VRChat の場合は「Player」「Player local」「MirrorRelrection」にのみチェックを入れるとアバターのみを照らすことができる。逆にすればアバター以外を照らすライトを作れる。ワールドを赤くして、アバターはオリジナルの色を描画したいときなどに使い分けることが可能であるほか、アバターのみをリアルタイムで照らすなどの設定をすることで軽量化にも役立つ

・リアルタイムや mixed はなるべく減らした方が良い。Area Light がそこそこ均一に照らせて、かつ、必ず baked になるので便利

・Directional ライトは上向きにすると世界が夜になる。複数の Directional Light がある場合、世界の昼夜に関係する Directional ライトは Intensity が一番強いもの。Inspector の Light の項目にチェックが入っていなくても(つまり実際には何も照らしていなくても)昼夜には関与できる

4-2.ライトの当たるオブジェクト

オブジェクトの Inspector にある MeshRenderer という項目に設定すべき項目がある
また、モデルによっては影用の UV(展開図)が準備されていないものがあるのでその場合はUnity上で準備することができる
さらに、シェーダー設定で Emission にチェックを入れた場合は、そのオブジェクト自体を光らせることができ、その場合、それらについてもリアルタイムか baked にするかを選ぶ必要がある

手順
*影用の UV の準備*
1.導入したアセットの3Dモデルを表示させ、選択する(散在している場合もあるのでテクスチャーの場合と同様頑張って探していく)

2.Inspector の Generate Lightmap UV にチェックが入っていない場合、チェックを入れて Apply ボタンを押す

*オブジェクトごとの設定*
3.基本的に不要だが Inspector 上で以下の設定が異なっている場合は変更する
・Cast Shadows: On
・Reseived Shadows: チェック
・Scale in Lightmap: 1 (これは「調整と確認」で変更する可能性がある)

*オブジェクトを発光させる場合*
4.Inspector の Shader の項目を展開し、Emission にチェックがついている場合(発光させる場合)、Grobal Illumination を「Baked」にする

*リフレクションプローブを設置する*
部屋や廊下など、光の具合や反射を反映させるためにリフレクションプローブを置く。リフレクションプローブは四方を向いたカメラで、撮像された画像を指定した範囲にある光沢面に反映させる。特に窓ガラスや金属面などがある空間にはあった方が良い

5.Hierarchy で右クリックし、Lightメニューから Reflection Probe を選んで必要な空間に配置する

6.Inspector の Reflection Probe の項目の一番上にあるボタンの左側を押して、反射の範囲を設定する。設定は直方体の各面にあるポインターを操作することで可能

7.Inspectorで Type を「Baked」にする

*設定を確認する*
8.上部ドロップダウンメニューよりWindow>Rendaring>Light Explorerでライティング関係のセッティングを一覧でみることができる

9.Light、Reflection Probes、Static Emission の各項目を確認して間違いがないか確認する。
・モードが勝手に Realtime に切り替わっていることがあるので注意深く確認する
・Reflection Probesでは、屋外に置いた場合を除いて Projection は基本的にBoxにし、Far Plane は小さめにする(100とか)
・Static Emissiveでは不要な発光オブジェクトが無いかを確認し、不要なものがある場合はリンクアイコンをクリックして発光を消す

4-3.ライティングの設定

準備が出来たらライトをベイクする

1.上部ドロップダウンメニューよりWindow>Rendering>Lighting settingと選んで、出てきたウインドウ(Lighting)を Hierarchy のあるウインドウのタブにしておく

2.以下の通り設定する
・Environment Lighting: Skybox(重い場合はColorにして空の色を設定する)
・Lighting Mode: Shadowmask
・Lightmapper: Progressive GPU (Preview)
・Direct Samplings: 32
・Indirect Samplings: 512
・Environment Samplings 256
・Lightmap resolution: 10
・Lightmap size: 512
・Compress Lightmap: チェック
・Ambient Occlusion: チェック

3.ライトベイクを実行する(Generate Lighting ボタンを押す)

本番環境では Lightmapper を CPU にするとより良い見てくれになる場合がある

4-4.調整と確認

ライトを焼くと、時々おかしな模様や影が出てくることがある。その場合は以下のようにして再度焼き直す

1.おかしな焼け方をしたオブジェクトを選択し、Inspector から Scale in Lightmap の値を大きくする。最初は5くらい、良くならなければ10くらいと徐々に数字を大きくする

2.Scene ビューの右上にある「Shaded」というドロップダウンメニューで「Baked Lightmap」にチェックを入れると影のみを見ることができるのでライトベイクがおかしいかもと思ったら確認するとよい
なお、おなじメニューで Show Lightmap Resolution にチェックを入れておくと Scale in Lightmap に応じたライトマップの解像度が市松模様の細かさで表示されているので、参考にする

3.十分に市松模様が細かいのに影がおかしい場合は影用のUVが出来ているか確認する。それが問題ない場合はライトベイクの解像度やサンプリングのパラメーターを上げてみる

5.ワールドのバージョン/改変履歴管理

ワールドの制作が進んでくると、新たにアセットを導入したり、ライトを増やしたり、プレハブの関係性が複雑になってきたりするので、それらがあとからトレースできるように以下のような点を気を付ける必要がある

5-1.バックアップルール

バックアップは unity package の形で残す。残す際のルールは以下の通り
共同制作者との共有はこのバックアップと使用したアセットリストを用いる

手順
1.Project ウインドウの Assets フォルダ内に、ワールドについての記録を残すためのサブフォルダを設定する

2.Project(Hierarchy にある Scene)はこのフォルダに保存すること
自分で構成したプレハブや改変したテクスチャ・マテリアルもこのフォルダ内にサブフォルダを作って入れておくこと(コピーを保存しておくのではなく、正本をここに置いて、ここからSceneに配置する)
使っているアセットのリストもここに置いておく

3.ワールドの内容は、作業を終了するたびに空の GemeObject の子としたうえで1のフォルダにプレハブとして保存しておく(作業を再開するときには Unpack することを忘れないこと)

4.バックアップはProjectウインドウの Asset フォルダにある1のフォルダを右クリックすると出てくる Export Package を選択し、そのフォルダ以外のチェックを外して Unity package として保存する
Asset sotoreのアセットやその他売り物のアセットはバックアップ用Unity packageには含めないこと
サイズが巨大になるのも問題だが、制作をグループでやっている場合、制作途中のワールドをこのUnity packageのバックアップを用いてやり取りするときにパブリックなストレージを経由できなくなる

5.バックアップを復帰させる場合は、使用しているアセットを導入した空のプロジェクトに、Export してある Unity pakcage を導入する

5-2.使用しているアセットを導入するたびに記録する

アセットの内容物は多くの場合プレハブの材料として参照されているため、どのアセットを導入したかは、アセットを導入するたびにテキストファイルなどに記録すること
これは5-1で述べたようにバックアップからの復帰の際に重要である

5-3.なるべく細かくバックアップしておく

なるべく細かくバックアップしておくこと
バックアップデータが大きすぎる場合は、ライトベイクの情報を消すと軽い状態で保存できる。ライティングのタブの Generate Lighting ボタンにある小さな三角を押すと出てくるドロップダウンメニューから Clear Baked Data を選ぶとライトベイクの情報を消すことができる

6.

以上の内容を実践することで、それなりに重くない(重くないとは言ってない)ワールドができるはずだ。ただ、ここには入っていない重要なポイントとして、ライトプローブがある。ライトプローブは今回の公演のベースワールド制作時に取り入れようとしたのだけれど、なぜかうまくいかなかったため導入を断念した。これについては今後の課題である
また、ここで制作したベースワールドは動きもギミックもない、静的なワールドとなっており、動きのあるワールドの制作についても今後の課題である
同様に見てくれをファインチューニングするための PostProcess についても今回はいじっていない

また、Cluster のワールドを作る場合は、Layer 周りがかなり異なっているため注意が必要である。ただし、Cluster については公式がリリースしているクリエイターズガイドに詳しい記事が多いのでそれらを参考にすると大体何とかなる

本記事は、基本的にこれで一旦締めとするが、今後改訂が行われる可能性があることを最後に記しておきたいと思う


この記事が気に入ったらサポートをしてみませんか?