今回はUnity 5.6で追加されたLightingの新しい機能、特にShadowmaskについてです。
Shadow Maskは動的な影と静的な影を混ぜる手法
まずShadowMaskとは何ぞやという話ですが、要するに動的な影と静的な影を混ぜる新しい手法の一つです。
今までMixed系の手法は、ライトマップに焼いた部分は(既に焼いた)ライトの影響を受けず、ダイナミックなオブジェクトのみ影を描画する…という手法でした。
その場合、既に焼いたライトマップに追加でライトが加算描画されるといった事が発生していました。例えば下の場合、赤が動的、青が静的な影です。赤の落とす影が一部濃くなって描画されています。
5.6以前でも回避方法は無い訳ではありませんでしたが、5.6のShadow Maskでより綺麗かつシンプルに回避が可能になりました。
下の図ではShadow Maskを使用しています。
「影」の計算を事前に行う
ShadowMaskのやっている事は単純で、影を事前に計算しておく事です。
下ではほぼ全てのモデルがリアルタイムな影を持つ場合です。FrameDebuggerで確認すると、Shadows.RenderJobDirで影の計算が行われている事が確認出来ます。
ソレに対してShadowMaskで影を生成してみます。今度は赤はDynamic、青はStaticである場合です。
シーンは同じですが、Shadow.RenderJobDirで生成している影のテクスチャには、ダイナミックな赤い球しか表示されなくなりました。
ソレ以外の影は事前にShadowMaskとして計上されています。
マスクなので輝度や色を変える事が出来る
Shadow Maskを色々試して気づいた面白い事の一つは、今までのBaked Shadowと異なり輝度や色を変更出来る点です。
ShadowMaskは実行時に色や輝度が変えられる。ただしRealtimeGIが無効の場合はGIはLightmap事前に焼き込まれる為、大きく輝度を変えない方が良い #unitytips pic.twitter.com/9Xtai18BbC
— 椿 (@tsubaki_t1) 2017年4月18日
このミソはShadowMaskはあくまでもマスクであるという点です。
今までは影はベイクするとテクスチャに全て書き込んでいました。そのためテクスチャ自体の色を変えない限り影の色や輝度を変更する事は出来ませんでした。
ShadowMaskは単純に「マスク」で、影計算は事前に行いますが光の計算はリアルタイムに行うので、光の色や輝度を変更しても反映する事が出来る訳です。
ただし、下にも書きましたが間接光の計算は確定しているので、あまり強力に色を変えたりしない方が良さそうです。少し点滅するくらい。
間接光は事前にテクスチャに焼かれる
影以外の光の計算がリアルタイムで行われるとなったとき気になるのは間接光の扱いですが、事前計算してテクスチャに焼きこまれます。
上の内容で「RealtimeGIを設定しとけばGIが更新できる」ようにTwetterで書いてますが、これは自分の勘違いです。
テクスチャにベイクされるので更新出来ません。
光沢が綺麗に出る
Shadow Maskは影の設定だけで光はリアルタイムです。なので光沢もリアルタイムと同じように出ます。
Unity 5.5以前はライトマップにベイクしてしまうと光沢が死ぬ問題がありましたが、ShadowMaskを使えば光沢が表現されます。
下は青がStatic(+Shadow Mask)、赤がリアルタイムです。
Cookieが使える
ShadowMaskは光計算はリアルタイムなので、クッキーが使えます。
クッキーで絞り込んでいる場合でも、ShadowMaskは最大範囲で作られるので、少し動かしたり出来るのは若干面白いです。
近距離はダイナミックに、遠距離はShadowMaskを使う
個人的に最も気に入っている機能はDistance Shadowmaskの機能です。
この機能では「遠距離の影はShadowMaskを使うが近距離の影はダイナミックに描画する」という機能です。
何が良いかと言えば単純に、影の解像度を減らせます。
遠距離に低解像度のShadowMaskを使って、色々と節約
例えば下のシーンでは、17mのリアルタイムシャドウでソレ以外はShadowMaskを使用しています。一見それなりに見えますし、実際近くの影は綺麗に描画出来ています。
ShadowMapの解像度を節約
実はここで使用しているShadowMaskは、実はShadowMaskのResolutionは「5」という恐ろしく低い値を設定しています
この解像度でShadowMaskを表示するとボケボケの影が表示される事になりますが、近距離はダイナミックに影を描画する事で、近距離はパッキリと遠距離はボケボケの影が使用できます。
これが生むメリットの一つは、Lightmapのサイズです。徹底して低解像度に出来るので、サイズを大きく下げる事が出来ます。
例えば上のシーンに使用しているマップは50*20m級のマップですが、ここで使用しているテクスチャのサイズはたったの341kbに収まります。
これをDistance Shadowを使用せず綺麗な影のライトマップを表現しようとResolution 40(初期値)でやろうと思ったら、11MB近くになり、沢山のメモリと高いロードのコストを払う事になります。
またベイクのための解像度が減る事で、ライトマップが少し早く焼けます。
なお、Lightmapの解像度を下げるとShadowMaskの解像度だけでなく、間接光の解像度やEmissiveなオブジェクトの解像度、Bakedでテクスチャに焼き込んだ影の品質が下がります。
下の図はResolution2で影をベイクした場合です。staticが近距離では汚く見えます。
リアルタイムな影の負荷を節約 or 高品質化
何より良いのは、手前側のリアルタイムな影の品質も向上する事です。
影に使用するテクスチャは、影の品質で設定したサイズをShadow Distanceで分割していきます。その為、影の描画範囲が狭ければ狭い程、高解像度な影が描画出来ます。
もし右のようなフワっとした影が好みなら、ShadowのResolutionを落とせば良いです。それで(Soft Shadowなら)フワっとなりますし、描画負荷も落ちます。
影がShadowMaskになるタイミングは、Cascadeで見ると良いです。
2017と5.6でDistance Shadowの設定位置が異なる
まだ確定かは分かりませんが、Unity 2017では設定位置が変化していました。
Shadow Maskの使い方
LightingのLighting ModeをShadowmaskに設定し、ShadowMaskを作りたいライトをMixedに設定するだけです。