本記事は,サムザップ Advent Calendar 2019 #2 の12/24の記事です
#はじめに
みなさま、はじめまして
サムザップの中山です。
今年は、Unite Tokyo 2019にてAddressable Assets Systemについて
お話させていただく機会がありました。
此度のアドベントカレンダーでもその話の続きを・・・と思いましたが
今回は、本業であるインゲーム開発に関わる話をしようと思います。
#2Dゲームの表示順について
SortingLayerとSortingOrderを組み合わせて、階層構造で表示順を決めていくのが一般的です。
ある意味web制作的でシンプルなので、大抵の場合問題なく開発を進められると思います。
しかし、表示されるオブジェクトの順番が整数で決まるので、中途半端なかぶりを許してくれません。
2Dで取り扱われる想定のオブジェクトには、"RenderType = Transparent"、"ZWrite = off"が記述されたシェーダーが刺さっています
これはSpineの基本的なシェーダーでもそうですし、Unityのビルトインシェーダーでも同じです。
半透明かつZwriteを無視することで、いわゆる2D表現を行っています。
#パーティクルとの組み合わせ
とはいえ、ゲーム上で扱うには表示順が曖昧であったほうがいいときもあります。
エフェクトに使うパーティクルと組み合わせるときが代表的な例です。
Spineのオブジェクトとパーティクルを重ねたらどうなるでしょうか?
Spineのサンプルデータで見てみます。
SortingOrderとSortingLayerが同じだった場合
最終的な表示順は、Z軸でどちらが前かで決まります。
パーティクルの場合エミッターが基準となります。
つまりエミッターがSpineより少しでもカメラに近ければ
そこから発生されるすべてのパーティクルがSpineオブジェクトよりも表示順が強くなります。
生み出されたパーティクルがそれぞれ個別の表示順を獲得するには、ZWriteをOnにするのが手っ取り早いです。
しかし、その際に意図しない見た目になることが多いと思います。
Spineなどの2Dオブジェクトはたいていポリゴンの形と画像の形は一致していません。
ポリゴンの余白の部分があるのですが、通常は透明になっているので目には見えません。
ZWriteをOnにすると、パーティクルよりも先に余白の部分がレンダリングされてしまう事があるのです。
↑足の部分で後ろに回り込んだパーティクルがレンダリングされていない
透明と不透明がはっきりしているデザインの場合、これを回避するのは比較的容易です。
シェーダーにカットオフ用のレンジスライダーを作り、その値に応じてフラグメントシェーダーでクリップを行えば
不要な部分がレンダリングされないので、意図した見た目に近くなります。
参考までにこんな感じで追加してみました。
_Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1
//中略
clip(texcol.a - _Cutoff);
その他
ZWriteを追加したことによって、Z軸から表示順を決めることができるようになりました。
しかし、同時にSortingLayerとSortingOrderも生きている状態です。
Z軸での判定が効くのは、ZWriteをOnにしたオブジェクトに対してOffの状態のオブジェクトのSortingLayerが同等か高いときです。
そうでない場合はSortingLayerとSortingOrderに準じた表示順になります。
まとめ
お手軽ですが、なかなか反動のあるやり方でもあるので
使えない場面も、まぁあるかなと思いますが
一つの手段として覚えておくといいかもしれません。
明日は@shirahama_manabuさんの記事です
それでは、良いお年を〜