
みなさんこんにちは、MinaFrancescaです。
前回のライティングに関する記事はUnity2018までのもので、2022/2/15現在はUnity2019を使うルールとなっております。そのためライティングとそれに関連してくる様々な設定を、細かい説明は少なめにして「こうすればうまくいく!」というていで、Unity2019対応として改めてご紹介していきます。
もちろんここでご紹介する内容が何よりもベスト!ということではない、ということはご留意ください。
今回作業ワールドは私のHOMEワールド「みーなさんち」を使って説明していきます。
◆この記事について
なぜこうする必要があるのか?というお話は(一部をのぞき)最小限にして説明していきます。
ライティングに関する様々なマニュアルが既に世の中にたくさんありますが、それらでは紹介されていない、あるいはそれだけでは足りない部分を補っていきます。
ライティングだけでなくそれに関連するワールド作成のポイントもご紹介していきます。
それでは下記の項目順に説明していきます。
◆目次
・ヒエラルキーの整理整頓 ・綺麗なLightmapを焼く ・アバターの見た目を考慮したライティング ・オキュリュージョンカリング ・リフレクションプローブ ・PostProcessing ・室内と室外のライティングの変化 ・Lightmapが綺麗に焼けるMeshBaker設定 ・Realtime(Mixed)ライトも上手に使う
開発環境は下記の通りです。 Unity 2019.4.31f1 (64-bit) VRCSDK3 CyanTriggerを利用しています
ヒエラルキーの整理整頓
まずはライティング本編に入って行く前に、ちょっとお節介をさせてください。 ご自身のUnityのヒエラルキーをいまいちど眺めてみませんか?ヒエラルキーの整理整頓は、小さなプロジェクトではさほど問題になりませんが、配置するオブジェクトが多くなればなるほど、あとから管理が大変になってきます。

私はこちらのアセットを利用しています。 Rainbow Hierarchy 2 https://assetstore.unity.com/packages/tools/utilities/rainbow-hierarchy-2-106670?locale=ja-JP
具体的にどんなことが出来るのかというと、階層になる部分に点線が付与されるのと、ゲームオブジェクトにアイコンを設定できます。 また、上の画像では目のマークのアイコンが非表示になっています。これはビルド時に非表示にしておくべきオブジェクトを指しています。こうすることで後から「あれ?これは出しておくんだっけ?消しておくんだっけ?」と迷うことが無くなります。
次に命名規則を自分の中で決めて、出来る限りそれを守っていくことを心がけましょう。私の場合はパスカルケース(先頭を大文字)です。上記画像では見えませんが、さらにアンダースコアやハイフンをうまく使い分けると便利です。 例として、「Lighting-Night / Lighting-Day」など。
そしてそれぞれを空オブジェクトで、いわゆるフォルダ分けされているような状態を作ると美しいヒエラルキーとなるでしょう。ワールドのセッティングに関するもの、ライティングに関するもの、サウンドに関するもの、といった具合に分けて整頓しましょう。
プロジェクトが大きくなる予定の方は、このあたりの細かいことがあとからじわじわと負担になってきますので、ぜひお勧めしたいところです。
綺麗なLightmapを焼く

Lightmap Parametersを作成します。

Lightmap Parametersをこのように設定します

MeshRendererコンポーネントのScale In Lightmapを10に設定します

ヒエラルキーでMeshRendererと検索すると、
MeshRendererコンポーネントが付与されているオブジェクトを一括で選択、
設定変更できます。

モデルのインポート画面。赤枠部分のように設定します。

skpモデルの場合です。赤枠のように設定します。

こちらはfbxやobjモデルの場合です。赤枠のように設定します。
Generate Back Face メッシュの裏面が無くて透明になって困る場合は「Generate Back Face」にチェックを入れます。
Generate Colliders コライダーを設定する予定がある場合は、こちらをチェックしておくと、あとから大量にコライダーを設定する必要がなく便利です。
Mesh Compression メッシュを圧縮して軽量化する設定です。圧縮率は微妙ですが通常Highで大丈夫です。 稀にこの設定によってメッシュが破綻したり、ジラジラと重なっているかのような見た目になってしまう場合があります。見た目がおかしいな?と思ったらこの設定を疑ってください。

