見出し画像

趣味開発のアプリでVRM1.0モデルの読み込みに対応した話

※2022/12/12追記: スライドの中で触れている骨折バグが(恐らく)完全に治った事について追記しました。

こんにちは、クラスターでSoftware Engineerをやっている獏星(ばくすたー)です!

本記事は クラスター Advent Calendar 2022 9日目の記事です。8日目の記事はtharaさんのOverwatch2とチーム開発でした。記事の解釈としてはアレですが、ゲーム中に「コレって実質仕事では?」と思わされることは往々にしてありますよね…。

はい。

本記事ですが、趣味開発の自作アプリでVRM 1.0形式モデルの読み込みに対応した話を紹介します。

※事前注意ですが、この記事は個人開発で作っているアバターアプリである VMagicMirror の開発に関するものです。趣味開発の話題のみが出てくることをご承知おき下さい。


この記事では説明しないこと

VRMという人型3Dモデルの形式の詳細については本記事の範囲外です。


おもな対象読者

  • アバターアプリ開発者で、現在VRM 0.x形式のモデルを扱っており、VRM 1.0対応に興味がある人

  • アプリ開発者ではないが、VRM 0.xとVRM 1.0の互換性がどのくらいあるのか気になっている人


前提: VRM1.0っていつ出たんですか?

「VRMは知っているけどVRM 1.0って何?いつ出たの?」という人や、先にオフィシャル寄りの情報を拾いたい人のために前提知識を確認しましょう。

カッチリした定義をGitHubで見るアプローチもありますが、初手はVRMコンソーシアムの動画から入るのが分かりやすくて良いと思います。

アプリ開発者は途中は飛ばしながら見ても大丈夫で、最後の「アプリケーションをVRM 1.0対応にしてみよう」が主に注目すべきパートとなります。

上記の動画紹介があったタイミングとか、UniVRMのリリース履歴を踏まえると、「VRM1.0がいつ出たか」の答えとしては2022/9/22のUniVRM 0.104.0がリリースされた時点と考えるのが一つの回答になります。

参考: https://github.com/vrm-c/UniVRM/releases/tag/v0.104.0


本題

では本題です。

以上です。


いかがでしたか?


最後までお付き合い頂きありがとうございました!


本題2: スライドの補足

流石に投げすぎなので補足します。

前述したUniVRMのリリース自体や、それに付随したサンプルプロジェクト(VRM_Samples-0.107.0_1e8a.unitypackageなど)やらを踏まえて、アプリ開発者のやることは結局次のようなフローになります。

  • サンプルプロジェクトを眺める

  • モデルのロードAPIをとりあえず差し替える

  • VRM 0.x用のクラスはもう使われないので、新しいクラスにどんどん書き換えていく

    • ここの詳細はスライドでは省略している部分も多いです

  • 利用規約UIは作り直す

  • 使うクラスをVRM 1.0用に書き換えてもバグってる部分はどうしても出るので、ひたすら直す

  • 直し終わったら完成!

このフローの唯一にして最大のポイントを抑えておくと、UniVRMのAPIが完全に非互換で大幅に変わっているため、手間がかかり、かつバグから逃げ切るのはとても難しいです。

VRM 0.xからVRM 1.0への移行は(少なくともUniVRMでは)呼び出すAPIをゴリゴリ刷新することで成立します。よくあるライブラリのアップデートとは全くノリが異なるので、少なくともPythonを2.xから3.xに引き上げるとか、Unity EditorやUEを4年分くらい一気にバージョンアップするときのような緊張感が求められます。

アプリ側でVRM 0.xを使い倒していたり、アバターの操作を作り込んでいればいるほど緊張感は高くなります。VMagicMirrorの場合は次のような特徴がありました。

  • 瞬きに合わせて目を少し下に向けるなど、目の制御でやや細かい事をしてる

  • IKとFK (AnimationClip + 自作のモーションファイルフォーマット) の双方でアバターが動くようにしている

  • パーフェクトシンクに対応している + それ以外でも表情をカスタムして適用できる

こうした特徴により、比較的マイナーな地雷も踏んだような気がします…。

具体的な内容はスライドを再度ご覧下さい。


VRM1.0向け実装(UniVRM v0.108.0)の良いところ

ここまで苦労話みたいなトーンで色々書いてきましたが、悪い話ばかりではないのは強調しておきます。

まず新APIではVRM 0.x系/1.0系のモデルがどちらも読み込めます。私はVRM 1.0の話が浮上した当初「モデルロードから互換性が無いのかな~めんどくさそうだな~」と思っていたので、この点はかなり安心しました。

