VRoid Studioで作成したVRMを一度Blenderに読み込み、再度VRM形式で出力すると、
VRoid Hub上でCutoutマテリアルの透過部分が背後のメッシュごと透過してしまう現象が発生した。
Unity上では正常に表示されるため、原因の特定に4日もかかりました…
備忘録として残します。
結論
-
原因
Blender出力時、MToonのCutoutマテリアルに_ALPHABLEND_ON: True
キーワードが付与されてしまう。
このキーワードは半透明合成用であり、Cutoutでは(おそらく)不要。
Blender VRMアドオン作者様から「Blender 4.2以降で発生していたバグで、最新版(v3.11.1)で修正した」とのコメントをいただきました。最新版では_ALPHABLEND_ONがfalseで出力されるようになっています。感謝。
-
対策
最新版アドオン(v3.11.1以降)を使用する ←推奨
出力されたVRMファイル内の、MToonシェーダーのCutoutマテリアルのkeywordMapから_ALPHABLEND_ON: True
を削除する。
またはUnity上でマテリアルを新規に作り直す(回避策)
再現条件
- 現象
VRoid Studioで作成したVRMを一度Blenderに読み込み、再度VRM形式で出力すると、
Unityでは正常に描画されるが、VRoid Hubでは透過部分が背後まで抜けて見える - 再現例
瞳の輪郭、胸元のリボン、袖口部分
環境
現象の再現には、VRoid StudioのAvatarSample_Mに協力してもらっています。
ソフトウェア/アドオン | バージョン |
---|---|
VRoid Studio | 2.1.5 |
Blender | 4.2.10 LTS |
vrm-addon-for-blender | 3.6.0 |
Unity | 2022.3.17f1 |
UniVRM | 0.129.3 |
調査経緯
-
Unity上では正常
Unityで表示した場合、VRoid Studio出力版とBlender経由版で見た目に差はなし。
Render Queueやマテリアルの各種設定も完全一致している。 -
VRoid Hub上で誤表示
VRoid Hubにアップロードすると、Blender経由版のみ透過処理がおかしくなる。
背後の肌や髪まで透過してしまう。
下図では、瞳の輪郭(赤線で囲った部分)、胸元のリボン、袖口部分で発生。
VRMファイル内部の比較
原因が全くわからないので、Pythonで正常版と異常版の中身を読み出し、マテリアル周りの記述を吐き出させて、違いを確認する。
VRMは、3Dモデルの標準形式であるglTFを拡張したファイル形式である。
この拡張部分の中にあるextensionsセクションでは、VRM独自の追加情報が定義されており、MToonのマテリアル設定を扱うmaterialPropertiesもここに含まれる。
ここではmaterialPropertiesに記録されるプロパティを詳しく見ていく。
PythonではglTFを取り扱うパッケージをインポートすることでVRMファイルの中身を簡単に見ることが可能。
glTFのoverviewを参考にVRMファイル内のマテリアル周りの記述を抽出する。
VRMの拡張機能は、extensions
のエントリポイント内に記載されており、
MToonのマテリアル情報はextensions["VRM"]["materialProperties"]
に格納されている。
関連しそうな違い(Cutoutマテリアル)
レンダリングタイプがCutoutマテリアルに関して、keywordMap項に関連しそうな違いがあった。
異常なモデル(Blender経由版)では_ALPHABLEND_ON: True
が追加されている。
...
'keywordMap': {
'_ALPHATEST_ON': True,
'_NORMALMAP': True,
'MTOON_OUTLINE_COLOR_FIXED': True,
'MTOON_OUTLINE_WIDTH_WORLD': True},
...
...
'keywordMap': {
'MTOON_DEBUG_LITSHADERATE': False,
'MTOON_DEBUG_NORMAL': False,
'MTOON_OUTLINE_COLOR_FIXED': True,
'MTOON_OUTLINE_WIDTH_WORLD': True,
'_ALPHABLEND_ON': True,
'_ALPHAPREMULTIPLY_ON': False,
'_ALPHATEST_ON': True,
'_NORMALMAP': True}
...
VRM 0.x仕様にはCutout時のキーワード一覧は明記されていないがUnity Standard Shaderの挙動から推測するに、_ALPHABLEND_ON
は半透明のブレンド処理を有効にするためのキーワードなので、Cutout「アルファ閾値で完全表示 or 完全非表示」では必要ないはず。
VRM 0.xの各レンダリングモードにおけるキーワードの違いに関する情報は見つけられなかったが、Unity の公式ドキュメントでは、「Standard Shader」における各種レンダリングモードと、それに対応した Shader キーワードが明示されている。Cutout モードでは「透過合成」ではなく「アルファ値による切り抜き」によって描画されるため、_ALPHABLEND_ON
は使用されず、_ALPHATEST_ON
が使われる。
Unity 上で動作するMToonも同じキーワード対応で描画処理が動作すると理解するのであれば、CutoutにおいてALPHABLEND_ON
は記載する必要はないはず。
修正してVRoid Hubで表示確認
ためしにcutoutが使われている衣装マテリアルのALPHABLEND_ON
を消してみる。
import pathlib
import pygltflib
# VRM読み込み
path = pathlib.Path('.\\blender_output\\AvatarSample_M_compression.vrm')
glb = pygltflib.GLTF2().load_binary(path)
# 例:衣装マテリアル(配列インデックス5)のkeywordMapを修正
glb.extensions['VRM']['materialProperties'][5]['keywordMap'].pop('_ALPHABLEND_ON', None)
# 保存
glb.save_binary('fixed_model.vrm')
この修正版をVRoid Hubにアップロードすると、衣装の透過の誤表示が解消された。
(瞳の輪郭部分については何もしていないのでもちろん表示がバグったまま。)
追記:調査の過程でPythonでVRM内部を直接編集しましたが、現在はアドオンの最新版を利用するのが最もシンプルな解決策です。
関連情報
同様の事象は、VRMアドオンのGitHub Issueにも報告があったみたい。
Blenderとアドオンのバージョン組み合わせにより発生する可能性があったようです。
v3.11.1リリースに伴いresolvedとなりました。
- glTFに関して、Pythonでの取り扱い方の参考記事
透過処理の話はまじでむずぃ。