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を生成し、それをモデルデータとして扱っているわけだ。なるほどなぁ...。