VRoidのcluster用VRM出力、結局どうすれば良いの？

現在、VRoid Studioからはcluster対応のVRMを出力する機能が備わっていますが、一方では「画質が汚い」とか「clusterの制限が厳しすぎる」と言う評価もあるようです。
Macやスマホでもアクセス可能な国産バーチャルSNSですので、なんとか楽な方法で課題を解決したいと思います。

# clusterへの出力は標準で対応している

現行のバージョンのVRoid Studioは標準でclusterへの出力に対応しています。
「撮影・エクスポート」タブのエクスポートから選択します。

厳密には制限はこれだけではありませんが、clusterにアップロードするには以下の制限をクリアする必要があります。
* ポリゴン数: 32000以下
* マテリアル数: 8以下
* ボーン数: 128以下

![スクリーンショット 2021-01-08 7.42.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/931697/3c9df104-2f33-14a6-533d-0791aa6ad53b.png)


# マテリアル統合機能は2048pxで出力よりも4096pxで出力してリサイズしよう

VRoid Studioは、アトラス化の機能が2048pxで出力しようとすると、ちょっとばかしおバカな挙動をするので、できる限り4096pxで出力してからリサイズすることをお勧めします。
(縮小のスケールが50%ですらないってどう言うこと？)


![スクリーンショット 2021-01-08 7.46.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/931697/14e48cb1-5245-5b11-80db-a95efd84bc39.png)

なぜか髪のマテリアルが複数コピーされるおかしな挙動についてはどちらでも起きていますが、原因わかりません。

4096pxで出力するとそのままでclusterにアップロードできないのですが、この辺のソフト使えば2048pxにリサイズできるので、極力4096pxで出力してリサイズすることをお勧めします。

- VRMテクスチャ差し替え＆最適化ツール #cluster #VRM <br>
https://booth.pm/ja/items/2601784

とはいえ、clusterで2048pxの解像度をフルに使えるのは、イベント主催者限定で、多少ピクセルが潰れるにしろ細部まで拡大しなければ割とどうにでもなるレベルなので、VRoidの出力をそのまま使っても極論どうでも良い気がします。
問題は、さらなる劣化を招く一般向けの512px強制縮小です。


# VReducerはclusterの一般ユーザーの救世主となるか？

一般ユーザー、モバイル表示、あるいはワールドで使えるVRMの最大解像度が事実上512pxに制限されているので、そこをどうにかしないといけません。
VRoidのアトラスの割り当てですと、512pxにリサイズされた時、肌とかワンピースの解像度は256x256pxになります。これはあまりに小さいでしょう。
でも512x512pxをまるまる1衣装に使えれば割とどうにかなると思いませんか？

そう言うわけで、ワンピースなどの解像度を最優先でリサイズする方向でいきましょう。
VReducerはpythonで書かれカスタマイズ可能なソフトですので、衣装の解像度を極力稼ぐ方向でチューニングするなど柔軟性が高いと思います。

VReducerの導入方法についてはとみねさんあたりも纏めていますからこちらの記事を参照してください

* https://qiita.com/htomine/items/4ad53c0d4c526cd433b7


## MacでのVReducerのインストール
Windowsユーザーの方が多いのでMacについてフォローしておくと、文中のコマンドのpipはpip3に、pythonはpython3に読み替えてください。必要に応じてHomebrewを導入してください。
M1のマシンではRosetta 2だとうまくいくようです。ターミナルを開いて

```
% arch -x86_64 zsh
```

と打てばIntelマシンだと思い込んで動いてくれます。

## VReducerを利用するときのエクスポート設定
今度はマテリアルを統合しない設定でVRoidからエクスポートすることになりますが、今度はマテリアルの統合をやめて、ポリゴン数とボーン数だけ制限内に収まるように調整してVRMをエクスポートします。

* ポリゴン数: 32000以下
* ボーン数: 128以下

## VReducerの制約

ノーマルマップとかリムライト（スフィア）とかのマテリアル情報を吹っ飛ばしてしまいます。しかし、ここでは、それは大した問題ではないことにします。

- そもそも低解像度でノーマルマップとか意味あるの？
- 「VRoidらしくないテクスチャ」みたいなの流行ってるし、リムライトも大抵の人嫌いだよね？

そんな感じで消し飛ばしてしまっても別に痛くない人もいるわけだし、そこに納得いかない人は、BlenderやUnityと十分仲良くなってください。


## VReducerの改造