PointLightを配置しましょう。
Lightは、オブジェクトの中に埋もれないように配置します。 通常は「No Shadows」の設定で大丈夫ですが、味のある影、ホラワなどのボソボソとした感じがお好みであれば「Soft Shadow」を使ってみるのも良いかもしれません。

PointLightをたくさんおいていくと、何故か光ってくれないLightが出てきます。
こちらの設定を参考にしてください。Pixel Light Countが低く設定されていることが原因です。
これはプレイヤーの視界内で一度に処理してくれるライトの数で、多くすればするほど負荷は高まります。しかし結局はBakeしますのでUnityエディター上で不便のないように数値をあがておきます。
※VRChat内においてはこの設定は反映されないとのご指摘がありましたので若干文章調整しました。

焼きたいオブジェクトをStaticにします。
闇雲にすべてをStaticにするのではなく、Contribute GIにチェックを入れるだけでもBakeの対象になります。動かす予定のもの、例えばドアやコップなど。こういったものはContribute GIのみにチェックを入れます。鏡面反射させたい場合はReflection Probe Static もチェックを入れます。

画像のように設定します。

画像のように設定します。
Lightmap Resolution / Lightmap Size こちらは仕上げの場合の数値です。開発段階では、「5 / 512」くらいで十分です。
Lightmapper Progressive GPU(Preview)に設定します。グラフィックボードで焼くのでとても高速です。 対応していないグラフィックボードをお使いの場合は、Bake時にここが勝手にCPUに設定しなおされてしまいます。勝手に設定が変わってしまってGPUでBakeが始まらない場合は、新しい高性能なグラフィックボードの購入を検討しましょう。

さてこの設定は意見が分かれるところです。私は基本Directional LightはBakeしません。
何故Bakeしないかの理由として下記があげられます。Bakeしてしまうといろいろな問題が起こります。(問題ない場合もあります、ケースバイケースです)
ワールド制作に関する問題
・樹や草の影が地面に落ちない
・風で樹の葉が揺れているのにその影が動いてなくて不自然
・焼いたけどなんか汚い、不自然
・樹や草が真っ黒になる
・いつまでたってもBakeが始まらない場合がある
・水シェーダーを使った水が消える
アバターに関する問題
・アバターが真っ暗
・アバターによる影が落ちない
ビジュアル面でいろいろな問題が起こります。上記を踏まえてDirectionalLightをBakeしても大丈夫なケースとそうではないケースを考えてみます。
DirectionalLightを焼いてもOKなケース
・Terrainの樹、草、水シェーダーを使った水を使用していない
・太陽光(月光)が必要ないワンルームなどの室内シーン、閉鎖空間、箱もの
・大人数が集まる予定があるのでとにかく軽量化したい
・リアルタイムの影は無くても良い、ビジュアルにそんなにこだわっていない
DirectionalLightを焼かないほうが良いケース
・太陽光(月光)による木陰を表現したい
・昼夜サイクル、またはその切り替えを実装したい
・Terrainによる草木が配置されている自然豊かなシーン
・水シェーダーを使用した水があるシーン
・アバターの見た目を、どんなシェーダーを使ったアバターでも出来るだけ均一にしたい
・とにかくビジュアル面を損ないたくない
アバターのシェーダーが闇鍋状態のVRChat。アバターが真っ暗になってしまってワールドを気に入ってもらえない、というのは出来れば避けたいですよね。 LightProbeを利用して事前計算させる手法もありますが、ライトが無いところに行くと急激にアバターがまっくらになってしまって、明るく見える特定位置に立ち続けてフレンドと会話した経験はありませんか? VRChatの必死の最適化により、Directional Lightを焼かなくても十分90FPSに到達するワールドを創ることが可能です。
前回のUnity2018の記事では「とりあえずこうしておけば」という体でしたが、いろいろ賛否、意見の分かれるところなので、今回はもっとじっくり掘り下げていきます。
以下に続きます。
アバターの見た目を考慮したライティング

