VRMのバイナリとかを見て遊んでた記録

はじめに

vrmのバイナリや構成を見て遊んでたこと、思考を垂れ流しで書き留めておきます。別に何かできるようになるような記事ではないです。

はじまり

clusterにVroidのモデルをアップロードしようと思ったらアップロードのサイズ制限に引っ掛かってアップロードできなかった。(当時vroidは素体だけで30Mb近くあった)。だが、vrmという規格は新しすぎて特に圧縮するようなサービスがない。

なので、「とりあえずバイナリエディタに突っ込んでいらなそうなとこ削ってみるか」、という安易な気持ちでバイナリエディタvrmファイルをつっこんだ。異様に長いシグネチャに違和感こそ感じたものの、画像ファイルっぽいバイナリ部分を見つけたので削除してみた。これで、ちょっとテクスチャはバグったような見た目にはなるものの動きはするだろうと思ったが、全く動かなかった。

不思議だ。もしかしたらヤバいところを消してしまったのかもしれない。バックアップからデータを復元し、画像バイナリのようなクリティカルな部分ではなく、ASCIIで構成されたテキスト部分らしき部分を少し消してみた。これなら構造を壊してないはずだ、と思ったが全く動かない。1byteでもバイナリの挿入/削除を行うとデータが壊れる。

分かった、「これ相対参照してる!」、間違いない。飛ばして特に読んでいなかったバイナリの最初の方のASCIIを読んでみると、明らかに相対参照してそうな文章が見つかる。というか、これJSONじゃねぇか...。うーん、これは普通の3Dモデルのファイル形式でもないし、vrmの独自規格でもなさそうだ。

glTF-2.0に気付く

独自規格だろうし、どうせ知らんファイルシグネチャだろうと無視してたファイルシグネチャを調べてみる。glTF・・?なるほど、こういうファイル規格があるのか。ちなみに、glTFのファイルシグネチャは「67 6C 54 46 02 00 00 00」だった。 さっそくglTFのGithubへいき、READMEに目を通した。
github.com

VRMの構造理解

「ははーん、こんなカラクリがあったのか」と、glTFのREADMEとVRNのバイナリを交互に見ながら構造理解を進めていく。これは面白いものを見つけたと、喜んで見ていたがあるものを見つけてしまった。

ドワンゴさんのVRM仕様 - dwango on GitHubに全てが載っている...。これまで解析していた内容は無に帰した。ここまで分かりやすく技術公開を行ってくださるとは、さすがドワンゴさんだ。素晴らしい。

テキストファイルによるモデル編集

なるほどなるほど。こんなJSONで分かりやすく管理されているならば、わざわざモデリングソフトやUnityを使わずともモデル編集が可能じゃないか。テキストエディタの軽快な動作でやってしまおうじゃないかと。そう思って調べてみたら、丁度いいのがあった。
VScodeにglTF向けのExtensionがある。これはいい。使ってみよう。
marketplace.visualstudio.com

拡張子こそvrmはglTFと違うが、根本的な構造は一緒だ。ちょっとJSONが拡張されたぐらいだし、glTFと互換性があって当然だ。拡張子さえ合わせればこのglTF向けのExtensionはバッチリ動いてくれるだろう。

完璧だ。素晴らしい。変更も全て思った通り綺麗に反映されていく。 f:id:colaiiiyahhou:20181028192507p:plain

詳しくは別途で記事を書いたので、気になる人はそっち見て。 qiita.com

vrmを人力分解する

vrmはglTFのバイナリ形式であるglbで構成されている。が、特にそんな圧縮されているわけでもなく、テクスチャやボーン情報などが定義されているJSONファイル(.gltf)、アニメーションやジオメトリ情報を含むバイナリファイル(.bin)、テクスチャの画像ファイル(.jpg,.png)で構成されている。特別ツールを使わないでも普通に目grepなりして抜き取ることができる。

例えばだが、こんな感じでpng画像のファイルシグネチャと終わりの部分を検索をかけて、マーキングし、その間の部分を切り取ればすぐに分解することができる。終わり部分のすぐ後に次の画像バイナリも始まっており非常に分かりやすい。

f:id:colaiiiyahhou:20181028220028p:plainf:id:colaiiiyahhou:20181028215944p:plain

ビルドされた実行ファイルからvrmファイルを抜き取る

結論から言うと、Unityのバージョン2017以降で作られたものから抜き取るのは僕にはできなかった。逆にバージョンが5系統以下なら比較的容易に抜き取れた。だが、それはvrmだからという理由ではない。Unityそのものの脆弱性だ。

VRMはこんなに分かりやすい形式だし、VRMで作られたゲームなどはバイナリを覗いて簡単にデータの抜き取りができるのでないかと思った。というわけで、vrmのモデルを配置しただけの簡単なプロジェクトをunityで作成し、ビルドして実行ファイルを作成した。

しかし、どこにもvrmの痕跡が見当たらない。sharedassets0.assetsあたりにあるはずなのだが、どこにも見当たらない。どうやらビルドされて組み込まれる時にはもうvrmの形式ではないようだ。

