vrm-c / vrm-specification

vrm specification
232 stars 36 forks source link

[VRMA] Humanoid ボーン以外のアニメーション #437

Open ousttrue opened 1 year ago

ousttrue commented 1 year ago

TODO: Hipsより親にアニメーションが含まれていた場合はどうしましょう? Rootを指定させた方が良いでしょうか?

ousttrue commented 1 year ago

Humanoid ボーン以外のアニメーション

意外とややこしくて、厳しくするとエクスポートする側の負担が増すというトレードオフがあります。 一切禁止しないでよさそうな気がします。

import 側で如何に無視するのかガイドラインを作ってはどうかと思います。

引き換えに import 側は各ボーンのローカル回転値が humanBone の回転値であることを期待できなくなります。 各ボーンのローカル回転値は HumanoidParentInv * world で算出するという方式になりそう。 HumanoidParent というのがポイントで実際の親 node でない可能性があります。

ousttrue commented 1 year ago

あたりが strict で扱いが簡単なクリーンなものになりそう。 not clean なものから clean なものを生成することは可能です。

TokageItLab commented 1 year ago

VRMA が glTF と同じように Humanoid 以外のボーンの Bone Rest を保存するのであれば、Humanoid 以外のボーンに対して下手に回転値を弄るべきではないと思います。それらに対してだけ例外的に相対的な値をアニメーションから抽出するというのは冗長で、Humanoid であるボーンとの一貫性がなくなってしまう事になります。

そもそも VRMA に記録されるのは glTF と同じように各ボーンのレスト回転を含む Absolute な回転値を想定しているという認識であれば、

各ボーンのローカル回転値は HumanoidParentInv * world で算出するという方式

初期姿勢に回転を含まない

これらはそれぞれ https://qiita.com/TokageItLab/items/beaf219762e1e34a6250 の記事で説明した Local Animation と Global Animation だと思っていますが、それを VRMA 自体に記録するというのは、記録された値を使用したい場合に、リターゲットの方法を間接的に指定することを意味します。

リターゲットの方法をアニメーションデータの方で指定する事は問題ないと思っています。

しかし場合によっては、そのような Local Animation や Global Animation としてのデータの格納はあまり良い方法ではないと思います。

例えば、Local Animation を記録している VRMA から Absolute Animation を取得したい場合、 Local Animation の値にソースモデルのボーンのレスト回転を再度乗算して値を復元する必要があります。この時、特に Local Animation と Global Animation の変換については計算上 Local Animation -> Absolute Animation -> Global Animation という Absolute Animation を経由した計算を行う必要があります。

『リターゲットの方法を指定する enum オプションをボーン毎に設定できるように VRMA に含めて、値の適用方法をアニメーションの制作者が指定する』のであれば事前計算は計算量を減らすために意味のあるものになると思いますが、『リターゲット方法を後からアニメーションを利用するユーザーが指定するのを可能にする事を前提としている』のであれば、Absolute Animation として記録しておくのがリターゲット方法の変更時に最も計算量が少なく、元の glTF アニメーションとの互換性もあるため無難だと思われます。

もし『ソースモデルのレスト回転を同梱しない』ようにして、リターゲットの適用方法を『アニメーションの出力時にのみ決定できる』ようにしてしまえば、そのような事前計算はデータの軽量化・計算量の削減という面で間違いなく意味があります。しかし、これは glTF との互換性を破壊するので json ベースの glTF ではない新たなフォーマットを作成する事になり、あまり手軽ではないかもしれません。


余談1 アニメーションにおける T-pose 定義について

この issue では off-topic かもしれませんが、VRMA の中の Humanoid についても T-pose である事を明記した方がよいかと思われます。


余談2 ルートモーションの正規化について

上記にも関連しますが、root(もしくは他のボーンの position アニメーション)をリターゲットする為には各モデルの歩幅の比率によって値を計算し直す必要があります。歩幅の比率の近似値としては T-pose 時の hips の高さが利用できますが、これを VRMA として何らかの形で定義に入れる事はできるでしょうか。例えば、position アニメーションの値に関しては hips の高さ等で除算し、正規化されて格納される形(つまり全ての VRMA には hips の高さが 1m のモデルで position アニメーションが再生された状態が記録される)でもよいかもしれません。


長々と失礼致しました。

TokageItLab commented 1 year ago

ousttrue 氏の最初の方のコメントで少し示唆されていますが、ガイドライン側で解決するというのが最も良いように思えます。

Humanoid 外のボーンアニメーションの回転値には手を加えず、 https://qiita.com/TokageItLab/items/beaf219762e1e34a6250 で示したような3つのリターゲットの計算方法をガイドラインに明記し、Uni-VRM 側でそれら3つのリターゲットを行うための API を用意するのが最も良いと思われます。

また、スケールに関してもアクセサリー等として利用するケースが存在するため、基本的には破棄しない方がよいように思います。上記のリターゲットの計算により相対値等が算出できる場合、ユーザー側で解決可能な筈です。

ただし、「Root や関節間ボーンのような Humanoid ボーンを子孫に持つケース[^1]」や「負のスケールや非直交なスケール[^2]」では問題が発生する可能性が考えられるため、

というような制約を持たせるのが良いのではないでしょうか。

[^1]: 非 Humanoid ボーンの scale を 0.1 にした後、その子の Humanoid ボーンの scale を 10 にして見た目を整える可能性がありますが、これを非 Humanoid ボーンを持たない Humanoid に適用するとアニメーションが想定通り(見た目通り)に適用されない可能性があります。Humanoid ボーンに関してスケールを1に強制する事については個人的にはまだ許容範囲ですが、その場合このような関節間の非 Humanoid ボーンとの整合性がとれなくなるため、『子孫に Humanoid ボーンがある場合にはスケールについての制約を課し、子孫に Humanoid ボーンを持たない場合はスケールについての制約はない』というのが良いと思います。

[^2]: 回転が壊れる可能性があります。Shear な scale についても同様です(これは glTF の方で何らかの制約があったような気がしなくもないですが..)。