表情差分の抽出と切り替え
2019/02/17追記
Tightメッシュにも対応しました
ノベルパートでの立ち絵での表情の切り替え テラシュール御大でも何度かネタにされているあれです。
これについて、自分は「表情差分とそれ以外がちゃんと分かれたメッシュを作って顔の箇所のUVを切り替えればよいのでは」と長年うっすらと考えていました。 9sliceの真ん中を書き換えるようなイメージです。
で、このたび実装してみました。
どんな感じか
アセットの準備
何はともあれ表情切り替えのある画像を用意します。 以下はUnity-Chanの公式よりありがたくいただいてきました。
次にぎっはぶのコードをプロジェクトに突っ込みます。 コンパイルが通ったらProjectViewを右クリックして、「Create → ScenarioCharacterAssetGenerator」をぽちります。
これは表情差分の抽出、画像のパッキング、Meshの生成をするためのGenerator (ScriptableObject)が作られます。 インスペクタは下図のようになっています。
こやつに、画像と出力パスを設定します。 立ち絵のデフォルトになる画像をBaseTextureに、差分をDiffTexturesに、出力先をDestination Pathに入力します。 Block Sizeは圧縮テクスチャのブロックサイズです。DTX1/DTX5, ETC2, ASTC(4x4)あたりを使うなら初期値4のままでかまわないです。RGBA16やRGBA32などの圧縮なしや減色のみのフォーマットを使うならBlock Sizeは1としても良いです。 Diff Rect, Diff Rect Adjusted By Block Sizeは差分抽出中に勝手に入る数値です。デバッグ用に表示してます。
「表情差分画像生成」ボタンをポチると、マルチスプライトが生成されます。
表情差分側のほうはBlockSize分の余分なピクセルが周辺にあります。これは圧縮テクスチャ使用時、引き延ばしたときにBilinearフィルタで絵のつなぎ目が破綻しないように、という処置で今回のこだわりポイントです。単なる色の引き延ばしであるExtrudeではダメでした。
パックされた画像が出来上がったら「Mesh生成」をぽちります。パック画像と同じフォルダにメッシュができます。
実際に使用する
MeshRendererにScenarioCharacterMeshコンポーネントを貼り付け、表情のSpriteを全部ぶち込みます。
Materialは_MainTex
と_Color
を指定できるものならなんでもよく、つまりSprites-Defaultを使えます。
MeshFilterには生成したMeshを指定してください。
SpriteIndexに、使いたい表情のIndex値を指定すれば表情が切り替わるはずです。 なんか描画がおかしかったら一度プレイモードで再生してみてください。わりと起きます。ExecuteInEditMode難しいんじゃい…
5枚の板ポリが含まれたメッシュをただ描画するだけで、画像もパックされてますので当然ドローコールは1です。板ポリ1枚描画するのと大差ないといっていいでしょう。
良い手法かどうか
メッシュを準備する手間があるかわりに描画方法としてはとても単純で素直なものなので、全体と表情差分を別描画する方式と違って半透明の問題が起きません。
ただし結構大きな欠点として、TightメッシュではなくFullRectで描いているので透明領域のピクセルの塗りが無駄オブ無駄です。フィルが良くない。
よって、頂点数を増やしてフィルを落としたいなら結局Tightメッシュ+表情別描画+SpriteMaskのテラシュール方式りに落ち着きそうな気もします。有料でいいなら宴のダイシングが描画の素直さとフィルの削減で一番バランスが良いかなぁ。