【Unity】入門ライティング設定！

## 概要
最初は**「(簡易的な)VRChatのワールド最適化について」**としようと思ったのですが、結局ワールド作成における最適化の話は**（殆どライティングの話になるな）**と思ったので、さっとUnityのライティングについて網羅できる記事を書こうと思います。
「Unity 最適化」で調べても、話としてはC#の事とかメモリの管理の話が中心で「VRChatのワールド最適化」とはまた話が異なるので、この記事を書こうと思いました。
あまりガチガチの話はできないので、**VRChatでワールド作り始めた人向けの記事**として書きます。

## 目標設定
![Lighting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149449/47099ca4-6dc6-a2c9-67c2-7ddf0de723e4.png)
VRCで指定されてるUnity2017.4.15f1を使用しています。
スフィアとキューブだけを並べた新規のシーンを作成。**(あまり重くならないように)**ライトの設定だけで画作りを行ってゆく。
マテリアルのShaderはスタンダードShaderです。

## Hello Unity
![Auto.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149449/83784097-6c95-5ee1-7a43-99c69b24afd5.png)
まず、エディタのメニューバー[Window]>[Lighting]>[Setting]でタブを開いて**[Auto Generate]のチェックを外しましょう。**
Unityの教本にはほぼほぼ書いてあって、分かってる人からすると当たり前なのですが…もしかすると、導線によってはそういった情報が手に入らない可能性はあるので触れておきます。

Auto Generateとは、**作業中にUnityが自動でライトの計算を行ってくれる機能**なのですが、大体のフローとしてはWorldをセットアップして区切りがついた段階でライトの計算をする方がスムーズです。デフォルトだとオンになっているので外します。
**チェックを外した後は手動でベイク(ライトの計算を行う)してから、プレビュー**してゆきます。

ちなみに、**Lightingの設定はSceneと紐づいている**ので、[add Scene]から新規に作成した場合、最初に外す必要があります。
プロジェクト単位の設定ではない事に注意が必要です。

**Generate Lightmap UV's**
ライトをベイクしたらモデルが汚くなった！という方は、アセットフォルダからモデルの設定を確認してみてください。
<a target="blank" href="http://nn-hokuson.hatenablog.com/entry/2017/01/30/193251">【Unity】Unity5でライトをベイクした結果が汚い</a>

## ライト(Light)コンポートを知る
![UniLighting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149449/0beb60ca-9d4b-58c2-693e-63c365948938.png)
ワールドをセットアップする場合、極力Lightの持つプロパティについて説明できるようにしておくのがよいです。

何故なら、ムービーなどで使われる3Dは１枚の画像をレンダリングに時間をかけるプリレンダと呼ばれる物に対して、ゲームは**リアルタイムレンダリング**でリアルタイムに実行されるからです。
そもそも光のシュミレーションという時間のかかる処理を、**短時間でそれっぽく見せるのがリアルタイムレンダリングの技術**なので、最適化をするにしても理解が必要というわけです。
代表的な部分についてざっくり説明します。
あと全てのコンポートで共通ですが、ハテナマークの辞書をクリックすると、リファレンスに飛びます。
<a target="blank" href="https://docs.unity3d.com/ja/current/Manual/class-Light.html">Light インスペクター</a>

### Mode （ライトのベイクについて）
**Realtime(リアルタイム)、 Mixed(両方)、 Baked(焼き込み、事前計算)**　があります。
VRChatの場合「リアルタイムが１灯～２灯、他はベイク」ぐらいを目安に考えるのがいいと思います。
（もちろん、作りたいものや演出によって異なるので、あくまで目安です）
Mixedは「動いてる物に対してはリアルタイム、止まってる物に対してはBakeする」というだけなので、リアルタイムとして数えます。

![Bakestatic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149449/02462a5f-1a69-d6b0-a2c1-0248a0203171.png)
>ゲームを実行してから[Status]を押すと、レンダリングをするのに行われている処理の統計が確認できます。
>注目すべき箇所は Batch と SetPass calls の値で…この値を減らすことで'レンダリンに必要な'処理は軽くなります。

それではベイクの説明に移ります。
**上の画像は「全てのオブジェクトをstaticにしてBaked」**したのに対して、**下の画像はオブジェクトを配置しただけで何せずそのまま実行しています。(非static）**
ライトは「ディレクショナルライト（Mixed）１灯のみ」で共通です。

**見た目は同じなのにパフォーマンスが異なります。**
リアルタイムの場合 Saved by batching が 0 で Batches と SetPass の値が大きく…
ベイクの場合 Saved by batching が 13 で Batches と SetPass の値が小さくなっています。

どういう事か？といいますと…**バッチ(Batches)処理とは「(ざっくり)まとめて処理する」**という意味で。
リアルタイム(非スタティック)ではまとめられる処理が無いのに対して、スタティックにしてベイクするとまとめられる処理が増えるので処理が最適化されるという事です。

リアルタイムの場合、**オブジェクトが動く可能性を考慮しています。**
ゲームである以上、外的要因が加わり動いたり、消えたりする可能性があるので、動くオブジェクトは毎フレームオブジェクトの状態を見た上で計算する必要があるわけです。
なので、リアルタイム(非スタティック)の場合、**似たような見た目であってもそれぞれ結果が異なる可能性があるので、処理がまとめられず…１つのオブジェクト毎に１つ１つ処理する必要がある。**という事です。
スタティックでオブジェクトが止まっていれば、Unityがレンダリングを最適化しやすくなるので、バッチ(Saved by batching)が増えます。

また「ライトを焼き込む(ベイク)」といい、ライトは事前計算する事ができます。
**ゲーム的に破壊されない建物などの場合、動かないので毎フレーム計算する必要はない**わけです。
そういったものは**「ライトの結果を事前に計算しておいて表示する」**という方法がとれます。
これなら、高速かつ高品質な結果が得られるわけです。（ベイクした計算済みの結果は必要なので、メモリは必要）

まとめると…
・ベイクできるものについてはベイクしよう！（持てる物などはベイクすると矛盾するのでしない）
・スタティックにできるものはスタティックにしよう！
・そもそも、レンダリンとかプログラムとか難しい事抜きにして**「まとまってると仕事がしやすい」**というのは人もコンピューターも同じだぞ！

### Type(ライトの種類について)
Directional, Point, Spot ,Area とありますが、ポイントライトとディレクショナルライトについて触れておきます。

![d.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149449/10974ec0-4a95-9bdc-eaaa-80583cccb98e.jpeg)
Directionalライトは影響範囲こそ広いものの**「光の強さは一定」**のモデルなので、計算は単純化しやすい。
**太陽光の差し込む方向ベクトル** と **明るさ** だけあれば基本的なシュミレーションはできてしまう。

![p.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149449/e44798f6-9ae0-e76a-29cd-3fc6411205c6.jpeg)
一方で、**ポイントライトとは１点から周囲に広がるの光で、距離によって減衰する効果を持つ**
これをプログラムとして表現する時どうなるか？
まず、光の方向ベクトルは一方方向だけでなく、三次元の放射状広がるベクトルとなる。光の当たったポリゴンによって光のベクトルは異なる。
また、減衰を考慮するので、光源からオブジェクトまでの距離を求めて、光の当たった箇所の光の強さを求める必要がある。あきらかに**計算回数が多い**。

>体感的に、自然現象をプログラムに直した時（計算複雑そうだな）って思う感覚が必要。

要するに**Directionalライトは単純なモデルに対して、ポイントライトは処理の多いモデル**という事です。
で大事なのは「ポイントライトを使うな」という事ではなく**「ポイントライトは効果的に使おう」**という事である。

ポイントライトで表現できるのは暖炉の火や、焚火などが考えられる。非常に魅力的。
つまり、ライティングの主役は**こいつに決めて**（演出による）そこから主役を盛り上げるようにライティングを設計する。
あと、**ベイクできるポイントライトは極力ベイクしましょう。**
ベイクしてしまえば実行時の処理はさほどかからないので、雰囲気の出るよい光源を軽量に扱える。

### その他設定
**Intensity**
明るさ。ただ、**リアルタイムなライトの場合、よほどの事がない限り１をベースに考える**のがよいです。
VRChatはワールドによって光源が異なる為、**実際問題Shaderの最適な設定はワールド毎に異なる**のが現実です。
VRCで人気のShaderはワールド毎に環境が異なるという特殊な状況を加味した上で、最大公約数となる処理を行っています。
なので、明るさに変わった値を入れてしまうのは得策ではありません。（ベイクするライトは関係ない）

**Shadow Type**
床に落ちる影の設定。**リアルタイムなライトの場合、暗いワールドで影がなくても矛盾しない場合は**切った方が無難。
ちなみに シャドウ(影) と シェード(陰) は意味が違う。
<a target="blank" href="https://docs.unity3d.com/ja/current/Manual/ShadowOverview.html">影</a>

## 環境光について(Environment)
ライティングの設計において、ポストプロセス以上に大事だと思うのが、環境光(Environment)だと思います。

![e.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149449/09b25011-d783-19b1-0d32-c21a3ad7e18d.gif)
一目瞭然だと思いますが、落ちてる影の色を変える事ができます。
EnvironmentLoghtingは**デフォルトの場合「Source Skybox」になっており、Unityデフォルトのプロシージャルskydomeを使用するとプロシージャルskydomeの色を影として与えます。**
新海誠監督の映像などを見ると分かりますが、**落ちてる影すらも色鮮やか**です。
つまり、空気感のようなものを演出する場合はEnvironmentLoghtingを絶対にいじる必要があり、理解する必要があるわけです。
**そもそも拡散光とはどういう事なのか？**みたいなのは、美術書とかに載ってます。

![en.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149449/775ef1ff-0b2c-e9c8-fb96-ee3dd2268734.png)
今回は「頑張っていい感じの夕方にする」という目標でライティングしてゆきます。
ひとまず、現段階では上記のような環境光にして、夕方にしてみます。

## リフレクションプローブについて

![reflection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149449/9b444eee-beb3-38ad-c212-b43009113406.png)
**左がリフレクションプローブなし、右がリフレクションプローブ有り**
よくみると左は室内なのにスカイボックスを反射していて、右はちゃんと室内を反射しています。

リフレクションプローブとは、**物体が反射した時の映り込みに使うデータ**です。
細かい使い方等は、調べてください… <a target="blank" href="https://docs.unity3d.com/ja/current/Manual/UsingReflectionProbes.html">リフレクションプローブの使用</a>

主に、物体を鏡面反射させたい時に出てくるので、一見するとワールドに鏡面のものがなければ関係ないように思います。（大理石とか、光沢のあつ机とか、ガラスとかが無いワールド）
しかし、**ワールドに訪れた人の中に、反射する金属のマテリアルを設定している可能性**はあります。
また、見栄えもよくなり、室内なのに空を反射するといった矛盾もなくなるので**Bakedであれば基本的に設定し得です。**
設定するようにしましょう。

![rihureku.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149449/f811f767-0a53-2556-f3e4-1f078a9a1f8e.png)
また、リフレクションプローブの映り込みで違和感のあるものに関してはstaticのメニューからチェックを外すと、リフレクションプローブのベイク対象から外されます。

## 以上を踏まえてライティング
![20190414054922img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149449/30a7757e-3fd5-4b01-e947-da31cfeedf53.png)
セットアップ直後

![20190414101131img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149449/f6fbc452-7b8d-9dba-356e-40527d0f3ba2.png)
ライト調整後（ポストエフェクトなし）

ライトは…ディレクショナルライト(Mixd)×１、ポイントライト(Bake)×２で、ポイントライトは窓際の落ちてる光と、室内の明かりで１灯つかいました。
結局スカイボックスはアセットを使用しました…どうしてもディレクショナルライトを傾けて空の色を変える場合、他のライティングを邪魔するのと、(プロシージャルスカイボックスの色を変えたくて)角度のキツイディレクショナルライトを置く事になるぐらいであればスカイボックスを変えた方がいいです。
（リアルタイムライトはキャラにも落ちるので）

・環境光(Environment)の調整
・基本ライトの使用（＋マテリアルの調整）
・リフレクションプローブを普通にセットアップ
以上に気を遣うだけで、余計な処理を行わずにそれっぽくできます。

ここからポストエフェクトを追加すればよりよくなるとおもいます。
<a target="blank" href="https://youtu.be/r5mNmH68KPQ">【Unite 2017 Tokyo】ゲームの見た目も盛ったら変わる！ヤバい！ポストプロセス！入門！</a>

## おわり
これでUnityのライティング入門の話は終わりです。
初学者向けの表面的な内容だけをなぞってるので、ステップアップしたい場合は個人的に以下の教材が良かったです。（保証はしません）

<a target="blank" href="https://www.amazon.co.jp/dp/4862461530/ref=cm_sw_r_tw_dp_U_x_FaPSCb2EWTQ39">カラー&ライト ~リアリズムのための色彩と光の描き方</a>
Unityとは関係ない美術本ですが、光とか色の捉え方や表現の仕方、考え方など学べます。
絵にかくか、CGにするかの違いなので、そもそもの絵作りの正解とは何か？を考えるヒントになります。
この本で言われてる事をUnityに置き換える事ができればいいわけです。

## 参考リンク
<a target="blank" href="https://docs.unity3d.com/ja/current/Manual/LightingInUnity.html">ライティングの概要</a>
<a target="blank" href="https://docs.unity3d.com/ja/current/Manual/OptimizingGraphicsPerformance.html">グラフィックスパフォーマンスの最適化</a>
<a target="blank" href="https://unity3d.com/jp/learn/tutorials/projects/creating-believable-visuals/lighting-and-setup">ライティングと設定</a>
<a target="blank" href="https://www.slideshare.net/UnityTechnologiesJapan/unity-3-vfx-graphunity">【Unity道場 3月 ~ライティングとVFX Graph~】Unityのライティング機能のおさらい</a>