そのほか、揺れものは公式の実装がJob Systemベースになった(※)おかげで手軽にそこそこ速く動いてそうですし、スライド中で紹介したように風エフェクトのような揺れもの制御に適したAPIもあります。VMagicMirrorでは風エフェクトを搭載してから3年ほど経つので、API側で配慮があったのは嬉しいポイントです。

※VRM 1.0移行前はUniVRMの揺れものではなく、有志によるJob版の実装を使ってました。

また表情周りのAPIはシンプルになり、モデル側の表情設定と、それを制御するコードとが分割されました。読み味、書き味どちらも向上していると言えるでしょう。

以上のように、最終的にVRM 1.0対応するのはコードメンテナンス的に見ても良いことだと思います。モデル所有者側でVRM 1.0形式が普及する前にアプリのVRM1.0対応をトライするのは是非おすすめしたいです!


最後に: 具体的な話

VMagicMirrorはOSSなので、なんとVRM 1.0対応の全容が公開されています。

…全容がデカすぎて読みにくいですね。+20000行の差分のうち大部分はVRM 1.0向けの利用規約UIですが、それを差し引いてコード差分だけ見ても結構なボリュームがあります。

少なくとも日本語圏の皆様は直接聞いてもらったほうが速いと思います。アプリ開発者でVRM 1.0対応に興味がある方は、Twitterとかで質問いただければ可能な範囲で回答します。

なお、VRM1.0対応由来のバグリストも着実に溜まっていて上記PRのマネでうまく行くことは一切保証できませんので、そこはご注意ください。


本記事は以上です。

翌日、クラスター Advent Calendarの10日目はmarikoさんの「全部同じじゃダメ!?マルチデバイスアプリでの操作・体験設計」です!



2022/12/12追記: 骨折バグが完全に直りました

※この追記はアプリ開発者のみ対象にしています。

記事中のスライドにて、VRM 1.0移行中に起こったアバターの骨折バグについて触れ、UniVRMのRepositoryにissueを立てて助けて貰ったことを紹介していました。以下はそのことに関する追記です。

issueの回答ではFinalIKのFullBodyBipedIK(FBBIK)を適切にセットアップすれば骨折しないことを教えてもらい、実際に9割ほど直った状態になったのですが、アバターを体格の異なるものに切り替えるとまだ骨折するケースが残っていました。スライドで「絶賛調査中」と書いてた部分がそうです。

で。

その後、調査の一環で改めてFinalIKのドキュメントの"Adding FullBodyBipedIK at Runtime"というセクションを読んだところ、FBBIKのセットアップをするときはTポーズではなくIポーズ(気をつけの姿勢)を基準に各種の方向をコードで指定してね、という記述を発見しました。

// To know how to fill in the custom limb orientations definition, you should imagine your character standing in I-pose (not T-pose) with legs together and hands on the sides...

http://www.root-motion.com/finalikdox/html/page8.html


こういう想定姿勢がどうこうという記述は行き違いとかバグの温床なため注意して読み直したところ、最終的にVRM1.0モデルと動的生成したFBBIKの組み合わせでは以下のような引数の組み合わせが期待されていると分かりました。

fbbik.solver.SetLimbOrientations(new BipedLimbOrientations(
    // 最初の2つは第3引数がVector3.leftではないことに注意
    new BipedLimbOrientations.LimbOrientation(Vector3.forward, Vector3.forward, Vector3.up),
    new BipedLimbOrientations.LimbOrientation(Vector3.forward, Vector3.forward, Vector3.down),
    new BipedLimbOrientations.LimbOrientation(Vector3.forward, Vector3.forward, Vector3.left),
    new BipedLimbOrientations.LimbOrientation(Vector3.forward, Vector3.forward, Vector3.left)
));

これを踏まえて手元の処理を直したところ骨折バグは完全に直り、アバターの体格差によらず良い感じに動いてくれるようになりました!

この話は完全にFBBIK限定のバグ対策なため応用性に乏しいですが、おそらく他のIK実装でもIKの機嫌をちゃんと取れてるかどうかがVRM 1.0のボーン制御の成否に影響するケースはあると思われます。

もしVRM 1.0移行中に骨折バグを踏んだ場合、使用中のIK実装をよく調べ直すことを検討してみて下さい。

参考: UniVRM側のissue / VMagicMirrorで追加修正を入れたPR

この記事が気に入ったらサポートをしてみませんか?