読者です 読者をやめる 読者になる 読者になる

テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】リアルタイムな影とベイクした影を混ぜる、Shadow Mask 特集号

f:id:tsubaki_t1:20170418215930j:plain

今回はUnity 5.6で追加されたLightingの新しい機能、特にShadowmaskについてです。

Shadow Maskは動的な影と静的な影を混ぜる手法

まずShadowMaskとは何ぞやという話ですが、要するに動的な影と静的な影を混ぜる新しい手法の一つです。

f:id:tsubaki_t1:20170418221250j:plain

tsubakit1.hateblo.jp

今までMixed系の手法は、ライトマップに焼いた部分は(既に焼いた)ライトの影響を受けず、ダイナミックなオブジェクトのみ影を描画する…という手法でした。
その場合、既に焼いたライトマップに追加でライトが加算描画されるといった事が発生していました。例えば下の場合、赤が動的、青が静的な影です。赤の落とす影が一部濃くなって描画されています。

f:id:tsubaki_t1:20170418223021j:plain

5.6以前でも回避方法は無い訳ではありませんでしたが、5.6のShadow Maskでより綺麗かつシンプルに回避が可能になりました。

下の図ではShadow Maskを使用しています。

f:id:tsubaki_t1:20170418223635j:plain

「影」の計算を事前に行う

ShadowMaskのやっている事は単純で、影を事前に計算しておく事です。
下ではほぼ全てのモデルがリアルタイムな影を持つ場合です。FrameDebuggerで確認すると、Shadows.RenderJobDirで影の計算が行われている事が確認出来ます。

f:id:tsubaki_t1:20170418231014j:plain

ソレに対してShadowMaskで影を生成してみます。今度は赤はDynamic、青はStaticである場合です。
シーンは同じですが、Shadow.RenderJobDirで生成している影のテクスチャには、ダイナミックな赤い球しか表示されなくなりました。
ソレ以外の影は事前にShadowMaskとして計上されています。

f:id:tsubaki_t1:20170418231957j:plain

マスクなので輝度や色を変える事が出来る

Shadow Maskを色々試して気づいた面白い事の一つは、今までのBaked Shadowと異なり輝度や色を変更出来る点です。

f:id:tsubaki_t1:20170418225151j:plain

このミソはShadowMaskはあくまでもマスクであるという点です。

今までは影はベイクするとテクスチャに全て書き込んでいました。そのためテクスチャ自体の色を変えない限り影の色や輝度を変更する事は出来ませんでした。

 

ShadowMaskは単純に「マスク」で、影計算は事前に行いますが光の計算はリアルタイムに行うので、光の色や輝度を変更しても反映する事が出来る訳です。

f:id:tsubaki_t1:20170418225555j:plain

ただし、下にも書きましたが間接光の計算は確定しているので、あまり強力に色を変えたりしない方が良さそうです。少し点滅するくらい。

間接光は事前にテクスチャに焼かれる

影以外の光の計算がリアルタイムで行われるとなったとき気になるのは間接光の扱いですが、事前計算してテクスチャに焼きこまれます。

f:id:tsubaki_t1:20170418232740j:plain

上の内容で「RealtimeGIを設定しとけばGIが更新できる」ようにTwetterで書いてますが、これは自分の勘違いです。
テクスチャにベイクされるので更新出来ません。

光沢が綺麗に出る

Shadow Maskは影の設定だけで光はリアルタイムです。なので光沢もリアルタイムと同じように出ます。

Unity 5.5以前はライトマップにベイクしてしまうと光沢が死ぬ問題がありましたが、ShadowMaskを使えば光沢が表現されます。

下は青がStatic(+Shadow Mask)、赤がリアルタイムです。

f:id:tsubaki_t1:20170419005101j:plain

tsubakit1.hateblo.jp

 Cookieが使える

ShadowMaskは光計算はリアルタイムなので、クッキーが使えます。

f:id:tsubaki_t1:20170419010614j:plain

クッキーで絞り込んでいる場合でも、ShadowMaskは最大範囲で作られるので、少し動かしたり出来るのは若干面白いです。

f:id:tsubaki_t1:20170419011211g:plain

近距離はダイナミックに、遠距離はShadowMaskを使う

個人的に最も気に入っている機能はDistance Shadowmaskの機能です。

