※ この記事は VRM 1.0 における変更点をざっと見た感想を述べるものであって、VRM 0.x 対応アプリを VRM 1.0 に対応させるための手順などを詳しくまとめるようなものではないことをあらかじめ断っておきます
VRM 1.0 所感
より glTF 拡張フォーマットとして正しくなった VRM 1.0
VRM 1.0 のリリースおめでとうございます。このリリースにおいて、個人的に大きな変更であると感じているのは以下の3つです。
- アセットが +Z 軸向きに格納されるようになった
- モデル内部の座標パラメータが OpenGL 座標系で統一された
- ボーンのローカル軸を保持するようになった
これらは glTF 拡張フォーマットを名乗る以上は VRM 1.0 で絶対に直して欲しかった所だったので、それらが修正された今、VRM はようやくアバターの統一規格としての第一歩を踏み出せたのではないでしょうか。(僕は本当にこれがスタート地点だと思っています)
SNS での反応
ところで VRM 1.0 についての反応を SNS ですこしリサーチしてみた所、あまり良くない反応というかボヤきをちょっと見かけたので、VRM コンソーシアムとは全く関係なく僕が個人的に回答をしてみようと思います。
SpringBone がボーン個別にパラメータを設定するようになったので面倒
これは完全に GUI の問題であって、VRM 1.0 のフォーマットそのものが悪いわけでは決してありません。例えば、Unity 側で開始ボーンと終了ボーンをセットしてカーブを描く事でそれらのボーンに値を設定するような GUI を UniVRM もしくは何らかの VRM 作成アプリで実装すれば解決できる問題だと考えます。
VRM 0.x の IK 設定をそのまま持ってくると壊れる
前回の記事で書いた通り、IK における回転軸の決定方法によってはその挙動が壊れる可能性があると思います。VRM 0.x で正規化された軸を決め打ちで指定している場合、Unity においてはその参照を UniVRM の ControlRig に置き換えることで互換性を保つことが出来るのではないかと予想します。(未検証)
本題
VRM 1.0 の親指の向きの定義
※ ここからはボーンやリターゲットについての用語を交えて話をします。可能であれば前々回の記事や前回の記事をざっと流し読む事をオススメします
さて、VRM 1.0 で T-pose についてのガイドラインも更新されました。概ね問題ないと見ていますが、その中で少し引っかかる点がありました。
#### 定義 1.8. 見た目上、親指は X 軸と +Z 軸の中間の方向に伸びていて、地面と平行であると定義します。
見た目上、親指は地面と平行に、X 軸と +Z 軸の中間 45 度の方向に真っすぐ伸びていると定義します。
また爪の面は他の 4 本の指とは違い 90 度外側にロールした方向を向きます。
なるほど、親指の向きについての定義ができたようです。ただし、あくまでこれはメッシュの形状についての定義であり、関節ルールすなわちローカル軸の向きの定義ではない事に注意が必要です。
とりあえずメッシュについては、親指が伸びる方向は他の指と同じく水平で、人差し指に腹を完全に向ける状態が VRM 1.0 の親指としては正しいという事になります。
この画像の指はロボットハンドなので問題なく見えますが、一般的な人型モデルの場合、最初からこの状態で指をモデリングする事はまずありえないと思います。とはいえ、数値・目安としては分かりやすいのでこれが悪い定義だとは言い切れません。
この定義が意味する所は、指をモデリングする時は好きなように作ってもよいが、VRM としてエクスポートする時だけこのような向きでエクスポートする必要があるという事です。
Blender で例えるなら、指を作成した後に Edit モードではなく Pose モードで指を回転させた状態で Armature モディファイアを適用し、『Apply Pose as Rest Pose』を行なうという操作がエクスポート前だけ必要になります。
当然、この操作を行った時点で親指の根本周辺のメッシュが乱れますが、VRM 1.0 としては問題ありません。後々ボーンを本来の角度にアニメーションさせればメッシュも元通りになるからです。したがって、この操作が原因で発生したメッシュの乱れを手直しする必要は無く、むしろ避けるべきです。
この親指についての定義があまり周知されていないように見受けられ、定義に沿っていない VRM 1.0 モデルが大量に出回ってしまうのではないかという事について、僕はかなり危険視しています。
定義に沿っていない VRM 1.0 モデルが出回ってしまったとして、どのぐらい問題になるのか、何か対策できることはないか、そもそも指の向きに定義が必要なのか、色々と考察してみましょう。
補足1:エクスポート時のメッシュの乱れについて
@mimyquality さんから、「90 度ロールした親指のメッシュは乱れていない方がよい」との意見がありました。調べてみた所、Unity の Humanoid Muscle には指のロールをアニメーションさせる機能がないそうで、Humanoid Muscle を利用する環境では『メッシュの乱れをアニメーションの中で再度ロールして戻す』ことが容易ではないようです。
参考記事:Unity Humanoid制御に指ロールを追加したい
とはいえ、Unity Humanoid Muscle もレガシーなシステムになってきていると感じます。
少なくとも glTF には指ロールのアニメーションを持たせる事が可能であり、また VRM 1.0 は Unity への依存性を排除した独立した glTF の拡張フォーマットとするのであれば、下位環境に合わせて指ロールを切り捨て、アバターとしての表現力を落とす事は避けるべきでしょう。
Unity Humanoid Muscle での利用のみを前提とするなら、メッシュの乱れはエクスポート時に解決しておいた方がよいかもしれませんが、VRM 1.0 が Unity 外にも普及する将来を見据えるのであれば、指ロールをアニメーションさせる事を前提としたセットアップをすべきだと考えています。
補足2:VRM 1.0 のアニメーションについて
VRM 1.0 は現在(2023年6月) アニメーションの為のフォーマットを整備しており、その中で指ロールをよしなに扱えるようにして欲しいとの Issue を立てたところ、現時点においては Humanoid の HumanPose を介さない形でアニメーションを適用する事を想定しているという旨の回答を頂きました。つまる所、glTF に記録されている Transform 値がそのまま VRM 1.0 のボーンに適用されるため、指ロールのアニメーションも正しく再生されるとの事です。
この事からも、やはり VRM 1.0 としての利用を前提とするなら、親指がアニメーションにより自然なロール値に戻る事を前提としてセットアップする(エクスポート時のメッシュの乱れはわざと解消しないでおく)方が良いであろうと現段階では結論づけられます。
そもそも指の向きに定義が必要なのか
ここで基本に立ち返って、なぜモデルが T-pose のような形でシルエットが統一されていると便利なのか考えてみましょう。前回の記事で、glTF におけるボーンアニメーションの適用方法には AbsoluteAnimation・LocalAnimation・GlobalAnimation の3通り考えられる事について説明しました。
Blender のアニメーションシステムは LocalAnimation を採用しており、また VRM 0.x の正規化は GlobalAnimation の適用を静的に行うような物です。そして、LocalAnimation と GlobalAnimation は初期ポーズからの相対的なアニメーションを行うので、それらでは初期ポーズのシルエットを一致させる必要があるのです。
それを踏まえると、一般的なアプリケーションとの互換性や VRM 0.x の正規化を考慮する場合、初期ポーズのシルエットが一致している方が望ましいという事が言えます。
なぜ A-pose ではなく T-pose を利用すべきなのかというかという話については今はあまり関係ないので、余談として最後に書いておきます。
指については AbsoluteAnimation が使えるのではないか
ここで AbsoluteAnimation についてもう一度考え直します。AbsoluteAnimation はレスト成分を含むと以前説明しました。
レスト成分とはすなわちモデルの初期ポーズであり、つまり AbsoluteAnimation はモデルの初期ポーズを考慮せずにアニメーションを行ってしまいます。なので、そのままアニメーションを共有したのではモデルの体型を大きく変化させてしまいます。
このため、前回の記事では AbsoluteAnimation でアニメーションを共有する為には初期ポーズのローカル軸の完全一致を必要としていると説明しました。
ここで、『初期ポーズを考慮せずにアニメーションを行う』という点に注目します。
以前、関節ルールの統一についても触れました。そこで関節ルールが統一されている場合、LocalAnimation では関節の向きを尊重したアニメーションの共有が可能になると説明しました。
ここからが重要なのですが、関節ルールが統一されている場合、AbsoluteAnimation ではモデルの初期ポーズに関係なくアニメーションの共有が可能になります。つまり、A-pose のモデルで作成したアニメーションと T-pose のモデルで作成したアニメーションを共有できます。
これだけだと便利に聞こえるかもしれませんが、例えば I 字背骨のモデルと S 字背骨のモデルでアニメーションを共有すると、初期ポーズすなわち背骨の形を無視するために、体幹の歪みが発生します。
また、位置アニメーションの共有はできません。これは初期ポーズの『骨の長さ』を変化させてしまうため、チビキャラを無理やり8等身に引き伸ばすような変形が発生してしまうからです。
引用:https://github.com/TokageItLab/realtime_retarget
low-poly-godette / CC by SirRichard94
背骨はモデルのスタイルに影響するために初期ポーズが重要になります。
では指についてはどうでしょうか? モデルによって I 字だったり S 字だったりする事はあるでしょうか? 位置アニメーションは必要でしょうか?
ほとんどの場合、指についてはモデルに依存したスタイルの違いを気にする必要はないと考えます。
つまり、関節ルールを統一して AbsoluteAnimation でのアニメーションの共有を行うという前提においては、指については明確な T-pose の定義は必要ないという結論になります。
引用:https://github.com/TokageItLab/realtime_retarget
結果として、よりよいリターゲットのためには、関節ルールを決めた上で、背骨から肩にかけては GlobalAnimation、腕や脚には LocalAnimation、指には AbsoluteAnimation というような適用方法が望ましいのではないかと考えられます。
とはいえ...
残念ながら VRM 1.0 には関節ルールの定義は盛り込まれませんでした。
また実際には VRM モデルは、先に述べたようなリターゲットアルゴリズムを選択できる環境で使われるとは限りません。Unity のように出力時の指の形ができるだけ揃っていたほうがよい環境も存在します。
VRM 1.0 では親指の向きが定義されましたが、その周知についてまだまだ不十分です。【親指は地面と平行に、45 度程度開き、かつ爪は 90 度外側に向いている】という状態は、ごく一部の環境では比較的有効である反面、人体において自然な姿勢とは言えません。はじめからこのような形でモデリングしているモデラーはほぼいないでしょう。
一応、最近のアップデートで UniVRM の方には設定すべき親指の爪の向きを示すガイドが実装されてはいますが、その周知はまだまだ足りていないように感じます。
引用:https://github.com/vrm-c/UniVRM/pull/1885
アニメーションを破綻なく共有するために、制定した親指の定義について、モデル出力時のワークフローまで含めてしっかりと説明していく必要があります。
もちろん関節ルール、つまりボーンのローカル軸についても定義していくべきということも、引き続き提唱していきます。
ちなみに Godot に実装したリターゲット用の Humanoid には以前僕が提唱した関節ルールを採用しました。
余談1 T-pose は A-pose よりも適切な定義か
最近 Godot に色々実装している中で、ブレンドアニメーションのような回転の合成においては初期ポーズから 180 度以上回転しないというような計算を行うことにより、ポーズ同士を補間する際にボーンが体を貫通するのを防ぐことが出来るという事を覚えました。
引用:https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html#for-better-blending
つまり、モデルの初期ポーズはできるだけ関節の可動域の中間であるとプログラム上も助かるという訳で、T-pose や A-pose はその需要を満たしてくれます。
ただ、実際に関節の可動域の中間を考えると、Unity Humanoid が内部に持つようなバイクポーズの方がより適切かもしれません。
引用:https://docs.unity3d.com/Manual/MuscleDefinitions.html
しかし、T-pose はボーンに設定すべきローカル軸の多くがワールド XYZ 軸とほぼ直交しており、A-pose やバイクポーズよりも目標とするポーズが分かりやすいので、プログラマーとデザイナーの両側から見てちょうどよい塩梅の初期ポーズであり、これが自然とスタンダードなポーズになったのではないかと僕は推測しています。
余談2 VRM 1.0 でも UV の向きはまだ統一されていない?
Unity(DirectX 系)と OpenGL 系では UV 座標の V 軸の向きが異なります。
引用:https://www.charlezz.com/?p=1007
故に MToon の V スクロール値が正の時に視覚的にどちらの方向にすすむか定義した上で、UniVRM からの VRM 出力においては 3D 座標パラメータのように MToon の V スクロール値も正負を反転して VRM 内に格納すべきなように思いますが、どうなのでしょうか......。ただ、この辺りは他の Khronos のシェーダ拡張がどのようになっているのかとかも調査してすり合わせていく必要がありそうで、今後も経過を見守る必要がありそうです。
一応 U スクロール値が正の時に左向き正の時に左向きに V スクロール値が正の時に上向きに進むように定義されているようです。
OpenGL はメモリ内部でテクスチャの上下が逆転するため結果としてテクスチャから見た UV は U-Right V-Down となり、スクロールによりそれと逆方向にテクスチャが移動するという事であれば一貫性はとれているようです。
引用:https://www.puredevsoftware.com/blog/2018/03/17/texture-coordinates-d3d-vs-opengl/
ただ、これらの実装については KHR_texture_transform に従うものらしく、そもそもの Khronos 側でまだハッキリと決まっていない部分でもあるようなので経過観察が必要だと思われます。