もうちょっと詳しく見てみよう。Unity Assets Bundle Extractorというツールを使って組み込まれているデータを見てみた。こちらのツールの使い方は以下のサイトが分かりやすい。 blog.fujiu.jp

読み込み解析自体はできたが、Unity2017.4で開発していたため、案の定エクスポートができなかった。この時点でどんなファイルが組み込まれているか分かったので、大体察しはついたが、せっかくなので5系で作り直してエクスポートもしてみた。

vrmとしてではく、meshデータからobjファイルとして抜き取ったことになるができた。この調子でテクスチャなども抜き取っていき、再構成すればvrmファイルとして再現できるだろう。 f:id:colaiiiyahhou:20181028220752j:plain

どうやら普通にいつも通りのprefabが組み込まれてるっぽいですね。そういえば、vrmファイルをunityにインポートするとprefabが生成され、それを使ってましたね。よく考えたらvrmなんてシーン上においてないしビルドしていない。vrmはモデルデータの設計図とパーツの詰め合わせパッケージようなもので、実体は設計図のJSONを参考に作り直して使っているようですね。その作り直す機構がUniVRMパッケージでそいつがvrmファイルからprefabを生成し、それをモデルデータとして扱っているわけだ。なるほどなぁ...。

Vroidのモデルをclusterで使用する(ごり押し)

はじめに

clusterでのハロウィンイベントのため、Vroidのモデルをアップロードしてアバターとして使いました。
ただ、Vroidのモデルはポリゴン数、マテリアル数ともに非常に多く、clusterのアバター制限に引っ掛かりアップロードできません。なので、Unityでモデルをごり押し編集してアップロードしたという話です。
f:id:colaiiiyahhou:20181028164827p:plain

モデリング全く分からんけどUnityなら使えるマンの記事です。読者もそのレベルを想定しています。Blenderなどが使えないのでUnityでごり押してます。

利用環境

・Unity2017.4.12f1
・cluster(2018/10/26 現在)
・Vroid(v0.2.15)

本題

目次
1.Vroidでモデルを用意する
2.Unityでモデルを調整する
番外 ちょっとオシャレする

1.Vroidでモデルを用意する

自由にモデルを作ると制限に引っ掛かりまくってアップロードできなくなりました。以下の点に注意してモデル作成をしました。
Vroidの基本的な操作については以下が参考になります。 sleepfreaks-dtm.com

目次
1-1. 髪の毛を10本程度に抑える。
1-2. マテリアル数を意識する。

1-1.髪の毛を10本程度に抑える。

Vroidは髪の毛1本1本にマテリアルを設定していきます。clusterは32個以上のマテリアル設定が行われたモデルにエラーを返すため、この仕様と非常に相性が悪いです。

Vroidのモデルは髪の毛なしの素体だけでも15のマテリアルが設定されています。なので、素体のマテリアルを削らないのであれば、描ける髪の毛は17本までとなります。
また、髪の毛1本増えていくごとにポリゴン数も上がっていきます。ポリゴン数の観点からみても、たくさん髪の毛を描くのは厳しいです。

丁度17本髪の毛を生やすと今後モデルの装飾なども行うときに厳しくなるので、10本程度くらいに抑えて作りました。

なお、髪の毛を描く際ですが、 テクスチャパラメータの横幅をできるだけ小さく、ヘアーパラメータの太さをできるだけ大きくすると少ない髪の毛でも誤魔化しやすかったです。後ろ髪など目立ちにくいところは太くして本数を節約し、前髪などこだわりたい場所に本数を割けるようにすればまだマシな見た目にできると思います。

f:id:colaiiiyahhou:20181028054511p:plain

1-2.マテリアル数を意識する。

clusterのマテリアル数制限は8個までですが、Vroidのモデルは髪の毛のマテリアルを抜いても15個もあります。後でマテリアルを削ることになります。各テクスチャを複雑なデザインにせず、淡泊なデザインにしておくと使いまわしがきいて良かったです。 また、髪の毛の色も1色増やすごとにマテリアル数も増えるので、髪の毛の色は1色に抑えました

ただ、モデル生成時点でどのマテリアルを残すのか決めるのは難しいので、テクスチャデザインは一回全て後回しにして次のUnity作業をした方がおすすめです。

Vroid上で編集できる以下の画像の要素は全て1つ1つマテリアルとして生成され、cluster制限を圧迫します。各パーツのマテリアルが使いまわせるようによく考えてデザインしましょう。

f:id:colaiiiyahhou:20181028063027p:plainf:id:colaiiiyahhou:20181028062945p:plain

2.Unityでモデルを調整する

先ほど生成したモデルをUnityで読み込みます。
Unityインストールする方法は以下参照。
tech-camp.in

UnityでVRMをインポートする方法は以下参照。
qiita.com

目次
2-1.マテリアルの削減
2-2.マテリアル設定

2-1.マテリアルの削減