この機能では「遠距離の影はShadowMaskを使うが近距離の影はダイナミックに描画する」という機能です。

何が良いかと言えば単純に、影の解像度を減らせます。

f:id:tsubaki_t1:20170418234112j:plain

遠距離に低解像度のShadowMaskを使って、色々と節約

例えば下のシーンでは、17mのリアルタイムシャドウでソレ以外はShadowMaskを使用しています。一見それなりに見えますし、実際近くの影は綺麗に描画出来ています。

f:id:tsubaki_t1:20170418235557j:plain

ShadowMapの解像度を節約

実はここで使用しているShadowMaskは、実はShadowMaskのResolutionは「5」という恐ろしく低い値を設定しています

この解像度でShadowMaskを表示するとボケボケの影が表示される事になりますが、近距離はダイナミックに影を描画する事で、近距離はパッキリと遠距離はボケボケの影が使用できます。

f:id:tsubaki_t1:20170419000059j:plain

これが生むメリットの一つは、Lightmapのサイズです。徹底して低解像度に出来るので、サイズを大きく下げる事が出来ます。

例えば上のシーンに使用しているマップは50*20m級のマップですが、ここで使用しているテクスチャのサイズはたったの341kbに収まります。

これをDistance Shadowを使用せず綺麗な影のライトマップを表現しようとResolution 40(初期値)でやろうと思ったら、11MB近くになり、沢山のメモリと高いロードのコストを払う事になります。

f:id:tsubaki_t1:20170419001248j:plain

またベイクのための解像度が減る事で、ライトマップが少し早く焼けます。

 

なお、Lightmapの解像度を下げるとShadowMaskの解像度だけでなく、間接光の解像度やEmissiveなオブジェクトの解像度、Bakedでテクスチャに焼き込んだ影の品質が下がります。
下の図はResolution2で影をベイクした場合です。staticが近距離では汚く見えます。

f:id:tsubaki_t1:20170419020209j:plain

 リアルタイムな影の負荷を節約 or 高品質化

何より良いのは、手前側のリアルタイムな影の品質も向上する事です。
影に使用するテクスチャは、影の品質で設定したサイズをShadow Distanceで分割していきます。その為、影の描画範囲が狭ければ狭い程、高解像度な影が描画出来ます。

f:id:tsubaki_t1:20170419002354j:plain

もし右のようなフワっとした影が好みなら、ShadowのResolutionを落とせば良いです。それで(Soft Shadowなら)フワっとなりますし、描画負荷も落ちます。

影がShadowMaskになるタイミングは、Cascadeで見ると良いです。

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

2017と5.6でDistance Shadowの設定位置が異なる

まだ確定かは分かりませんが、Unity 2017では設定位置が変化していました。

tsubakit1.hateblo.jp

Shadow Maskの使い方

LightingのLighting ModeをShadowmaskに設定し、ShadowMaskを作りたいライトをMixedに設定するだけです。

f:id:tsubaki_t1:20170419014227j:plain

tsubakit1.hateblo.jp

関連

tsubakit1.hateblo.jp

【Unity】InspectorでCtrl+Clickを押してTextureの簡易ビュー表示

 な、なんだってーーーー

InspectorでCtrl+Clickで簡易プレビュー

MaterialのInspectorビューにて、Ctrl + Clickでプレビューが出来るみたいです。
知らんかった

f:id:tsubaki_t1:20170419020927g:plain

Frame DebuggerやLightmapでも使える

Materialの設定以外でも、Frame DebuggeやLightmapの確認でも使えます。

f:id:tsubaki_t1:20170419021230g:plain

f:id:tsubaki_t1:20170419021409j:plain

関連

No hack, no work • Unity進捗どうですか2

【Unity】シーンの変更を「無かったこと」にする

f:id:tsubaki_t1:20170414030546g:plain

ちょっとしたTipsです。

シーンの変更を「無かったこと」にする

シーンの内容を変更すると、シーン名の右にアスタリスク(*)が表示されます。この状態であれば、シーンの変更を破棄する事が出来ます。

f:id:tsubaki_t1:20170414030659j:plain

  1. Hierarchyのシーンを右クリック
  2. Discard Changesを選択

マルチシーンエディティング等で他のシーンから物を持ってきた時等によく使ってます。

 

勿論、Saveして変更を確定してしまったら戻すことは出来ません。これは「保存してなければ」使えます。

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

