【Unity】低予算・低容量で表情差分・動作差分の立ち絵を実現する方法

![eyecatch_2107LowCapacityAssetForUnity-or8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/e4abaa9b-7155-bb01-6cad-af474cfb04eb.png)

※ 本稿は <a href="https://tech.drecom.co.jp/?_src=qiita">Tech Inside Drecom</a> に掲載された記事、「[【Unity】低予算・低容量で表情差分・動作差分の立ち絵を実現する方法
](https://tech.drecom.co.jp/making-unity-portrait-variation/?_src=qiita)」の Qiita 出張版です。

---

# はじめに

こんにちは、Unityエンジニアをやっている竹内です。
今回は、「立ち絵の差分絵でアセットの容量が増える」という問題に対して、
「差分絵を1枚の画像に変換する事によって容量を抑える」という方法について
検討・実装したことについてまとめました。

立ち絵を実装する場合下記のような方法がよく使われます

* Live2D
* Spine
* 表情などの差分部位だけ別部品にして実行時に重ねて表示
* 差分の画像をすべて用意する

![figure1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/902a9473-b455-b37f-b41a-4719a2cd80f7.png)

![figure2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/488cd9f5-71b7-59ba-a355-2c177408f458.png)


# 各手法のメリット・デメリット

## Live2D、Spine

### メリット

* リッチな表現が可能　（モーションなどで見栄えがとても良くなる）
* アセットの容量が小さい

### デメリット

* パーツ分け、モーション付けなど行わないといけない為制作コストが高い

## 表情などの差分部位だけ別部品にして実行時に重ねて表示

### メリット

* 表情などの差分絵を用意するだけな為制作コストが低い
 * アセットの容量が小さい

### デメリット

* 差異部品の位置調整がおかしいとズレる
* 動作差分には不向き

## 差分の画像をすべて入れる 

### メリット

* 差分絵を用意するだけな為制作コストが低い

### デメリット

* アセットの容量が非常に大きくなる

## 今回紹介する方法

### メリット

* 差分絵を用意し変換処理を行うだけな為制作コストが低い
* ある程度の動作差分は表現できる
* アセットの容量が小さい

### デメリット

* 素材がちゃんと差分画像になっていないと成果物の容量が大きくなる

立ち絵差分の画像を今回の手法でアセット作成すると元データの約20％ほどの容量で差分絵表現ができるようになります

#### 成果物

![figure3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/1b4c57e4-161f-29d6-bc1d-5c8764afe1cd.png)

左が上記の画像から生成した画像、右が元の1枚絵の画像

![figure4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/6df88522-5b51-e959-c6a3-2b1639341b40.png)

# 実装の話

実装の大まかな内容は下記になります

1. テクスチャを32×32のブロックの集合とみなして1ブロック内のピクセル情報からハッシュ値を生成
2. 差分絵全てのブロックハッシュを生成し同じハッシュ値のブロックはスキップ
3. テクスチャにブロックのピクセルを書き込み
4. 全ての元画像のブロックの位置、ハッシュ値と3で生成したテクスチャのブロックの位置、ハッシュ値を記録したScriptableObjectを生成
5. uGUIのGraphicクラスを継承したクラスのOnPopulateMesh内で4の情報を元にUV値をポリゴンに指定して描画

# ピクセル補完問題
何もせず上記の実装を行うとピクセル補完をバイリニアなどにした時に問題が発生します

ブロックとブロックの境界（パディングを入れている場合透明なピクセル）が隣のピクセルと補完される事で下記の画像のような境界線がくっきり出てしまう問題が発生します

![figure5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/8a2ba312-f577-9316-03cd-3993e0b3793c.png)

この問題を軽減する為に行ったのが<font color="red">外周に同じ色のピクセルを置けば隣のピクセルを巻き込んでも違和感のない色になる</font>という解決方法です

#### 外周に同じ色のピクセルを置いた状態

![figure6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/bcc4675b-738c-28de-20a2-e335fbb6aa38.png)

#### 同じ色を置く位置に色を付けた状態

![figure7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/761d1213-f3e9-ae16-3dd0-ca7fa36ce9b3.png)

#### 拡大（最も外側のピクセルが内側のピクセルと同じ色になっています）

![figure8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/5f8eef3f-800b-8fc3-6062-b7d077e375f0.png)

またImageコンポーネントを継承して実装する事でマスクを掛けたりHierarchyの順番を入れ替えるだけで前後関係を制御できるようになります

予算がないけどアセット容量を抑えつつ差分表現をしたい！という時に非常に有用な手法なので是非参考にしてください

この機能の実装のサンプルとソースコードは下記URLから参照する事ができます

* https://github.com/oTAMAKOo/UniModules/tree/master/Scripts/Modules/PatternTexture
* https://github.com/oTAMAKOo/Example-PatternImage

# 使用方法

![figure9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/cae1126c-24a5-2e68-1af4-d799939e6c94.png)

* メニューのOpen PatternTexturePackerから下記ダイアログを開きます
* パックしたいテクスチャを選択した状態でCreateを押下します
* 出力先を指定するとパックされたテクスチャが出力されます

![figure10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/bf6ccbe4-3fec-6f7b-8cdd-45e071794f77.png)

BlockSizeは1ブロックのサイズになります
ブロックサイズが小さいと出力データが大きくなる事があります
AlphaMapはピクセルがあるブロックに当たり判定を持たせることができる機能です
出力データが少し大きくなりますがキャラの形に当たり判定を設定したい時などに活用できます

# まとめ

テクスチャ容量を抑えつつ差分表現を行う方法を 検討・実装したことについてまとめました 。 結果として画像容量を80%ほど軽減して差分表現を行うことができるようになりました。 最後まで読んでくださりありがとうございます。

---

Tech Inside Drecom の最新の情報は Facebook や Twitter からお届けしています、フォローよろしくおねがいします！

* Twitter: <a href="https://twitter.com/DRECOM_TECH" target="_blank">@DRECOM_TECH</a>
* Facebook: <a href="https://www.facebook.com/tech.inside.drecom" target="_blank">tech.inside.drecom</a>

---

※ その他の Tech Inside Drecom の記事は、<a href="https://tech.drecom.co.jp/?_src=qiita">コチラ</a>からお探しいただけます！!