左が「Player」ではないレイヤー。右が「Player」のレイヤーです。
Directional Lightを2つ用意して、それぞれワールド用とアバター(プレイヤー)用とで使い分けることで、背景に埋もれないアバターの明るさを保持できます。
この方法は、アバター用のDirectionalLightが別にあるので、DirectionalLightを焼きたい方にも有用です。

ワールド全体に適用されるDirectionalLightです。(焼きたい方はBake設定に)

ただしCulling Maskの設定でこれらのチェックを外します。

アバター(Player)用のDirectional Lightです。これらにチェックを入れます。
こうすることで、ワールドとアバター(プレイヤー)とで別々の明るさを設定できます。

実際に自身のアバターを配置し、レイヤーをPlayerに設定してみましょう。
アバター(プレイヤー)が心地よい明るさで見えるように、アバター用のDirectional Lightの明るさを調整しましょう。 Culling Maskによって光の及ぶものを制御しているので、Directional Lightを2つ置いたから負荷が2倍、なんてことにはなりません。ご安心ください。 これで、ワールドのビジュアルを保ちつつアバターの見た目も確保できますし、どうしてもDirectionalLightを焼きたいという場合でもアバターの見た目を損なうことはありません。
同じように水にだけ有効なDirectionalLightを作れば、水シェーダーを生かすことが出来ますね。
この方法を提示した上で私はDirectionalLightは焼かないことを選択しています。私の作るワールドは樹々や草花が多く、室内と室外のシーンが共存しています。
太陽光(月光)を表現するとその自然な光と影によって見栄えも良くなります。
またどんなシェーダーを使ったアバターであっても、出来るだけ皆同じような明るさで見えるアバターで鏡の前に立って楽しくトークを楽しみたいのです。
60マイルにも及ぶ実績を経てこの方法に辿り着いております。もしまだどうしたらいいかわからないという方や、特にこだわりはないよという方は、ぜひ当記事の通りにチャレンジしてみてくださいね。
オキュリュージョンカリング

ライティングとは外れますが、一応ざっくり説明しておきますね。
オキュリュージョンカリングは、「Occlusion Area」というコンポーネントをCubeに付与し、設定したい範囲をこの画像のように覆ってください。
闇雲に全体をオキュリュージョンカリングBakeしてしまうと、ワールド容量が大きくなってしまいます。

室内がある場合は1~2。広いフィールドの場合は5~10くらいです。
リフレクションプローブ

鏡のようなオブジェクトや、反射して背景が映り込むようなオブジェクトがある場合は、ReflectionProbeを配置しましょう。
後ろのスタンドミラーにご注目ください。反対側の本棚が映り込んでいます。

とても現実味が増しますのでぜひ設定しましょう。
PostProcessing

Nearを0.01に設定しましょう。ガチ恋距離設定です。必須です。マストです。これによって育まれる愛がVRCにはあります。

PPS(命名はなんでも大丈夫です)という空オブジェクトを作成して、Post Process Volumeのコンポーネントを付与します。
レイヤーを先ほどのTransparentFX(他のレイヤーでも良いのですがこれが一番それっぽい名前のレイヤーなので私はこれにしています)に設定するのをお忘れなく。これで画面効果がかかります。
※どのタイミングなのかわからないのですが、Layer22がPostProcessingとして名称が自動設定されるようになっているみたいなのでそちらを使用すると良さそうです。

VRCWorldのPrefabを配置していることと思います。
Reference Cameraの設定にMain Cameraを必ずセットしてください。
VRChatにアップロードした時に、この設定が空のままだと画面効果がかかりません。

街灯はぼんやりと光ると良い感じです。