【Unity】スプライトの描画順を「下にある物を手前」にする

f:id:tsubaki_t1:20170414014046j:plain

今回はUnity 5.6から追加されたTransparency Sort Modeを使って「スプライトの描画順を下にある物を優先」にします。

Spriteの描画順

Spriteの描画順は、基本的に

  1. Sorting Layer
  2. Order In Layer
  3. カメラに近い順

で判断されています。

まずSorting Layerで描画順を判断し、同一のSorting Layer内であればOrder In Layerで判断、それで判断つかなければ通常のTransparentと同様にCameraからの距離で判定しています。

f:id:tsubaki_t1:20170414014433j:plain

それでも決着がつかなければ生成順っぽいです。

例えば下のParspectiveのカメラの場合、Zの距離は同じでも中心から離れれば離れるほど奥に描画されます。

f:id:tsubaki_t1:20170414015628j:plain

逆にOrthographicの場合、Zの位置…つまり手前にあるか奥にあるかで判定します。この位置が同一ならば、生成順っぽい気がします。

f:id:tsubaki_t1:20170414015852j:plain

今回はこの「Sorting LayerでもOrder In Layerでも描画順が決着つかなかった時の描画順」を、少し変更して「下にある物を手前に描画」してみます。

下にあるスプライトを手前に描画

Unity 5.6からTransparency sort modeという項目が追加され、Custom Axisなる項目が追加されました。

この値を変更すると、スプライトの描画ルールが変更出来ます。

f:id:tsubaki_t1:20170414014151j:plain

例えばTransparncy Sort ModeをCUsとmAxisに設定しTransparency Sort Axisを(X:0、Y:1、Z:0)とすると、Y軸的に下にあるオブジェクトが手前に描画されます。

f:id:tsubaki_t1:20170414020647g:plain

逆にYが-1だった場合、上にあるものが手前に描画されますし、Xが1なら左にある物が手前に描画されます。
もちろんZが1ならZ軸的に手前にある物が前面に描画されます。

f:id:tsubaki_t1:20170414020822j:plain

同一の大きさのスプライトであれば、これで問題ありません。

縦に長い物体の問題

厄介なのが縦に長い物体、例えば柱や家等の建築物です。

スプライトの「上下」の判定は、どうやらスプライトの中心点で判断しているらしく、Pivotを変更した場合でも下のアニメーションのように「中央」で判定されます。

f:id:tsubaki_t1:20170414021340g:plain

解決:Z軸で描画順を調整する

これを解消する手っ取り早い方法が、奥行きの判定にZを追加し柱のZ値を調整する事です。奥に行って欲しい位置にスプライトを配置し柱のZ値を調整、手前になった所が概ね丁度よい位置になります。

f:id:tsubaki_t1:20170414021929j:plain

f:id:tsubaki_t1:20170414022447g:plain

補足:もう一つ厄介なのがパーティクルです。

Simulation SpaceがLocalならばBounceは固定なので上と同じように調整してやれば良いのですが、Scaling ModeがWorldだと中心地の取得が若干面倒なことになります。

複数のスプライトを合わせて表現しているスプライトの問題

もう一つが複数のスプライトを組み合わせて一つの絵を表現しているケースです。

例えば下の車は車体とタイヤの二つのスプライトで表現されています。この時、単純に「下が手前」としてしまうと、タイヤと車体で奥に行く位置が異なります。

これはAnima2D的な物を表現する際に問題になります。

f:id:tsubaki_t1:20170414023308g:plain

解決:SortingGroupでスプライトを一つのスプライトとして扱う

解決方法は単純で、Sorting Groupを使用します。これでスプライトをまとめると、単一のスプライトのように扱われるようになります。

f:id:tsubaki_t1:20170414024058g:plain

また、グループに纏めたスプライトの描画順が何であれ、周囲にはSorting Groupで指定しているOrder In LayerやSorting Layerになります。

上のZ値も合わせて位置を調整すると、割と普通に使えるようになります。

f:id:tsubaki_t1:20170414023734j:plain

tsubakit1.hateblo.jp

要するに

つまり

  • Custom AxisでY軸・Z軸で描画順を制御する
  • 縦長の物はZ値を使って描画順が変わる位置を微調整
  • 複数のSpriteを組み合わせている物はSortingGroupで纏める

という事

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp