vrm-c / vrm-specification

vrm specification
243 stars 37 forks source link

VRMのデータ的でのローカル軸の維持 #34

Closed ghost closed 2 years ago

ghost commented 4 years ago

UniVRMの方とどちらが適切か悩みましたが仕様に関わる部分だと思うのでこちらに投稿致します。 現在の、UniVRMで正規化処理を行うとボーンをUnityのHumanoidに最適化したポーズを取り各ボーンの軸がすべてワールド座標に向いて正規化されます。 UniVRMで出力されたデータを、GLTFローダーなどで読み込むと分かりやすいです。

例えば、このように指に対して適切にローカル軸を設定したボーンが

このように、UniVRMでHumanoid向けに正規化されるとメッシュに対してローカル軸が消え、ワールド方向に向き曲がる方向がおかしくなってしまいます。

VRM ヒューマノイドの要件(仮) 加えて T-Poseになっていること 各ノードの回転・拡大は無いこと< UniVRMでこの正規化処理でローカル軸が消え去る

VRMの仕様定義で、各ノードに回転は無いこととあるのですが回転値を0値にするのは構わないですが、Humanoidに最適化したポーズに変形して上記の正規化処理を行うとローカル軸が消えてしまい、Humanoidが実装されている環境以外で読み込むと曲げる方向がおかしくなってしまったりします。 例えば、FBXをHumanoidのセットアップを行った場合元のローカル軸は維持されその上でHumanoidの設定が適用されます。 VRMの仕様的にも同様に、ベースのGLTFのデータ的には元のローカル軸を維持してその上でHumanoidに対応する処理を行う仕様になって欲しいです。

UnityのHumanoidのTポーズ化に依存しないで、ローカル軸の値を0値にした場合指はこのように真っすぐに向いてメッシュと軸方向がちゃんと一致した状態になります。

UniVRMで行われている処理は、正規化時にボーンのParentをすべて解除してワールド方向に向けて再Parentしているのではないかと思います。 こちらのエンジニアの方で、ローカル軸を維持したVRMデータを作成できるように検証を行ってもらいましたが、ローカル軸を維持した状態のVRMも作成でき問題なく動作しているようでした。

iCyP commented 4 years ago

手動でTpose化すれば問題ない、自動Tpose化するとモデルが壊れるというuniVRMのTpose化issueになりませんか?

ローカル軸の保持は利用アプリ上での正規化を要するものとなり規格としての標準化の意味を薄めると思います。

また、アプリからのエクスポートであればアプリ側独自のTpose化実装もできるのではないでしょうか。 (Tpose化された)vrm由来モデルを再度vrmにする際にTpose化すると壊れるのでそのような場合はTpose化を実行しないようにという話もあります。手動(独自コード)でもTposeの仕様に沿っていればVRM出力時に絶対にuniVRMのTpose化を利用しなければならないというものではないと私は考えています。

m-sigepon commented 4 years ago

エクスポート時に独自にTポーズ化を行うことはできるのですが、そもそもモデルのローカル軸を消してしまう仕様が元のモデルの持つローカル軸の破壊的仕様と感じました。 その為、ローカル軸を維持した上で正規化処理した軸情報(回転値を0にするという情報)はVRMの拡張情報として持ってほしいという要望になります。 この仕様ですと、例えばGLTF化した際に元モデルのローカル軸は破壊されることなく他環境に持って行った際にVRMの拡張情報を参照してHumanoid設定を行うことができます。 また、VRMデータをGLTFとして参照する場合もローカル軸が破壊されていないデータを参照することができます。

その為、Humanoidを扱えないような環境で読み込む場合もローカル軸の再設定を行うという処理も不要になります。 現状、UnityのHumanoidは元のFBXのローカル軸を破壊せず維持した状態で持っています。 それと同様の仕様になってほしいです。

iCyP commented 4 years ago