眩しくしすぎると苦情がくるので注意しましょう。
室内と室外のライティングの変化

室内に入る時と出る時でアニメーションを設定し、スムーズにライティングを切り替えます。
アニメーションによってPostProcessのGlobalのスライダーが動いていることに注目してください。 これによって室内と室外のライティングをスムーズに切り替えます。


入り口付近にIsTriggerのコライダーを配置し、CyanTriggerでプレイヤーとの接触判定を取ります。
ここではAnimatorのtriggerに、出た時と入った時とで0と1を代入しています。

triggerが0の時と1の時とでステートを移動します。これによりAnimationClipを出し分けて、室内と室外とでライティングを分けています。

ちなみにリスポーンして瞬時に外に出た場合を想定して、resetというトリガーを作り、瞬時にステートを戻す処理も忘れずに入れておくとよいでしょう。

その場合、リスポーン地点にIsTriggerのコライダーを置き、ここでAnimatorにresetのトリガーを引くようにCyanTriggerで設定します。

プレイヤーの接触判定によってresetのトリガーを引き、なおかつtriggerの数値を0に戻します。室内だけのワールドでは必要ありませんが、お外に素敵なお庭を作りたい!という場合には有用です。
Lightmapが綺麗に焼けるMeshBaker設定
残念ながらこちらの設定をもってしてもうまく焼けないケースは十分にあります。
オブジェクトが真っ黒になってしまったり、そもそもBakeがいつまで経っても始まらない、ということもありますし、MeshBakeしたものが多かったり、アトラス化したテクスチャがものすごく大きいと、解像度をちょっと下げるだけでずいぶんと見た目が損なわれてしまうため、結果ワールド容量が肥大化する傾向にあります。
ここでは私の経験上もっとも成功率の高い設定をご紹介します。お悩みの方はぜひお試しください。

ワールド制作の場合は「TextureBaker and MultiMeshBaker」を使います。

対象オブジェクトを設定する画面です。
Exclude meshes with out-of-bounds UVsのチェックを外します。

正しくオブジェクトが設定されたかを確認します。

Create Empty Assets For Combined Materialのボタンでassetを作成します。

Multiple Combines Materialにチェックを入れて、すぐ下のボタンを押します。

ここがポイントです。Consider Mesh UVsすべてにチェックをいれます。
最後にBlend Non- Texture Propertiesにチェックを入れて、紫色のボタンを押します。

最後はおなじみの設定です。
以上で、最後に「Bake All Child MeshBakers」を押します。 何か問題がある場合は押しても一瞬で処理が終わってしまったり、エラーがログに出現したりします。

まとめたMeshがこのように出力されます。

Scall in Lightmap を10に設定するのをお忘れなく。

MeshBakeが終わったあとに残ったMeshBakerのゲームオブジェクトは消しても良いのですが、あとでまた同じ設定で利用したい場合もあるかもしれません。 また、MeshBakeする前のオブジェクトは、念のためバックアップでとっておくと安全です。 しかしそのままではビルド時にこれらも含まれてしまいワールドサイズに加算されてしまいます。 そこで赤枠部分を「EditorOnly」に設定します。これでビルド時にはこれらのオブジェクトが含まれなくなりますので便利です。
一度Lightmapを焼いてあるものをMeshBakeすると上の画像のようにLightmapの画像が紐づいてきたりしますが、これはMeshBakeした結果のオブジェクトには適合していないので、一度Lightmapをクリアして再度Bakeしなおす必要があります。

LightmapのデータはScene名と同じフォルダが生成されてそこに保存されています。
赤枠部分にチェックを入れ、クランチ圧縮をしましょう。
それでもファイルサイズが大きい場合はMaxSizeを512くらいまでは落としても大丈夫です。Reflection Probeも同じ場所に生成されています。こちらも赤枠部分にチェックを入れてクランチ圧縮しましょう。
Realtime(Mixed)ライトも上手に使う
ライトは全部ベイクするんだ・・・!という使命感に囚われていませんか? 実はRealtime(Mixed)のライトもとても有用ですし、Bakedライトでは表現できないことが多々あります。 ここではそのいくつかの設定例をご紹介します。

