本記事はVRM1.0におけるコンストレイント設定について、自身がVRM対応モデルの制作をした際に調べたことや気づいたことをまとめたものとなります。
VRM1.0はコンストレイント機能に対応しており、特定のボーンに追従して回転させるといったことが可能です。手首のひねり回転を補完するヘルパーが定番ですね。
これらはUnity上で設定することも出来ますが、Blender側で適切なボーンコンストレイント設定をしておけばVRM formatでの出力時にコンストレイントをそのままエクスポート出来るようになっています。
一方でVRM1.0のコンストレイントにはいくつか制約が設けられており、例えば上腕や太ももなど既存のボーン構造・コンストレイント設定では対応できないケースもありましたので、ここにメモとして残しておきます。
- 使用環境
- Blender: 4.4.3
- VRM Format: 3.7.5
- Unity: 6.1 (6000.1.10f1)
参考資料
VRM1.0の仕様についての解説動画です。VRMを策定しているVRMコンソーシアム様によるもので、コンストレイントについては12分35秒頃に解説、1時間2分20秒頃に実演があります。それ以外にも有益な情報ばかりなのでオススメです。
また、vrm-specificationではVRM1.0に関する仕様と、コンストレイントの設定例としてサンプルモデルが配布されています。こちらのモデルも参考になりました。
コンストレイントの概要
VRM1.0では以下の3つのコンストレイントを利用できます。
- Roll constraint
指定先のボーンの回転を1軸だけコピーします。Blenderでは「回転コピー」を1軸のみ指定した状態に相当。 - Rotation Constraint
指定先のボーンの回転を全てコピーします。Blenderでは「回転コピー」を全ての軸で指定した状態に相当。 - Aim Constraint
ボーンの方向を指定先のボーンに向けさせます。Blenderでは「減衰トラック」に相当。
これらのコンストレイントをどのように実装するかはアプリ側に委ねられており、挙動が統一されている訳ではありません。また使用にあたっていくつかの制約が設けられています。主要なものを以下に挙げます。
- 各ボーンに使用できるコンストレイントは種類問わず1つのみ
- Humanoidボーンや、Humanoidボーンを子孫に持つボーンにはコンストレイントを設定できない
- コンストレイントの参照先はHumanoidボーンでなければならない
- 回転コピーにおいて、値の「反転」は使用できない
Humanoidボーンはアプリ側が制御するためコンストレイントの影響を与えてはならず、またランタイムで処理するためコンストレイントが循環したり連鎖するような構築も出来ないようになっています。
「Humainodボーンが動いたらコンストレイントでヘルパーも動く、それでおしまい」というシンプルな構成が求められるようです。
Blenderでは「サイドバー(Nキー)→VRMタブ→Node Constraint」に各コンストレイントの条件が記載されています。
条件を満たしたコンストレイントはリストに追加されてエクスポート対象になり、Unityにインポートした際にも自動でコンストレイントが割り当てられます。
なお、循環依存関連の制約は満たしていなくてもエクスポート出来ましたが、アプリでの動作が保証されないため避けるのが無難かと思います。
前腕・手首のコンストレイント
ボーンコンストレイントの定番、手のひねりを前腕に一部反映するコンストレイントです。
手のY軸回転をコピーするだけで完結する動きのため、短い手順でVRMに対応できます。ボーンの階層構造は以下の通りです。
- LowerArm
- Hand
- Helper_UpperArm_01 (HandのY軸回転を追従:弱)
- Helper_UpperArm_02 (HandのY軸回転を追従:中)
- Helper_UpperArm_03 (HandのY軸回転を追従:強)
これらのヘルパーボーンに回転コピーを追加し、座標軸をY軸のみに、ミックスを加算に、座標空間を両方ともローカル空間に設定します。あとは各ヘルパーごとに影響値を調整すれば完了です。設定が適切なら「Roll Constraint」のリストにボーン名が追加されます。
また、座標軸を変更すれば膝や肘の回転にも対応可能です。
上腕・太もものコンストレイント
上腕や太ももの付け根側のひねり回転を抑えるコンストレイントです。
私が制作していたモデルでは上腕ボーンの子にヘルパーを追加し、回転コピーの「反転」を使ってひねりを相殺していました。しかしVRMの制約下ではこの方法は使えません。
そこで上腕とヘルパーは同じ階層に配置し、ヘルパーに「XZ軸回転を100%コピー」と「Y軸回転を任意の割合でコピー」を行うコンストレイントを設定します。
ただしこれも「使用できるコンストレイントはボーンにつき1つ」の制約があるため、ヘルパーを2つに分割して親子にすることで対応します。ボーン構造は以下の通り。
- Shoulder
- UpperArm
- LowerArm
- Helper_UpperArm_Aim (UpperArmのXZ軸回転をコピー)
- Helper_UpperArm_Roll (UpperArmのY軸回転をコピー)
- UpperArm
「Helper_UpperArm_Aim」は上腕のXZ軸回転に追従するためのボーンです。
ボーンコンストレイントに「減衰トラック」を追加し、対象ボーンにLowerArmを指定します。これによりLowerArmのヘッド(=UpperArmのテール)を追いかけるようになり、ひねり以外の上腕の回転を再現できます。
Aimヘルパーの子「Helper_UpperArm_Roll」は上腕のY軸回転を任意の割合で追従するボーンです。
前腕のひねりと同じようにY軸のみの「回転コピー」を追加し、お好みで影響度を調整します。これで前腕と同じXZ回転をしつつ、Y軸のみ任意の割合で反映できるようになりました。
なお、サンプルモデルではこの2つのヘルパーにそれぞれウェイトが振られています。
一方で私は元々ヘルパー1本で制作しており、再調整が面倒&ウェイトの種類を増やしたくなかったのでRollヘルパーにのみウェイトを割り当てています。これが正しいかは分かりませんが、今のところ問題なく動作しているように見えます。
おまけ:Blenderの回転コピーでY軸回転が飛ぶ話
以上の手順でコンストレイント設定がVRMに書き出され、Unityでも動作するようになります。
しかし、実際にはBlenderとUnityではコンストレイントの挙動は少し異なり、特にBlenderにおいては意図したものと異なる挙動をする可能性があります。それがこちら。
(クリックで再生できます)
ボーン構造は先ほどの上腕と同じです。これの上腕にあたるボーンをX軸→Y軸の順に回転させると、90度付近でRollヘルパーのY軸回転が弱まり、ある地点で回転が飛ぶのを確認できます。
これは回転コピーの仕様(座標空間やオイラーのXYZの計算順など)に起因するものと思われ、1軸のみの回転コピーはこのような「思ってたんと違う…」な挙動になります。
一応、回転コピーの座標空間を「ワールド空間」、順序を「YXZオイラー角」、ミックスを「置き換え」に設定すればUnityのコンストレイントに近い挙動っぽくなりましたが、部位やポーズによってはかえって破綻することもあり…オイラー君のこと、何も分からん…
まぁUnityのHumanoidでアニメーションさせる分には問題ないですし、そもそも他のアプリで同じことが起きる可能性はあるため、無理に修正するより回転順や角度に注意した方がいいのでしょう。調査中に見つけたBlender Artists Communityの投稿では
「モデルをこんなポーズにすると見栄えが悪い」という質問に対する答えはたいてい「じゃあ、モデルをそんなポーズにしないで」です。
と指摘されています。名言…
以上、VRM1.0フォーマットにおけるコンストレイントの概要と各部のセットアップ方法などでした。
現状はこれで間に合っていますが、今後も情報の更新や追加があれば適宜アップデートしていこうと思います。