早速、VReducerを改造していきましょう。
アトラス化によって衣装や肌テクスチャが他のテクスチャと結合されてしまうわけですから、アトラス化の処理を外せば良いだけです。
該当の処理を探してみると、vrm/reducer.pyの620行目あたりで何やらそれらしいことをしています。
察しの通り、ここがテクスチャをアトラス化する実処理でした。

```python
   # マテリアルを結合
    print('combine materials...')

# (中略)
        # 服の結合
        if cloth_place := get_cloth_place(gltf):
            gltf = combine_material(gltf, cloth_place['place'], cloth_place['main'], texture_size)

        # 体、顔、口
        gltf = combine_material(gltf, {
            '_Face_': {'pos': (0, 0), 'size': (512, 512)},
            '_FaceMouth_': {'pos': (512, 0), 'size': (512, 512)},
            '_Body_': {'pos': (0, 512), 'size': (2048, 1536)}
        }, '_Face_', texture_size)
        # レンダータイプを変更
        face_mat = find_vrm_material(gltf, '_Face_')
        face_mat['keywordMap']['_ALPHATEST_ON'] = True
        face_mat['tagMap']["RenderType"] = 'TransparentCutout'

        # アイライン、まつ毛
        gltf = combine_material(gltf, {
            find_eye_extra_name(gltf): {'pos': (0, 0), 'size': (1024, 512)},
            '_FaceEyeline_': {'pos': (0, 512), 'size': (1024, 512)},
            '_FaceEyelash_': {'pos': (0, 1024), 'size': (1024, 512)}
        }, '_FaceEyeline_', texture_size)

        # 瞳孔、ハイライト、白目
        gltf = combine_material(gltf, {
            '_EyeIris_': {'pos': (0, 0), 'size': (1024, 512)},
            '_EyeHighlight_': {'pos': (0, 512), 'size': (1024, 512)},
            '_EyeWhite_': {'pos': (0, 1024), 'size': (1024, 512)}
        }, '_EyeHighlight_', texture_size)

        # 髪の毛、頭の下毛
        hair_back_material = find_vrm_material(gltf, '_HairBack_')
        if hair_back_material:
            hair_resize = {'_HairBack_': {'pos': (512, 0), 'size': (1024, 1024)}}
            hair_material = find_near_vrm_material(gltf, '_Hair_', hair_back_material)
            if hair_material:
                hair_resize[hair_material['name']] = {'pos': (0, 0), 'size': (512, 1024)}
                gltf = combine_material(gltf, hair_resize, hair_material['name'], texture_size)

```


## 解像度＞マテリアルの質感という絶対の真理

顔パーツはある程度縮小されても余裕あるのでアトラス化を進めてそのぶん体／衣装の解像度を稼げば良いわけです。
そう言うわけで、顔パーツは統合を進める一方で体と衣装(上)をアトラス化しないように書き換えてしまいましょう。
それがこのブランチとなります。あと、VRoid 0.12.1への対応も入れておきました。
https://github.com/yakumo-proj/VReducer/tree/benefit-512px

さて、使用前と使用後です。顔は大差ないにしろ首から下がまるで別物ですね。
リムライトが効いてないけど、そんなものより解像度って圧倒的に大事だと思うでしょう？

![aaaaaa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/931697/4937e943-9cbd-08b4-f21a-9923c3fff77a.png)

まあ、実際のところ、VReducer(改)を使っただけじゃなくてベースヘアをHairSampleのベースヘアに変更したり、衣装のブレンドシェイプに合わせて法線を修正したり（エクスポート時にポリゴン数を微妙に削減するだけでできる）とかやってるわけですが。

## 見栄えをもっと良くするには？
解像度512pxでやれることは限られていますが、clusterのデータの制限の余力で何かできることはあるでしょうか？
先のVReducerの出力をみてみましょう。

```
(中略)
vrm materials: 7
materials: 7
textures: 10
images: 10
meshes: 3
primitives: 18
	 Face(Clone).baked : 9
	 Body.baked : 6
	 Hair001.baked : 3
```

マテリアル数は7です。マテリアルはあと1つですから余力があるとはいえませんが、1枚着重ねする程度は可能かもしれません（Unityの羅生門ツールとかで調べてみましょう）。
テクスチャは16枚までいけるので、ノーマルマップを復活させて衣装の立体感や質感を出す程度はできるかもしれません。512pxで十分見栄えするかどうかは疑問ですが。

色々試してみてください。
あとBlenderやらUnityやらでもっと楽に超美麗なVRMに変換できた人は教えてください。

# 512px基準でアバターアップロードしたらイベント用には解像度低すぎるけどどうすればいいの？

イベント用(2048px)とワールド用(512px)で作り分けて両方をアップロードしてください。そのためのアバターチェンジの仕組みです。