仕様通り正しく厳密にTposeになっていると仮定すれば、各humanoidボーンのローカル軸は固定の値を用いることができます。 なぜなら、Tpose化によってローカル軸情報-回転をジョイント・頂点座標情報にBakeされていると言えるからです。(仕様に明記されていないこと・標準に実装されているTpose化機能が問題ではありますが…) これにより、汎用的にモデルに動きをアタッチできます。 たぶん。(間違っていたらごめんなさい 

モデルにローカル軸情報を持たせることは、正規化(というより仕様準拠化)-Tpose化による上記利便性を失わせることになります。

参考: slideshare - unite-tokyo-20193dvrm の26枚目2項目目,33枚目

m-sigepon commented 4 years ago

モデルにローカル軸情報を持たせることは、正規化(というより仕様準拠化)-Tpose化による上記利便性を失わせることになります。

これは、ローカル軸情報を持つ上で正規化した情報を別に持つ(VRMの拡張として保持する)ことで解決することだと思いますが、その仕様ではダメな問題はあるでしょうか? 例えば、Mayaでは「回転」情報とは別にボーンのローカル軸情報を持つ「ジョイントの方向(ボーンの軸の向き)」というのを保持しています。

そのように、モデルのボーン情報が本来持ってるローカル軸は維持してVRMの拡張情報として正規化した情報を別に持てばいいのではないかと考えます。

iCyP commented 4 years ago

私は以下よりこの仕様は不要だと考えています。

  1. 先にも述べたが、正確に正規化されたモデルはローカル軸を固有する必要はない。#54 により各ボーンのローカル軸をドキュメントに明示・利用するだけで良い。むしろローカル軸の独自所有は動きのアタッチをモデルに最適化する手間が発生する。

  2. この仕様を読むか読まないかはクライアントが決定するということであれば、それはルックの一貫性を失う原因の一つになる。これはVRMのポータビリティという思想に反する。

  3. 個人的にその時点で必要最低限な方が良い(追加は楽、変更・削除は困難なため)。 現問題はTpose化の改善で解決できると感じている。

m-sigepon commented 4 years ago

VRMの利用想定がアバターのみでなく、今後色々な活用法をされるときにオリジナルのデータが持つローカル軸を維持するということはそのオリジナルデータの理想の状態を保証することができます。

例えば、一番問題に感じてるのはボーンの軸の向きに関わらずワールド方向にボーンが向いているという点です。

これは3Dデータとしては、基本的にこのようなデータを作成しません。 理由は、ローカル軸データを持っていないと曲がる方向の情報を失うためGLTFなど対応ソフトで読み込んだ場合、モーションを付けれるような状態ではないためです。

その為に、GLTFとしてはローカル軸方向を保持したモデル製作者が意図した最低限の状態を保持してその上でVRMに最適化されたデータが付加されるというのが理想だと考えているためです。

また、現在Tポーズ化はUnityのアバター生成のTポーズ化に依存しており完全な正規化が行えているわけではなくHumanoid依存の正規化になっているためです。(この点はVRMschema側ではなくUniVRM側で議論する問題だと思いますが) ここでいう完全な正規化というのは、ボーンの向きがワールド方向と一致していることを指します。(↓このように)

例えば、UniVRMで正規化後、背骨が湾曲してるのに対しジョイント方向がワールドの向きを向いているこの状態がおかしい状態です。(完全な正規化を行うなら人体の基礎ボーンの回転値を一度0値にしボーンの向きと軸の向きを一致させた状態が正しい正規化かと思います)

今後Unity以外でのVRMの利用を考えると、Humanoidに依存した正規化処理より元データ構造を保持してその上で、VRMに必要な情報を持たせるというのがエコシステムとして理想と感じます。

以上が、ローカル軸を維持した状態であって欲しい理由となります。

iCyP commented 4 years ago

(モーキャプに最適化された | 一般化されたモーションを持ったアプリに対する)3Dアバターフォーマット、から離れた使い方を使いやすくするべきという話は、VRM-Cの方々の判断すべきところであると私は考えますので、これ以上申し上げることはございません。

ただし、ボーンの向きとギズモが合わない言うのは、VRMとしてはTposeに反しているという問題です。これはuniVRMのTposeを通していればuniVRM、それ以外であればモデル固有の問題であり、ここで議論すべき問題ではないでしょう。Tpose化の問題であればuniVRMのリポジトリへissueを建てるべきです。

o0O(画像大きすぎて読みづらいです…高さタグ等で調節いただけると幸いです...e.g:)

<img height = "128" src=https://user-images.githubusercontent.com/3232308/69937332-d6c9b680-151d-11ea-8f39-ca5ca36a48fd.png>
m-sigepon commented 4 years ago

画像サイズ小さくしておきました。 Tポーズの正規化の件についてはUniVRMの方にissueを立てたいと思います。

m-sigepon commented 4 years ago

UniVRMの方でissueを立てる前に検証を行ったところ、純粋に全身の基本ボーンの回転値を0にしてHumanoidをセットアップしモーションを適用するとキャラの印象が大きく異なってしまうことが分かりました。 (これは、Humanoidに変換したモーションがマッスル値の差分データとして持っているからだと思います)

単純に正規化時に回転を全て0にしてギズモと軸の方向を一致する方法では難しそうでした。

FBXにHumanoidを適用してアバターを生成した場合、元のローカル軸は維持されています。恐らくHumanoidシステムは元の情報を維持してHumanoidシステムをラップ(バインド)する形で実現していると思います。 上記でも書きましたが、VRMが今後モーションキャプチャー環境だけに限らず幅広い使われ方が行われると想定するとローカル軸の維持が必要と思われるので、ベイクして焼き付けてしまうのではなくこのように維持される構造になってほしいです。

iCyP commented 4 years ago

一点確認させていただきたいのですが、その2体に当てたポーズはそれぞれそれ専用に設定したモーションデータでしょうか?それとも同じデータでしょうか?

 公開されているVroidのデフォルトTposeは人間が(普遍的な・見栄えよく)Tposeした時の姿勢をボーン初期姿勢として持っていると認識しています。同じポーズを適応しているのであれば、

という、人間として少し不自然な姿勢(モデリングできないので書籍頼みの知識です))から、キャリブレーション時のようなTposeを取っているときの姿勢への差分をポーズモーションへ適応しないと差異が出るのは当然と思います。ここに、仕様Tposeはモーションデータを作るときに留意すべき初期姿勢状態であるというDocumentationが必要でないか、というissueが考えられます。  ご回答頂けると幸いです。@m-sigepon

m-sigepon commented 4 years ago

一点確認させていただきたいのですが、その2体に当てたポーズはそれぞれそれ専用に設定したモーションデータでしょうか?それとも同じデータでしょうか?

2体に当てたモーションデータは、Humanoidモーション化した同じデータです。

■左側 人体の女性の背骨の湾曲に沿ってボーンが入ってる状態でHumanoidのFoce-Tポーズ化した状態

下記に該当する状態

 公開されているVroidのデフォルトTposeは人間が(普遍的な・見栄えよく)Tposeした時の姿勢をボーン初期姿勢として持っていると認識しています。

