テラシュールブログ

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

【Unity】複数パーツで構成されたSpriteを半透明にしても違和感をなくす方法

f:id:tsubaki_t1:20171124002131j:plain

今回は最近のスケルタルアニメーションでよく見られるような、複数パーツで構成されたSpriteを、違和感なく半透明にするアプローチについてです。

若干限定的な所があるので、そのあたりは自分で何とかする必要があります。

2Dのスケルタルアニメーション

最近では2Dでも伝統的なピクセルアート*1によるアニメーションだけでなく、各関節を動かしてアニメーションとするスケルタルアニメーション的な手法が多くなりました。

流行で言えばFate GO的な。

f:id:tsubaki_t1:20171124002737g:plain

この手法では大胆な変形が難しい反面、かなり高解像度な画像で多彩なアニメーションが実現出来るのが利点です。
上の品質をパタパタアニメ手法で実現しようとすると、大きなサイズのテクスチャが必要になります。もしモバイルで実現しようと思ったら、アニメの枚数を下げるか、解像度を下げることになりそうです。

スケルタルアニメーションを作る

こういった手法は、単純にDCCツール(所謂モデリングツール)で実現したり、Spineといった特化ツールを使用したり、Anima2Dを始めとしたアセットを使用したり、最悪アニメーションツールで頑張る事になります。

marumittu-tech.hatenablog.com

tsubakit1.hateblo.jp

半透明が問題

この手法で問題になるのが、半透明の扱いです。

 

半透明とはガラスのように光を透過する状況です。アニメや映画では幽霊や英霊が透明になると背景が透けた人物のシルエットが出て来る訳ですが、実際にはクリオネのような、内蔵が丸見えの状態になります。
「体が透けて!」みたいな状態は、実際には骨と筋肉が丸見えになる訳です。おおグロいグロい

f:id:tsubaki_t1:20171124004154j:plain

Wikipediaより

この動作は3Dでも同様に発生します。例えば、何も考えずキャラクターモデルを透明にすると、目や唇の裏側まで表現されてしまい、非常にホラーな絵が出来上ます。

一応1メッシュで構成されていれば簡単に解決が可能なのですが、複数メッシュで構成されていると複雑な操作が必要になります。

http://cdn-ak.f.st-hatena.com/images/fotolife/t/tsubaki_t1/20150907/20150907215905.png

tsubakit1.hateblo.jp

これは2Dでも同様です。2Dスケルタルアニメーションは複数パーツに分かれているスプライトを表現するので、同じような制約が発生します。

透明にする瞬間が短いなら余り気にならないかもしれませんが、長時間透明の場合や、可愛いキャラクターが透明になる時には、気になる所が出るかもしれません。

f:id:tsubaki_t1:20171124005046j:plain

 

実際、SINoALICE(シノアリス)でもスケルタルアニメーション的な手法でホーム画面のキャラクターを動かしていますが、半透明時には接続部が丸見えになります。
どこまで割り切るのかは問題でしょう。全てはトレードオフです。

f:id:tsubaki_t1:20171124005944j:plain

 Spriteを透明にするアプローチ

さて、今回の本題であるSpriteを透明にするアプローチを思いついて、実際に試したら上手く行ったので紹介しておきます。

Sprite Maskで手前のスプライトのみを表示する

簡単に言えばSprite Maskを使用して手前のスプライトだけを表示すれば良い訳です。以前に3Dで行った操作と異なり、2Dは明確に描画順が設定されているので、Sprite Maskでも十分です。

 

例えば以前紹介したキャラクターの顔と体のスプライトを分割してテクスチャの解像度を稼ぐ手法で考えてみます。

f:id:tsubaki_t1:20171124011558j:plain

 

このスプライトを半透明にすると、体(奥のスプライト)と手前のスプライト(顔)の両方が表現されてしまうため、あまり良くない感じの表現になります。

f:id:tsubaki_t1:20171124011809j:plain

これを「手前のスプライトにマスクを掛け、奥のスプライトはマスクがかかった部分を描画しない」とすることで、二重に描画されるのを防ぐ訳です。

f:id:tsubaki_t1:20171124013725j:plain

実際の手順

そこで手前(表情)のSpriteにSpriteMaskを設定、奥のSpriteにはSpriteMaskがかかっている部分を表示しないとします。

 

まずは表情の方に設定します。

  1. 表情を表現しているオブジェクト(今回はFace)にSpriteMaskを設定
  2. SpriteMaskのSpriteはSpriteRendererと同じものを設定

f:id:tsubaki_t1:20171124012116j:plain

次の体の方を設定

  1. 体を表現しているオブジェクト(今回はBody)のSpriteRendererの、Order in layerをFaceより下にする。
  2. Mask InteractionをVisible Outside Maskに設定

f:id:tsubaki_t1:20171124012411j:plain

 

これでスプライトの透明度を切り替えても、二重に表示されることを防げます。

f:id:tsubaki_t1:20171124012636g:plain

幾つかの問題対処法(概要)

基本的にコレだけなのですが、この方法では下のような問題を起こせます。

  • 複数のキャラクターが重複した際、別キャラクターのマスクも影響する問題。
    キャラクターを重ねると、2枚目のFaceが1枚めのBodyより手前に表示される。
    SortingGroupを使って範囲を限定すれば解決

    f:id:tsubaki_t1:20171124015527j:plain

  • 複雑な階層構造を持つ場合の問題
    具体的にはマスクするスプライトが同時にマスクされるケースでの対処法(図では腹の部分が二つのスプライトに挟まれている状態)
    SpriteMaskのCustom RangeでMaskの影響範囲を自分以下のSpriteにすれば解決

    f:id:tsubaki_t1:20171124015510j:plain

  • スプライトのエッジが透明な時、うっすらと境目が見えてしまう場合の問題
    SpriteMaskのAlphaCutOffを調整すれば解決

    f:id:tsubaki_t1:20171124015340j:plain

この辺りも含めて書くと記事が長くて面倒くさいとか思われそうなので、ちゃんとした解説は別記事にします。

tsubakit1.hateblo.jp

関連

他のもSpriteMaskは色々と面白い

tsubakit1.hateblo.jpSortingGroupはパフォーマンスを上げる上でも便利

tsubakit1.hateblo.jp

今回はSpriteとMaskが前提ですが、独自レンダラー・独自シェーダーの場合(例えばSpine)の場合は、ステンシルを使用するシェーダーを書くとかする必要があるかもしれません。

tsubakit1.hateblo.jp

 

*1:8ビットゲーとかよく言われるけど、大抵16ビットゲーだよね。絵の品質的に