【Unity】影の表現を軽量化するアイディア
今回は影の表現を軽量化するTipsについてです。
影はキャラクターの立ち位置を明確にして存在感を出します。影により地面とキャラクターの距離感が判断出来たり、影により周囲の空間を把握しやすくする等です。
ただし影の表現は負荷としてはそれなりに高い物です。
ステージや背景は、影の計算を事前にテクスチャ等に焼き付けておく事で、描画にかかる負荷を下げる効果が期待できますが、キャラクターといった動くものに対して利用する事は出来ません。
なおForwardの考え方で、Deferredは知りません。要するにモバイル的です。
影の負荷
Unityの影の負荷を考える場合、以下の要素を考えます。
- 影の範囲に何個の影をキャストするRendererがあるのか
- 影を発生させるポイントライトの数
- マテリアルの数
- メッシュの頂点数
影の範囲は、単純に影の描画対象の増減です。
これはShadow Distanceで設定します。
マテリアルとライトの数は、影の描画の回数を減らします。
影はマテリアルの数×メッシュの数×ライト(影)の数で描画回数が増えます。その為、この3つが増えていくと描画回数がどんどん増えます。
また描画する際、メッシュが多いとそれはそれで負荷になります。
一ユニティちゃん十三回
例えばSDユニティちゃんの場合、6個のSkinnedMeshRendererで構成されており、かつそれぞれのレンダラーが複数のMaterialを保持しています。
要するに、1体のSDユニティちゃんの影を表現するために、13回の描画が必要になります。
かつスポットライトやディレクショナルライトのようなライトを複数配置すると、そこに追加でライトの数の描画回数が加算されます。
つまりスポットライト3つあった場合、1体辺り39回、3体になると117回の描画が発生することになります。
描画回数はFrameDebuggerで確認出来ます。
…まぁSDユニティちゃん自体、本体に50近い描画が必要な主役級キャラなので、あんまり大量に描画すると言った事は無い訳ですが…
SkinnedMeshRendererはバッチが出来ない
もう一つの問題は、Skinned Meshesはバッチが出来ないという点です。
例えば下のようにバッチングが効くオブジェクトに関しては、実は「影を描画するパラメータさえ同じ」ならば異なるマテリアルでもバッチングが効くようになっています。
しかしSkinned Meshesはバッチングを行うことが出来ない制約上、マテリアル×メッシュ毎に描画が発生します。
影にSkinnedMeshRendererを使わないアイディア
そこで面白いTipsがあります。
If you deactivate shadow on your meshes and add some simpler mesh with "shadow only" you can save A LOT of tris and render time, especially in a scene with a large amount of dynamic objects where no one will notice cubic shadows #unitytips #gamedev #unity3d #madewithunity pic.twitter.com/1DLkmrzZ2m
— Stas Shostak (@StasShostak) 2018年2月13日
このTipsは、影の描画をSkinnedMeshRendererで行わず、もっと単純なモデルで代用する…というアイディアです。
やり方は簡単で、
- SkinnedMeshRendererのCast ShadowsとRecieve ShadowsをOFFにする
- カプセルとかを表現するMeshRendererをキャラクターの直下に配置
- カプセルのMeshRendererをRecieve Shadow をOFF、Cast ShadowsはShadow Onlyに
- カプセルのレンダラーはInstancingを有効にしておく
104回の描画が1回に収まった
上の操作をキャラクターに適応してみた所、ユニティちゃん8体で影の描画に104回の描画が必要でしたが、これが1回に収まりました。
異なるキャラクターが増えた場合も同様です。
影の描画はカプセルなので、カプセルが1回の描画で描画されている限り、描画は増えません。
詳細な影表現は無い
この表現の最大の問題は、影が雑になるという点です。
何せ「キャラクターの形でくり抜いて」影を表現していたのを「適当にカプセル状にくり抜いて」表現する形に変更したのです。形は大きく異なります。
一応、ボーンの計上に沿ってカプセル(やCube)を配置しておくことで、それっぽい形状を出す事も出来ます。
もう一つの問題は、Recieve Shadowを切る事でキャラクター自身に落ちる影(セルフシャドウ)が使えない点です。
これはモバイルのような小さな画面でプレイするゲームや、大量にキャラクターが出る系のゲームではバレないと思いますが、一人のキャラクターを注視出来る場合は注意が必要かもしれません。
Projectorの丸影と比べるとどうなん?
影の軽量化と言われてよく出てくるのが、プロジェクターによる丸影投影です。
プロジェクターの丸影投影は、挙動を分解すると「キャラクターの下に丸影が出るようにパラメータを調整したマテリアルを、メッシュに追加描画させる」機能です。
つまり、Shadow Blob ProjectorはProjectorで影を描画する場合、
- Shadow Blob Projectorの数だけ
- Shadow Blob ProjectorのポリゴンとShadow Blob Projectorが影響する面積を
描画する事になります。
問題は二つで、
- 地面を再描画する事になるので、メッシュ結合してるとハイポリを再描画といった事になりかねない
- 地面を再描画する事になるので、地面が画面の広範囲を締めてるとフィルレートがしんどい
ただし、影の描画に何度も描画しなくても良い利点はありそうです。
どちらのほうが良いかは、まぁゲームに依るかもしれません。