UE4でMToonを再現したい（1/2）


# MToonを再現したい
MToonはVRMファイルで使われている、標準シェーダの1種です。アニメ的表現に特化したものです。
詳細はこちら → https://dwango.github.io/vrm/univrm/shaders/mtoon/

Unity向けに作られているものを、今回はUnrealEngine4で再現していきます。
利用環境はUE4.20.3です。
内容にパラメータの解釈や実装の間違いありましたらすみません。ご指摘いただけると有り難いです。

# UE4におけるトゥーンレンダリング
com04さんのまとめページがとても参考になりました。勝手ながら感謝をお伝えします。
https://qiita.com/com04/items/a7895160df8d854fe924

記事のままですが、手法は大別して3種「マテリアル」「ポストプロセスフィルタ」「エンジン改造」があります。

# 先に結果
今回は「マテリアル」の手法で実装し、陰影には自前のシャドウマップを利用することにしました。
整理して [VRM4U](https://github.com/ruyo/VRM4U/wiki/VRM4U) のアセットに追加予定です。

描画コストは少々高いかも… とはいえVR機材を扱っているような環境であれば 余裕で動作すると思います。

![test6.gif](https://qiita-image-store.s3.amazonaws.com/0/36233/daf13596-1205-335b-16c2-0f411331eea2.gif)

モデルはこちらからお借りしました → http://3d.nicovideo.jp/works/td32797
要素は押さえられていると思いますが、機能不足はありそう…
以下、つらつらと。

# 再現にあたって考えていたこと

### 「主色/陰色」と「輪郭線の幅と色」を反映したい
これができれば8割方完成な気持ち。

- 主色/陰色について
    - 描画時に明確に陰・影領域を判別できている必要がある
    - ShadingShift（主色の面積を増減させる）に対応するため、中間値も欲しい
- 輪郭線の幅と色について
    - なんとなく背面法で良さそう
    - パラメータ参照が多いので、ポストプロセスだとどこかで手詰まりしそうな予感がする…

### 陰と影 を判別したい
※ここ言う「陰」「影」を図解しておきます。
1が陰で、2が影です。わかりにくくてすみません… 

| |
|----|
|![image.png](https://qiita-image-store.s3.amazonaws.com/0/36233/88e64dbf-a5e1-2651-2f60-83d5b09d9deb.png)|


- 陰と影
    - 検索すると こんな素敵な技が紹介されている。これで解決かと思いきや…
        - https://forums.unrealengine.com/development-discussion/rendering/125368-using-shadow-in-material
        - コメントにもあるように、forwardレンダリングでしか機能せず、4.20では正しく動作しない
        - （どなたか対応方法知ってたら教えてください… 4.19で動作するのは確認しました）
    - 陰は自前で計算できる。影を解決するにはShadowmap（厳密にはLightAttenuationTexture）を参照する必要がある
        - プラグインで配布したいので できればエンジン改造は避けたい
        - そういえばUnityでShadowmapを自前実装してる方がいたのを思い出した http://www.shibuya24.info/entry/shadowmap
        - 自分も作ってみよう

### 他のMToonパラメータとの相性は…

以下に表でまとめました。Unityでパラメータを触りながらだと わかりやすいかも。
この赤枠で囲った部分のパラメータです。

|この画面はUnityです|
|---|
|![image.png](https://qiita-image-store.s3.amazonaws.com/0/36233/fff49132-f284-80c4-73d8-892ca18c3db2.png)|

実装の手法として以下の3つを比較検討しました。厳密にはそれぞれforward/deferredで動作が分かれます。

- material+自前shadowmap（今回使った手法）
    - 自前のshadowmapを作成し、マテリアルで参照しながらシェーディングを行う手法
- material(+postprocess)
    - マテリアルでシェーディングしたりGBufferへ書き込みを行い、ポストプロセスで合成したり輪郭線描画を行う手法
- postprocessのみ
    - マテリアルは基本的な物理シェーディングを行い、ポストプロセスで加工を行う手法

#### Color
主色・陰色。

| 手法             |LitColor,Alpha| ShadeColor|
|:-----------------|:------------------:|:---:|
| material+自前shadowmap|○|○|
| material(+postprocess)     | ○     |  △<br>色指定の格納先に工夫が必要。Shadowmap参照可であれば○|
| postprocessのみ|○<br>BaseColorに格納|△<br>色指定の格納先に工夫が必要|

#### Lit & ShadeMixing
主色領域の調整・陰のボケ足・影の影響度

| 手法             |ShadingShift| ShadingToony |ShadowReceiveMultiplier|Lit&ShadeMixingMultiplier|
|:-----------------|:------------------:|:---:|:---:|:---:|
| material+自前shadowmap |      ○  |        ○       |○| ?<br>未検証 |
| material(+postprocess)     | ○     |  ○  |△<br>陰と影が判別できない。Shadowmap参照可であれば○| ? |
| postprocessのみ|△※<br>GBufferのNormalとライト向きで計算すれば○|△<br>左と同じ|×| ?|
※厳密にはライト向きとノーマルの内積を-1～+1の値で取得する必要がある。

#### LightColor
主光源の影響度・GIの影響度

どの手法でも、カスタムノードに記述すれば対応可能。詳しくは後半で。



#### Outline
輪郭線の出し方・線の太さ・ライト影響受けるか・線の色・ライト影響度

| 手法             |Mode| Width|ColorMode|Color|LightMix|
|:-----------|:-----:|:------:|:------:|:------:|:------:|
| material+自前shadowmap<br>背面法   | ○     |  ○  | ○| ○ |○|
| material(+postprocess<br>背面法   | ○     |  ○  | ○| ○ |○|
| postprocessのみ|  △<br>World方式はGbufferのNormalから算出  | △<br>幅をGBuffer格納 |○|△<br>色をGBuffer格納|△<br>左と同じ|

##　いざ実装

後半へ
https://qiita.com/ruyo/items/71a3f2f694d2853b3f1e