例えば水面に浮かぶ、あるいは半分くらい沈んでいるクリスタル。Bloomで処理しても良いのですが、水面にぼやぁっと青い光が当たると、水面がとても綺麗になります。
青いPointLightを置くとこのように綺麗な水面を表現できます。

Realtimeのライトは負荷が高い、という認識は間違いではありませんが、使い方をしっかりわきまえれば、負荷は最小限に絵心あるビジュアルを生みだせます。

赤枠部分に注目します。
RealtimeでもMixedでもどちらでも構いません。
Rangeが極めて小さい数値です。その代わりにIntensityがかなり高い数値です。
Rangeは広げて光が当たる面積が増えれば増えるほど負荷がグングン高まりますが、Intensityはどんなにあげても大きな負荷にはなりません。
ShadowTypeはもちろんNo Shadowsです。
そして最後にCullingMaskのプルダウンを確認しましょう。

Player、PlayerLocal、MirrorReflectionのチェックを外します。これでアバターにはこのライトが及ばないため負荷としてはだいぶおさえられますし、Intensityを高めに設定していてもアバターには及ばないためアバターが真っ白になる、なんてこともありません。
水面にだけ光を反映させたいのであれば、WaterのレイヤーだけにチェックでもOKです。

こちらの場合はどうでしょう。地面に置くタイプのお洒落照明ですが、現実世界であれば周囲の地面がぼんやりと明るくなるはずです。
残念ながらTerrainのLightmap焼き付けは私はあまりお勧めしません。2Dテクスチャの草を生やしている場合、草は焼けませんし、樹々を焼こうとすると樹々は真っ黒になってしまいます。つまり不自然な画になってしまう、ということです。

そこでRealtimeライトの出番です。先ほどの水面のクリスタルと同様に、Rangeを極めて小さくし、Intensityを高く設定します。

Rangeは1です。とても狭い範囲なので負荷もかなり抑えられています。

TerrainはEnvironmentのレイヤーなので、このようにCullingMaskのプルダウンでEnvironmentだけにチェックを入れます。 こうすることでTerrainにしか光が及ばないので、負荷をかなり最小限に出来ます。
ですがもちろん使いすぎは禁物です。広く見渡せる場所でこれを多用するとすぐにSetPassCallsが跳ね上がります。
◆編集後記
以上でUnity2019対応版ライティングの記事とさせていただきます。いかがだったでしょうか。 Google検索ですぐに見つかるライティング記事では、残念ながら情報が不足しているように思います。より多くの方が自由にのびのびとUnityのライティングを楽しく行えるよう、今回Unity2019対応版として新しく書かせていただきました。 また、CyanTriggerとAnimatorを使った室外と室内のライティング切り替えの仕組みや、そもそもBakeしないという選択肢。 何もかも必ずBakeしなければならない、というわけではなく、素敵なビジュアル、景観を創り出すために、Realtimeのライトも賢く使うということをご紹介させていただきました。
それから今回もBakeryに関する内容は省かせていただきました。というのも、Unity2019になってGPUでのBakeがよりスムーズに行えるようになったため、ますますBakeryを使う意味は薄れました。VRChatのワールドに行って、これはBakeryで焼いてるな!なんて見分けはまずつかないでしょうし、Bakeryじゃなくても綺麗にLightmapは焼けます。
ライティングはとても楽しい工程です。素っ気なかった景色がグンと見栄えするものになっていく工程です。設定項目や覚えなきゃいけないことは確かに多いのですが、まずはこの記事で紹介されているままにライティングにチャレンジしてみましょう。 より多くの方がVRChatで素敵なお部屋やお庭を手に入れられるよう、本記事をぜひ多くの方とシェアをお願いいたします。 それでは楽しいVRChatライフを。
MinaFrancescaでした。