以下の[モデル名].Materialsにあるファイルを削除していきました。このフォルダのマテリアル数を7個以下にしないといけません
clusterのマテリアル制限は8つですが、1つシェーダに使われているマテリアルがあるので、使えるのは7つまででした。(シェーダのマテリアルを削るのも試したが、見た目がすごく残念になったので微妙だった)
f:id:colaiiiyahhou:20181028155213p:plain
・F00_000_Body_00_SKIN(Clone)
・F00_000_EyeExtra_01_EYE (Instance)
・F00_000_EyeHighlight_00_EYE(Clone)
・F00_000_EyeIris_00_EYE(Clone)
・F00_000_EyeWhite_00_EYE(Clone)
・F00_000_Face_00_SKIN(Clone)
・F00_000_FaceBrow_00_FACE(Clone)
・F00_000_FaceEyelash_00_FACE(Clone)
・F00_000_FaceEyeline_00_FACE(Clone)
・F00_000_FaceMouth_00_FACE(Clone)
・F00_000_HairBack_00_HAIR (Instance)
・F00_001_Accessory_01_CLOTH(Clone)
・F00_001_Bottoms_01_CLOTH(Clone)
・F00_001_Shoes_01_CLOTH(Clone)
・F00_001_Tops_01_CLOTH(Clone)

僕は以下を残しました。 f:id:colaiiiyahhou:20181028155429p:plain
・F00_000_EyeHighlight_00_EYE(Clone)
・F00_000_EyeIris_00_EYE(Clone)
・F00_000_Face_00_SKIN(Clone)
・F00_000_FaceBrow_00_FACE(Clone)
・F00_000_FaceEyelash_00_FACE(Clone)
・F00_000_Hair_00_HAIR
・F00_001_Bottoms_01_CLOTH(Clone)

個人的に残した理由
目が死んでると一気に可愛くなくなったので、目のマテリアルは残した。
・F00_000_EyeHighlight_00_EYE(Clone)
・F00_000_EyeIris_00_EYE(Clone)

肌色のマテリアルは一個は必要。目の白目、体の肌にも使いまわした。
・F00_000_Face_00_SKIN(Clone)

まつ毛は後述の方法で誤魔化した。1つでもまだ大丈夫。眉毛はないと怖い。
・F00_000_FaceBrow_00_FACE(Clone)
・F00_000_FaceEyelash_00_FACE(Clone)

さすがに髪の毛はいる。その他アクセサリーとかでも使いまわせるので良い。
・F00_000_Hair_00_HAIR

服のマテリアルを消し、スカートだけ残したのは苦肉の策。単色とか淡泊なデザインにしてワンピースっぽくすれば誤魔化せんでもない。
・F00_001_Bottoms_01_CLOTH(Clone)

2-2.マテリアル設定

マテリアルを消したことにより対応していたマテリアル設定が空白になってピンク色になったので、その部分を埋めていきます。モデルのSkinned Mesh Rendereに各マテリアルが設定されています。僕は以下の画像のように設定しました。
f:id:colaiiiyahhou:20181028162132p:plainf:id:colaiiiyahhou:20181028162218p:plainf:id:colaiiiyahhou:20181028162100p:plain

番外 ちょっとオシャレする

さすがにそのままってのも味気ないのと、まつ毛を削ったことで目が少し寂しい感じなのでちょっとオシャレさせました。

角を生やす
以下のユニティちゃんのダレデモユニティチャンニナールから角をとってきて、モデルに生やしました。モデルのHead以下に配置すれば大体大丈夫です。   unity-chan.com f:id:colaiiiyahhou:20181028165256p:plain

眼鏡をつけさせる
以下からお借りしました。同じくモデルのHead以下に配置すれば大体大丈夫です。
顔のマテリアル削った違和感を隠すのに眼鏡はとても良かったです。 booth.pm

かぼちゃのイラストをつける
以下のサイトから画像を拝借し、Gimpを使って服のマテリアルの画像にはっつけました。 www.illust-ai.com

最後に

モデルをvrmとしてエクスポートしましょう。
UnityのWindow上部のUniVRMタブからExport humanoidを選択し、各項目を埋めればvrmとしてエクスポートできます。

clusterアップロード時にありがちなエラー

[{"Code":"TOO_LARGE_COUNT","Resource":"image","Message":"image count is too large.","Meta":{"actual":hoge,"max":16}}

テクスチャの枚数が多いです。vrmには著作権表示のアイコンに設定されるテクスチャがあるので、それを削除することで超過2枚までなら全く見た目を変えないで削減することは可能です。

{"Code":"TOO_LARGE_COUNT","Resource":"material","Message":"material count is too large.","Meta":{"actual":hoge,"max":8}}]

マテリアル数が多いです。減らしましょう。

{"Code":"TOO_LARGE_COUNT","Resource":"primitive","Message":"primitive count is too large.","Meta":{"actual":49,"max":32}}

マテリアルの設定数が多すぎです。Vroidでは髪の毛の生やしすぎが原因なことが多いです。

VRMファイルのプレビューに失敗しました。SDKを利用してUnityでお試しください。

マテリアルの設定が外れています。どうやらclusterはマテリアルが剥がれた状態になっているモデルを弾くようです。