■右側 上記データの背骨が湾曲している回転値を0値にし背骨をまっすぐにする処理を事前に行ったデータです、それをFace-Tポーズ化した状態

状態としては、この仕様に準拠した状態です。仰ってる通り自然な姿勢からは逆に曲がる状態ですね。

仕様Tpose 背骨が真っすぐ(自然な姿勢からは逆に曲がっていると言える? 足の骨がY軸(縦)に並行(解剖学的に言えば下に行くほど骨関節-回転軸は後ろに下がるはずでは?

この状態、もう一点問題がありました。 足の回転値が0値にすることにより、膝が伸び切った時にがくがくなる現象が起きました。

という、人間として少し不自然な姿勢(モデリングできないので書籍頼みの知識です))から、キャリブレーション時のようなTposeを取っているときの姿勢への差分をポーズモーションへ適応しないと差異が出るのは当然と思います。

通常はこのように回転値をすべて取り除く正規化を行っても、その背骨も含めた自然な初期ポーズを取るモーションを作成し、Genericで適用した場合はそれらのキーが反映されるのでちゃんた自然なポーズになります。 今回、Humanoidシステムをベースとしてポーズが適用されており。 Humanoidシステムは、初期ポーズからの差分データに変換さるようなのでFace-Tポーズしていた際に人間として背骨が湾曲していても、その状態を維持してモーションが適用されるようです。

ここに、仕様Tposeはモーションデータを作るときに留意すべき初期姿勢状態であるというDocumentationが必要でないか、というissueが考えられます。

現在の仕様が、「背骨が真っすぐ」が仕様となっている場合、上記現象がおきるため「背骨が真っすぐ」ではキャラの印象が上記のように損ねるのでHumanoidでは「人として自然な状態のTポーズ」になっていれば問題ない、逆にそれを真っすぐにするとキャラ性を損ねる問題があるのが分かりました。 それは別issueかもしれません。

iCyP commented 4 years ago

 理解としては、humanoidモーションの適用において、初期姿勢のキーを最初に打っても以降別のモーションを当てると初期姿勢のキーが残らないという問題ですね。 モーションを当てた場合ーアバター以外の使い方をした時に発生する(リターゲティングされたモーキャプデータであれば問題はないのではないかと思います、識者意見求む)、unity HumanoidとVRM1.0仕様のTposeとかみ合っていない問題と見えます。

 また、仕様に合わせてTposeにするとアバターの印象を与えたい姿勢と(モーキャプにせよ手付モーションなどにせよ)アクターの姿勢との差異の吸収させるは解決が難しい問題だと思います。かつ別issueですね。どこにどう提起すべきなのか分からないですが… バーチャルキャストはクライアント側でそれ実装しているように感じる (tweet @virtual_cast)ので、クライアントで解決すべきという思想なのかもしれませんが。どうなの?@vrm-c 氏~識者氏~

p.s. 脚がガクガクするのは汎用IKを真っすぐ繋がったボーンにリグセットアップ・ヒント無し(blenderでいうpole targetのような物)を適応すると、優先的回転軸を見失って、フレーム毎の計算結果に一貫性が失われることによるものでしょう。理屈からいえば脊椎、腕や指でも同じことが起こりえます。VRMクライアントに専用IKが組まれていれば or インポート時にIKセットアップされるよう設定すれば-(人型前提で、デフォルト姿勢が明らかで一意であれば曲がる方向は明確なので、自動セットアップは困難ではないはず、どのみち手間はありますが、ローカル軸はTpose依存固定仕様でもモデル固有仕様でもやることは同じでしょう(見る値が違うだけ))、解決できると思います。

ousttrue commented 4 years ago

VRM的には、T-Poseからローカル軸を得てください。 なので、ローカル軸がグローバル軸と一致するようにT-Poseにしてください。

また、Unityのmecanimはブラックボックスで詳細がよくわからないのでこれを基準に仕様を作ることができませんでした(mecanimがどこからどこまでの機能を指すのかよくわからないところですが・・・)。UnityのHumanoidポーズがmascle値の配列で表現されるところですが、これがリターゲットなども含んでいるようですがブラックボックスで同じ動作を作ることができません。

VRMとUnityHumanoidの共通点は、

あたりで詳細は特に互換性がありません。 またUnityでHumanoidを有効に使うには、AnimatorコンポーネントにHumanoidAvatarを適用して、特定の方法でポーズをつける必要があります。 Transformにrotationを代入するタイプの処理は、Humanoid.Avatarと無関係です。

m-sigepon commented 4 years ago

@ousttrue

なので、ローカル軸がグローバル軸と一致するようにT-Poseにしてください。

これを行ったところ、以下のようになりました。 ローカル軸とグローバル軸を一致するTポーズを行うのはキャラの体形を損なうためその対応では行えません。 これは実際に、このようなデータを手元で作っていただくと分かると思います。

1.左側の状態が現状のセットアップデータ

2.中央が女性らしい形状を維持して垂直にボーンを入れる場合

3.右がVRM的にローカル軸とワールド軸を合わせたいならモデルも垂直にする状態

2.は曲がる位置がモデルに対しておかしいので基本的にこのようなボーンの入れ方はしません 3.今回、正規化処理で全ボーンの回転値を抜いて完全なTポーズとして3の状態を作ってみました。 その結果がこちらになります。 右側が3の状態で、Humanoidでポーズを反映した場合Force-Tポーズを行った状態では自然なTポーズ状態に対してポーズが適用される仕様のためかボーンを棒立ちにしたらポーズも棒立ち状態になってしまいました。

例えば、キャラの体形を女性らしいS字を保ってボーンをワールドとローカル軸が一致する場所に配置したら曲がる基点がおかしいことになります。(実際のモデルの骨を通る位置から外れた位置になったりするでしょう) その為、通常はこのようにキャラの姿勢に対応する位置にボーンを配置します。

ローカル軸とグローバル軸を一致するには寸胴な体形のキャラしか作れないことになっていしまいます。

さらに、Unityでとの話になっていますがVRMとしては今後Unity外での利用も考えられますのでUnity基準で仕様を考えない方が良いかと思います。 その為に、GLTF的には元のオブジェクトが保持しているローカル軸を保持してその上でVRMの正規化を別の情報として持つ処理を行ってほしいです。 FBXをHumanoidでセットアップしても元のローカル軸が消えないように、そのFBXを他の環境に持っていってもオリジナルのローカル軸は非破壊でそれに対する処理を行うことができます。 現状ですが、VRMにした時点でローカル軸がUnityのHumanoidに依存したForce-Tポーズに対してワールド軸に正規化されてしまうのでローカル軸の破壊的処理が入っているのが問題だと感じております。

ousttrue commented 4 years ago

たしかに3軸全部完全にあわせる必要なさそう。 間違っておりました。 1軸はグローバル軸に合わせる必要がありそうです。 どの軸をワールドと合わせるべきかドキュメント化するべく検討します。

ボーンに沿った軸が必要な場合は、以下のようにローカル空間を各ボーンで求めてください。

// spine の例
var y = (tail - head).normalized;
var x = Vector3.right; // ボーンごとにワールドと一致するべき軸が異なる
var z = Vector3.cross(x, y);
// x, y, zが正規直行基底

ローカル空間がボーンに沿ったものになるはずです。 この使い方はVRMでは想定されておらず、今後の課題となります。

0b5vr commented 3 years ago

社内での議論の様子をまとめました:

したがって、ひとまずVRMとしてはHumanoidボーンの回転値について制約を設けない方針に切り替えるのが良いと思いました。

ousttrue commented 3 years ago

既存のプログラムが壊れて互換性無くなるので、それはできません。

0b5vr commented 3 years ago

私は、むしろ変えるなら今しかないと思っています。

あまり良くわかっていないのですが、各ボーン軸をワールド軸に向ける処理というのは、アプリケーション側で実行するのはそんなに難しいのでしょうか? UniVRMで現状できていることなので、その処理をエンドデベロッパーにexposeすれば、アプリケーション側で必要に応じて実行できるというイメージでいたのですが。

0b5vr commented 3 years ago

口頭で議論を行いました。

1.0においては、引き続き各ボーン軸をワールド座標系に合わせる方針で仕様を定義します。

TokageItLab commented 3 years ago

1.0においては

今後定義される可能性はあると言う事でしょうか。上でしげぽんさんが仰ったような S 字湾曲のようなケースに対しては、確かにオフセット値よりボーンのローカル方向の推定は可能です。しかし最初にある指のようなケースに対して、ロール値の推定をオフセット値から行う事は容易ではありません。 Unity の Mecanim はブラックボックスなのではっきりとは分かりませんが、モデルやアニメーションに対して恐らくインポート時にローカル方向の推定を内部的に行っているのではないかと考えられます。

ローカル方向を破棄してしまうと、例えば一つのアニメーションデータを用いて Unity の内外で同様のアニメーションを行うためには Mecanim と似た様な実装を各プラットフォームに強いる事を意味し、 Mecanim はブラックボックスである事により、一貫性が失われてしまいます(※1)。また、 Mecanim を各プラットフォームに実装する事と比較して考えると、上で FMS-Cat さんが書かれていますように、各ボーン軸をワールド軸に向ける処理をアプリケーション側の VRM インポーター等で必要に応じて実装する事の方が遥かに容易ではないでしょうか。

規格としてデータを揃える上で、ユーザーによって乱雑になりやすいデータを破棄するという事は一番簡単であり確実な方法ですが、失う物が大きいという事にも留意して頂きたいと思います。 #176 のようにローカル軸の名前を定めるのであれば、例えば Blender の Fortune アルゴリズムで推定されるようなローカル方向をロール値も含めて VRM の規格として定義し(※2)、推奨とする Humanoid ボーンのローカル方向をガイドラインとして記載し、それに従って貰う前提でローカル方向を保持するというような事も考えられるのではないかと、一つの意見を述べさせて頂きます。


※1: 現状の仕様では必然的にこの選択をとらざるを得ません。とは言え、 Unity で Mecanim を使うな、 Unity と Unreal の Humanoid の挙動を同じにしろ、というような事を言うのも無理があるので仕方がない事だとは思いますが...。

※2: Humanoid に対応するボーンだけでも基準となるローカル方向さえ決めてしまえば、 Mecanim のような実装に頼らずとも、プラットフォーム間でアニメーションの互換性をある程度保つ事が可能ではないでしょうか。アバターとアニメーションは切り離して考えるべき、と言う意見もあるかもしれませんが、アバターを用いてアニメーションやボーン操作を行わないという事は原則あり得ません。ボーンアニメーションのデータには基本的に相対値が用いられますが、アニメーションを作成するアバターと適用するアバターでローカル方向が異なると回転方向が変わってしまうので、ローカル方向の定義が重要になります。

infosia commented 3 years ago

Unity 以外のゲームエンジンでゲームやアニメーション用途での VRM 使用を検討しているのですが、ここまでの議論を拝見すると TokageItLab さんやしげぽんさんの仰る通り今後様々な用途での VRM 利用を考えるとボーンのローカル軸を破棄する仕様には無理があると考えています。破棄するのではなく glTF の拡張情報として正規化に必要となる情報を持たせる案に賛成です。

VRM の思想としてルックの一貫性・ポータビリティを担保したいという意図はわかりますが、情報が破棄されると元に戻せないのが問題だと考えています。 glTF の拡張情報として正規化に必要となる情報を持たせて、VRM の仕様としては正規化されたデータを見てください、という仕様では駄目でしょうか?

TokageItLab commented 3 years ago

私自身、 Godot というゲームエンジンで VRM に対応するかどうかというプロジェクトに関わっておりますが、 #12 でも挙げられているように、現在の仕様ですと Unity の Mecanim から離れてボーンの操作を行う事は困難です。 Blender の VRM Importer (恐らく Fortune での方向推定)(独自の決め打ちベースの方向推定っぽい)を用いたとしても本来のロール値は破棄されており、再編集やアニメーションの作成を行う事が困難である事に変わりはありません。

繰り返しになりますが Mecanim のようなリターゲッティングシステムの利用が前提にあると、ルックの一貫性・ポータビリティという点については Unity を離れた時点で破綻してしまいます。プラットフォーム間の互換性を考えるのであれば、ローカル方向をガイドラインで定める等してローカル軸の維持を行う必要があると強く感じております。


例えば Blender のボーンのローカル方向は進行方向が +Y となり、 VRChat のガイドラインには IK が関係するボーンのロール(ローカル Y 軸の回転)は 0° にするというようなガイドラインがあります。

https://docs.vrchat.com/docs/full-body-tracking

しかし、ロールを全て 0° (もしくは 0° 基準)にすると関節が自然に曲がる回転軸が X と Z で混在するという問題があります。


そこで、回転軸を優先した場合には #176 の参考のようになるかと思います。

https://docs.microsoft.com/en-us/azure/kinect-dk/body-joints

こちらでは全ての関節が自然に曲がる回転軸を Z と定めています(個人的には肩の軸に違和感があります)が、そもそも進行方向が X である事に加え、恐らく回転値の正負を左右で一致するように優先した結果として進行方向の軸の正負が逆転しております。また、ロール値の定義が必須(腰は 0° 、手首は 90° ...etc )となります。


個人的、及び知人のモデラーの観点からすると、どちらかと言えば後者の方が回転軸の役割が決められており理想的なのですが、 3DCG ソフトの制約上、進行方向は +Y にしたい所ではあります(軸に関してはインポータやエクスポータでローカル方向の情報を破壊せずに変換できるはずなのでデータ上は +X でも構いませんが...)。また、左右における回転値の正負の逆転はロール値の 180° 回転(右肘と左肘でロール値が 180° 異なるような形)で対応するのが理想的であると考えます。

アドオンや機能によってローカル方向を初期化する必要があるのであれば、それらを利用するアプリケーションの VRM インポータ側でローカル方向の初期化を行うべきです。また基準の値が定義される事で、例えば VRM 出力時に Humanoid ボーンにおいて基準のローカル方向と 45° 以上異なっている物がないかチェックし、もし存在すれば警告を出して変更を促すという様な実装も可能ではないでしょうか。

以上を踏まえまして、これらのローカル方向の値を数値として規格化・ガイドライン化した上でローカル軸を維持する事で、真の意味でプラットフォームを跨いでルックスを保った標準化が成り立つのでは無いかと具申致します。

infosia commented 3 years ago

本件と関連して #214 を新しい issue として追加しました。メッシュやボーンの情報などソースとなる3Dデータに対する破壊的変更に関連して VRM としてより広い思想の転換が必要かと思い問題提起させていただきました。VRM に必要な情報は VRM の extension として格納すべきだというのが私の意見です。

infosia commented 3 years ago

本件 #214 のような根本解決を望みますが、とりあえず影響範囲が少なそうな折衷案としてはアドホックですが『元の姿勢がどうであったか』という情報だけ追加プロパティとして持たせるというのはとりあえずの対策として(根本解決を何年も待つよりは)考えていいのかもしれません。回転だけバッファに格納すれば追加サイズは1ノードにつき sizeof(float) * 4 とちょっと、基本ノードの構造は VRM 0.x との互換性を保っているので既存プログラムの変更は必要なし、ローカル軸の表現が重要になってくるユースケースや Unity 以外のゲームエンジンで必要な場合だけそこを見ればいい、という感じです。こういう感じでプロパティを追加していくのは無秩序な仕様の肥大化を招きそうでよくない感じがしますが... #214 を待っていると何年もかかりそうなので案として俎上に載せたいと思います。

TokageItLab commented 3 years ago

本件に関しまして私の方でも問題点と解決案をまとめていまして、今月末に開催される VRM 勉強会で発表するように考えていました。

本件はいくつかの issue に跨がる問題であり、また Unity 以外の環境についても考慮・説明する必要があるので、まとめるのに手間取っておりますが、少なくとも一つ言えるのは現状のロール軸の定義に2軸使っているような定義では親指の回転方向を定義する事が明らかに不可能なので Unity 依存を断ち切る上では定義の変更は避けられないという事です。

saturday06 commented 3 years ago

BlenderのVRMアドオンに言及があったので補足です。VRMアドオンは最近のアップデートで、Blender 2.83以降の場合のボーン方向の推定にglTF 2.0アドオンのFortuneを使うようになりました。Blender 2.83未満の場合はFortuneが無いのでこれまで通りオリジナルのロジックを用いて方向推定を行います。Fortune自体も、もともとglTF 2.0アドオンのVRM対応のために導入されたっぽく見えます

lyuma commented 3 years ago

It is correct that the "Fortune algorithm" was designed for VRM. Prior to Fortune, the glTF importer had two options: Blender(+Y) and Temperance. It was suggested that Temperance did not point bones in the correct direction when given a VRM model. That is why the Fortune heuristic was prototyped and eventually committed. For editing VRM models, it is useful.

However... Fortune produces incorrect bone orientation in some cases, because it uses all child bones instead of only human bones. The main problem is that clothing and spring bones can cause the character rig to malfunction: for example, if I add a sleeve to the arm, it will take the average of the bones, and cause the Upper arm to point down, for example. Also, on characters with breast bones, the chest may point forward.

Some human bones may also produce incorrect results. For Hips, it will take the average of left leg, right leg and spine, which can produce an incorrect vector. For wrist, it may point in the wrong direction depending on the thumb positions, or if an extra unused bone exists between wrist and fingers.

Finally, Fortune is not sufficient for use in animation, because it does not select the correct bone roll (for example, to guarantee that X axis of bone matrix faces in a certain direction).

For casual editing in blender, Fortune is helpful. But for animation, you need perfection, not just working 80% of the time Fortune was an attempt to make some VRM files look good in the editor, but it is not correct in all cases and not sufficient for animation.

Ultimately, Fortune is only a heuristic. The problems with fortune can only be addressed with some understanding of the humanoid bones or the VRM format itself, or if the VRM format is changed to preserve the original bone roll and orientation.

Attachments for illustration, imported as .glb on Blender 2.91, using Fortune setting: Example using Miraikomachi by Bandai Namco: image You can see some issues here:

Example using 右近 by キツネツキ: image

TokageItLab commented 3 years ago

恐れながら、ローカル軸の破棄により起こる問題と改善案をまとめさせて頂きました。

https://qiita.com/TokageItLab/items/e5880123a9f508b2769d

改善案についてはあくまで提案なので、完全にこの通りにしろというわけではなく(して頂ければ幸いですが)、そこは議論していく所だと思いますが、記事中のまとめ部分に記述したように、最低限以下の2つは「プラットフォームを越える汎用アバターフォーマット」として必要であると考えます。

関連

54 Humanoid bone の向き?

83 SpringBone の回転方向の制御

118 アニメーションデータについて

176 ローカル軸の定義

emadurandal commented 3 years ago

議論に参加させていただきます。

私もローカル軸の情報は残した方が相互運用性と互換性(現実的な意味でどのソフトでも作り手やユーザーが望む結果になるという意味での)がむしろ高まると思います。 VRMが元々どこまでの用途を想定して作られたのかは私は定かではないのですが、今はモーキャプデータを元にリターゲットでVRMボーンにアニメーションを流し込んで(回転情報を上書きして)動かすだけではなく、プログラム制御で望む動きをさせたい(ローカル軸からの相対値変化で回転させたい)という需要もあり、そうした中でこのような徹底した正規化をされてしまうとそれができなくなってしまうと考えます。

しげぽんさんの以下の指摘については、これはMaya等のボーン自体の姿勢によらずボーンの回転の基準となる座標系をボーンごとに決められる(Mayaのジョイント方向=ローカル方向軸=Local Rotation Axis)DCCツールでなければできないと考えており、

(完全な正規化を行うなら人体の基礎ボーンの回転値を一度0値にしボーンの向きと軸の向きを一致させた状態が正しい正規化かと思います)

例えばMayaを例に取ると、Maya上での操作として各ボーンを平行移動値だけを使って配置しジョイント方向(ローカル方向軸:Local Rotation Axis)をボーンの向きに沿うように調整することですね。

ただし、こうしたMayaなどのDCC独自のローカル方向軸の仕様はglTFレベルではそもそも存在しませんので、glTFレベルではどうなるかというと、親指などの「作り手が意図する斜めの軸」が必要なボーンについては、Mayaのジョイント方向で設定した斜め軸情報がglTFのボーンノードのTransformとして(0, 0, 0, 1)以外のrotation(クォータニオン)値に変換されるか、あるいは(0, 0, 0, 1)に完全統一される場合でもアニメーションキーフレームの回転情報の方がMaya上とは異なる(glTFで正規化されたボーンでもアニメーション結果がMaya上と一致するような)回転情報に修正されてアニメーション情報が出力されるはずです。

それを、今のVRMの正規化仕様(及びUniVRMの正規化実装)では、こうしたさすがにrotationを残さなくてはならないボーンまですべからくrotation=(0, 0, 0, 1)にリセットしてしまうのが問題なのではないでしょうか。 仮に全てのボーンを完全にrotation=(0, 0, 0, 1)にリセットしてしまうのであれば、そのボーンに対するアニメーションを作り手の想定と一致させるため、アニメーションキーフレームの回転情報を本来のローカル軸でのアニメーション結果と一致するように修正することが必要で、それにはやはりローカル軸の情報が必要となります。

現状、プログラム制御でVRMモデルを(モーキャプなどでの回転値の上書き以外の方法で)動かしたい人たちは、VRM Addonなどのボーン方向(ローカル軸)の推定機能を使ってなんとか運用しようとしてますが、これらの推定は作り手がDCCツール上で意図したボーンのローカル軸と完全には一致しません。その結果、「ソフト間で挙動が異なってしまう」「作り手の想定どおりのアニメーション結果にならない」という現実的な相互運用性・互換性の欠如につながってしまう現状があると思います。

また、今後の議論としてはDCCレベルでのローカル軸機能(ボーン姿勢とは別に回転の基準座標をボーンごとに設定できる機能)とglTFレベルでのローカル軸は概念として明確に区別して議論した方が混乱が少ないと思います。

自分の参考ツイート: https://twitter.com/emadurandal_cgj/status/1377396480953122819 Mayaのジョイント方向についての参考リンク1: http://3dcgr2lab.com/2017/11/14/maya-setup-skeleton-rule-direction/ Mayaのジョイント方向についての参考リンク2: https://download.autodesk.com/global/docs/maya2013/ja_jp/index.html?url=files/CSS_Orient_a_joints_local_axes_manually.htm,topicNumber=d30e274617

ghost commented 3 years ago

そうですね。Mayaのジョイント方向は少し特殊なので、私が言い表したいのは回転値がボーンの向きに反してワールド座標に正規化されることを、ローカル軸が破棄されると表現しています。 その為、ここではUnityのトランスフォーム情報要は回転値に対しての話をしています。

分かりやすいのは、この背骨ボーンがボーンの接続方向に対してワールドにリセットされてる状態(その上で接続されている) Unityで表現するなら、トランスフォームが回転値が同様にワールド方向にリセットされる。

例えば、この画像はMetasequoiaでglTFとして読み込んだ状態です。 このような状態になっていると、ポーズの設定などが困難になります。(特に指摘がある指など) glTFをサポートしてる環境では、ボーンの接続に対してその方向が維持されることをローカル軸を保持すると表現しています。

https://github.com/vrm-c/UniVRM/issues/731 ボーン回転バックアップ、ボーン回転復旧機能 VRMの拡張情報としてその情報を保持しておいて、「VRM」としてインポート時に復元するissueが立っていますがその方法ではglTFを単純にインポートする環境では復元することはできません。 そのため、glTFとして最低限の情報として維持してほしいという要望です。

逆にこういった正規化処理を行いたいのであれば、このように元の回転値情報は維持してVRMのインポート時にその処理を行うというのが理想です。

その上で、UnityでFBXをイポートしてHumanoidをセットアップしたときのようにリターゲットシステムが、リグとして設定される。そして、アニメーションとして動作させるのはそのリグである。(これが理想) Unityで言う、Humanoidシステム、MotionBuilderでいうコントロールリグシステム(両者の設計者は同じ) https://area.autodesk.jp/movie/motionbuilder/02-characterize-control-rig.html

そうすれば、VRMインポーターを作る際にその処理を実装するれば正規化処理が行え glTFとしては元の回転値が維持されたデータが読み込むことが可能です。

TokageItLab commented 3 years ago

@emadurandal 整理するために一度「レスト」と「ポーズ」という単語を使わせて下さい。(ポーズの起点がレストです)

Maya については Joint orient = レスト、Transform rotate = ポーズ であり、そして Maya からエクスポートされる glTF 内のジョイントが持つ回転はレストであるという事で合ってますでしょうか? であれば、この issue はそのレストを破棄してしまうことに対する問題提起となっています。(おそらく趣旨は伝わっているかと思います)

また、この issue ではレスト = ローカル軸と呼んでいます。ローカル軸 が local axis rotation だとして、rest rotation と pose rotation のように回転にも種類があるので、個人的には rest という言葉を入れる、もしくは orient と rotate のように明確に単語を分けるなどしたほうが、もし VRM の方で呼称を統一するとしたら分かりやすいのかなと思ったりしてます。

追記:こんな感じで用語の混同が起きている気がします...(間違っていたらすみません)

How to notate rest and pose state blender Godot3 Maya glTF VRM
rest state editbone orientation bone rest rotation joint orient + local rotation axis joint rotation local axis?
pose state posebone rotation bone pose rotation joint transform rotate (undefined) (undefined)
rest + pose state editbone orientation + posebone rotation bone rest rotation + bone pose rotation local axis? joint rotation (animation) bone rotation?
emadurandal commented 3 years ago

@pixiv-sigepon @TokageItLab はい、多分認識は共有できていると思います。

また、この issue ではレスト = ローカル軸と呼んでいます。ローカル軸 が local axis rotation だとして、rest rotation と pose rotation のように回転にも種類があるので、個人的には rest という言葉を入れる、もしくは orient と rotate のように明確に単語を分けるなどしたほうが、もし VRM の方で呼称を統一するとしたら分かりやすいのかなと思ったりしてます。

はい、ここらへん呼び方を区別した方がスムーズにみんなで議論できそうです。MayaやBlender等のDCCに通じている方たちの意見もさらに増えてくると良い議論になりそうな気はしております。

emadurandal commented 3 years ago

vrm-c/UniVRM#731 ボーン回転バックアップ、ボーン回転復旧機能 VRMの拡張情報としてその情報を保持しておいて、「VRM」としてインポート時に復元するissueが立っていますがその方法ではglTFを単純にインポートする環境では復元することはできません。 そのため、glTFとして最低限の情報として維持してほしいという要望です。

逆にこういった正規化処理を行いたいのであれば、このように元の回転値情報は維持してVRMのインポート時にその処理を行うというのが理想です。

もしくは、UnityでFBXをイポートしてHumanoidをセットアップしたときのように元の回転値情報は維持してリターゲットシステムが、リグとして設定される。そして、アニメーションとして動作させるのはそのリグである。(これが理想)

そうすれば、VRMインポーターを作る際にその処理を実装するれば正規化処理が行え glTFとしては元の回転値が維持されたデータが読み込むことが可能です。

@pixiv-sigepon 私もこれが現実解の一つのように思います。

もしくは、 @TokageItLab さんがQiita記事で提案されているように、多くの需要を過不足無く満たす新たな正規化仕様またはガイドラインをVRMとして決めて、VRMの各実装はそれに従ってもらう。という方向性のどちらかが良いと思います。 https://qiita.com/TokageItLab/items/e5880123a9f508b2769d#%E5%90%84%E7%B7%A8%E9%9B%86%E3%82%BD%E3%83%95%E3%83%88%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E6%B1%8E%E7%94%A8%E6%80%A7%E3%82%92%E8%80%83%E6%85%AE%E3%81%97%E3%81%9F%E5%AE%9A%E7%BE%A9%E3%81%AE%E6%8F%90%E6%A1%88

個人的には何かしら方向性(汎用性を犠牲にしない程度の新しい制約)を示してあげた方が迷いがなくなるので、後者までやりきれれば理想と思いますが……。

infosia commented 3 years ago

ボーン回転方向について、おそらく Kinect での使用を意識していると思われる Microsoft Rocketbox アバターでのボーン回転を確認してみました。ご参考まで。

TokageItLabさんの記事の通り、手と足について屈伸方向の回転を行うと、胎児のように縮こまるポーズになります。足が三角座りのようになり手がクロスする方向に動いてより胎児のようなポーズになっているのが特徴かと思います。

モデルはこちらで確認できます Female_Adult_01.fbx

TokageItLab commented 3 years ago

@infosia そちらのモデルで手がクロスするのは A スタンスだからですね、ちなみに肩の屈曲方向に関しては筋収縮(大きく動く側)で統一するのであれば、上側に、いわゆる肩をすくめる時の方向になると考えています。

記事の方には書きませんでしたが、屈伸・捻り・開閉のような3軸で考えるという手法は Unity Humanoid の Muscle 値の方でも用いられているので(単語は異なったりしますが)その辺りの互換性も踏まえて、軸の役割を優先した定義を行うのが適切なのではないかと提案させて頂きました。

また上腕に関して、kinect では T ポーズから上腕を前後へ動かす回転を屈伸とみなしているように見受けられるのですが、恐らくこれは人間工学・解剖学分野からの引用で、解剖学では直立姿勢を基準として、上腕を前後に振る回転を屈曲(flexion)・伸展(extension)と見なしているので、それに対応付けた結果だと思われます。

参考: https://brookbushinstitute.com/article/joint-actions

ただし解剖学の流用が 3DCG 分野の T ポーズが基準となるというケースにおいて最適であるかどうかは分かりません。そこまで拘ることでもありませんが、私個人としては T ポーズから上腕を前後へ動かすよりも、T ポーズから上腕を上下に動かす回転の方がメインの運動を行う回転すなわち筋収縮として適切であると考え、記事に記載したモデルでは(恐らく解剖学的には外転・内転)を屈伸と見なしました。

解剖学の知識が前提にあると部分的に用語の混乱が起こるかもしれませんが、そもそも解剖学とは基準のポーズが異なり、「3DCG 的には T ポーズを起点として複数の回転が混在する動き」を「解剖学では一つの屈伸としている」ので、3DCG と解剖学では「屈伸」という単語は別のものとして考えるべきではないかと考えています。[※1]

とはいえ、既に存在している解剖学に合わせたほうが都合が良い可能性も捨てきれません。その場合、上腕だけでなく肩に関しても解剖学的には前に倒すほうが屈曲となる筈です(有識者意見求む)。回転させても胎児のポーズにはなりませんが、これはこれでロールが肩から肘まで一致するので整っていないこともないと思います。

要は「T ポーズからの筋収縮を屈曲とするか」「解剖学の用語に合わせたものを屈曲とするか」といった所なのですが、もし軸への再定義を行うのであればその辺りの最終的な判断はコンソーシアムの方へお任せします。


※1: ちなみに Unity Humanoid Muscle では上腕の動きに関して解剖学の概念は流用しておらず、Down-Up / Front-Back と定義されています。また複数のボーンで見られる Twist in-out というのは少し解剖学の概念(内旋・外旋)が入ってきているように思えますが、捻りの方向を明白にするという点で有用です。このように全てを解剖学から流用する必要はなく、3DCG にとって便利であるような定義を行うというのが理想的だと考えています。

infosia commented 2 years ago

最近リリースされた Meta Avatars SDK にサンプルとして添付されていた Meta アバターのファイル形式が glTF (圧縮された .glb、独自 extension 含む) だったので、ボーンの構造だけ抽出してみました。 https://github.com/infosia/themachinery-issues/blob/master/0017/0_quest.blend (Blender が必要です)

mixamo などともちょっと違う変わったボーン構成のようですが上腕のボーンなどはローカルのX軸を回転させると屈伸します。上腕の回転は前後(Kinnect と同じ)のようです。

ご参考まで。

0b5vr commented 2 years ago

VRM1.0のリリースに伴って要旨は満たされましたので、本issueはクローズします。

今後、本件に伴って別の問題が発生した際は、別途issueを立ててください。