今回は焼いた影とリアルタイムな影を混ぜる方法についてです。
焼いた影とリアルタイムな影
UnityではLightコンポーネントのShadowを設定するだけで、影を追加する事が出来ます。この際に表示される影はリアルタイムに計算されている物で、規模や物によっては非常に高いGPUの負荷になります。
このため良くある手法としては「事前計算した結果をテクスチャに焼きこんでしまう」という手法を取ります。これは所謂 Baked と Baked GI の組み合わせで、事前計算やテクスチャの読込が必要な代わりに、端末の発熱やCPU・GPUのパフォーマンス的かなり有利な設定です。
またリアルタイムな影は、Shadow Distanceの範囲内しか表示されません。例えば巨大なビル群がある場合、途中までしか表示されないといったケースもあります。
事前計算であれば(ライトマップを読み込む負荷およびベイクする負荷がありますが)遠方まで表示されます。
Baked Shadowはリアルタイムなオブジェクトに影を落とさない
この設定には一つ問題があります。Bakedで焼いた影はリアルタイムな影に影響を与え無い点です。
左の図はリアルタイム、右は背景以外はBakedでテクスチャに焼きこんでいます。比較すると、リアルタイムに配置した白い箱には影が落ちていない事が確認出来ます。
リアルタイムな物にBakedで焼いたマップの影をに落とす
リアルタイムなオブジェクトに影を落とす場合、RendererのShadowOnly設定を使用します。ShadowOnlyはその名の通り、影の描画にのみ使う設定です。
試しにCylinderをShadow Onlyに変更すると、Frame Debuggerを確認すぐ限り描画一覧(Render Loop Job)からCylinderが外されている事が確認出来ます。
これを活用します。
つまり、Baked にて焼き付けるCylinderと同じ位置にShadow OnlyのCylinderを配置します。
Lightの設定はMixed(ライトマップを焼くがダイナミックな影も落とす)に設定し、Shadow Onlyの方はLightmap Staticは外しておくのがポイントです。
パフォーマンス・クォリティを稼ぐために
これだけでは単純にLightmapの品質にリアルタイムな影を設定したいだけになってしまします。これだけでも一応「遠方の建物の影が表示される」という利点はありますが、パフォーマンスを考えて幾つか最適化を考えます。
Shadow Distanceを下げる
一つ目はShadow Distanceを下げる、つまり影を表示する距離を限定してしまう事です。遠方にあるキャラクターは影を使用せず目から近いキャラクターのみを表示するというアイディアです。カメラの向きやコンテンツにも寄りますが、意外と綺麗に映ります。
またShadow Distanceを下げるもう一つ良い所は、影が綺麗に映る点です。影の品質はShadow Distanceに強く依存します。Cascade(距離に応じて品質を分ける)設定もありますが、基本的に影の計算に使用する範囲が狭ければ狭いほど沢山の解像度が使えるので、綺麗になります。
影を落とすオブジェクトだけShadowOnlyを複製する
例えばShadow Onlyを影の落ちるオブジェクトにのみ設定することで、Shadow Mapを作る際の負荷が削れます。
ちなみに全てダイナミックなライトマップで構成してる場合、地面のCastShadowを切る事でも結構パフォーマンスが稼げたりします。
Shadow Onlyのメッシュはソコソコローポリでも良い
限度はありますが、Shadowに使う方のモデルはソコソコローポリでも良いです。細かいパーツ等は、余程投影先が単純な形状でない限り分からないと思います。
その他
この手法は「一応混ぜれるよ」ってレベルで色々と問題はあるので、対策してるバージョンの実験ビルドが公開されています。
https://forum.unity3d.com/threads/mixed-mode-fixes-and-lighting-window-preview-2-mix-harder.430308/
ちなみに、Baked Onlyでやる場合(モバイルとか)、シェーダーを少し書き換えた方が良いかもしれません。設定によっては結構顕著に色の違いが出ます。