この記事の趣旨
下記のソフトウェアを作った本人ではあるのですが、この辺りのソフトウェアで既に実装済みであって、これとは別の実装を作りたい人とか、pixivの中の人とか、原理がわからないとツールを使うのが不安の人とか、いろんな立場の人に読んでもらいたいなと思っています。
VRoid運営がなんと言おうと.vroid内の不要マテリアルは削除していい
複製ボタンで一発で増殖したマテリアルは削除ボタン一発で削除できるのがUI/UXとして好ましいし削除機能を実装しないのは(某天才プログラマーさんの言葉を借りるなら)「けしからん」と思うわけです。
間違えてマテリアル増やしちゃうことだってあるわけじゃないですか。そういううっかりって取り消せること国は権利として認められているのですね。民法95条にも書いてある。
削除処理の実装の実際
それでは処理を順を追って説明します、
##.vroidファイルの構造
VRoidファイルは、ZIPで固めた複数のファイルで構成されますが、説明に必要な部分に絞って表示しております。
Hairishesから参照されている/いないHair-Materialをグループ分けする
髪が参照しているマテリアルというのはhairs_defs.jsonのHairishesの各ノードのParam > _MaterialValueGUIDの値がこれに該当します。
なお、Hairishesは髪グループと髪との2階層構造になっていますが、両方の階層を見る必要があります。
ポイント:material_defs.jsonは髪以外のマテリアルも含む
新しめのバージョンで新規作成したモデルは、便宜上、3つの分類が存在することになります。今回は2のみが削除対象となります。
- Hairから参照されているヘアマテリアル
- Hairから参照されていないヘアマテリアル
- 髪以外のマテリアル
髪のマテリアルであることの識別方法は3つ
また髪かそうでないかを見分けるには以下のいずれかのKey-Value値を見れば良いかと思います。
_PrototypeId => "Flora/F00_000_Hair_00_HAIR"
_SphereAddTextureId => "/Matcaps/Matcap_RimHair"
_Tags => ["HairEditor"]
私は_SphereAddTextureIdを使っています。
というのも"Flora/F00_000_Hair_00_HAIR"の部分は条件によって異なる場合があるからです。
削除するテクスチャの選定
マテリアルとテクスチャは1:1で紐づいていて、削除対象のマテリアルノードの _MainTextureId キーに格納されているIDが削除対象のテクスチャとなります。
ひょっとしたら複数のマテリアルで1枚のテクスチャを共有するケースはあるかもしれません。一応用心のため、削除しないマテリアルから参照されているテクスチャIDが削除対象のテクスチャIDに含まれていないことを確認し、もし重なる部分があれば削除対象から除外しましょう。
SQLiteのエントリー削除
テクスチャの管理テーブルはcanvasとlayerの2つのテーブルで十分じゃないかという気もしないでもないのですが、4つのテーブルから構成されています。
正攻法としてはcanvas_idからこれに属するlayer_idを求め、layer_order, layer_info, raster_layer_contentの各テーブルのレコードを削除し、canvas_infoのレコードを削除する流れとなるかと思います。
髪のテクスチャIDはcanvas_infoのIDではなくnameの方に紐づいているのでその点だけ注意。
各レイヤーのテクスチャ本体はraster_layer_contentのBLOBに上下反転した状態で入っています。
レンダリング済みテクスチャの削除
rendered_texturesの下にPNGファイルが複数あるかと思いますが、削除対象は先のテクスチャIDに.pngを付けたものが対応しています。
Rubyの実装例
そんなわけで以前実装したものを紹介しておきます。
実はヘアプリセットの出力でもマテリアルは削減している。
実はVRoid Studioのヘアプリセットを出力する処理においても、Hairishesから参照されているヘアマテリアルのノードを抽出し、これに紐づくテクスチャのみしか出力しない処理がなされています。
(出力内容を見る限りでは)等価の処理を再現したのが下記のスクリプトです。
こちらも meta.json + hair_defs.json + material_defs.jsonと関連するテクスチャ(PNGファイル)から生成するので、原理としてはかなり近いです。
これは、VRoid Studioにおいてもヘアプリセットのエクスポートの処理を転用すればヘアマテリアルの削除が容易に実装できることを意味しています。
まとめ
VRoidのサポートページを見る限り、マテリアルを削除できないこと、これを削除できるよう要望があることは十分認識していて、それでもなお実装を後回しにしているのは何かしらの事情がありそうだということ。
困っているユーザーがいるのに「何もしない」という答えは最善ではないと思うので、私はマテリアルを削除する手段を作りました。