チュートリアル / Bifrost for Maya Rigging Challenge~一歩先のリグ・アニメーションに挑戦~
第10回:重心の可視化を行うサポートユニット

  • Maya
  • アニメ
  • キャラクター・リグ
  • ゲーム
  • コラム
  • シミュレーション
  • チュートリアル
  • 上級者
  • 中級者
  • 映画・TV

みなさん、こんにちは。

本コラムではMayaのプラグイン"Bifrost"を使って、リグ、アニメーション、物理シミュレーションなどの観点から作例を紹介していきます。今回はちょっと趣向を変えて、キャラクターなどの姿勢制御は一切行わず、サポートに特化した機能をリグに加えてみたいと思います。Bifrostのデバッグ描画機能を主に使っていきます。

成果物は以下の通りです。

今回の成果物

【環境】
・Windows 11
・Maya 2027
・Bifrost 3.0.0.0

Bifrostの可視化機能

まずは予備知識として、Bifrostのビューポート描画機能について軽く触れておきます。これまでの過去回でも何度も使用してきましたが、Bifrostグラフには点やベクトルなどをビューポート描画する機能が備わっています。terminal(*1)ノードの diagnostic ポートに何らかのジオメトリを接続することで、レンダリング結果に反映させずにビューポート描画のみを行うことができます。scope系のノードでも同じことができますが、内部に terminal を使っているので本質的には同じです。今回はこちらの terminal を活用していきます。

Bifrostの可視化機能

何を可視化するか

タイトルでは「重心を可視化」と書きましたが、重心だけではなくそれに付随する追加情報をいくつか可視化しようと思います。

項目は以下の通りです。

・重心(Center of Mass:CoM):各部位の近似質点より算出。
・重心線:重心から真下に下ろした線。これが支持基底面からはみ出してるか否かの表示も行う。
・支持基底面(Base of Support:BOS):複数の代表点のうち接地しているものによる凸包。
・重心の軌跡:過去数フレーム分の重心を結んだ線。
・重心の速度:過去数フレームの位置との差分ベクトル。
・軌道予測:速度と重力を元に軌道を予測。【※非接地中のみ】

重心(CoM)はキャラクター全体の重心です。支持基底面は地面に接地している点で繋いだ多角形の面です。例えば両足裏をしっかり地面につけて立っている時は、左爪先、左踵、右踵、右爪先で囲まれた四角形がおおよその支持基底面になります。重心をまっすぐ地面まで下ろした時、この点が支持基底面からはみ出しており、かつ静止状態にある場合は『バランスを崩して転倒しそう』という目安になります。(※動作中の場合は、これだけで安定性を判定できるわけではありません。)

左:安定/中央:不安定だが自立/右:他に支えがなければ倒れる
左:安定/中央:不安定だが自立/右:他に支えがなければ倒れる

重心の軌跡は『物理的に無理な動きをしていないか』の指標になります。ある程度重量のあるモノであれば、壁にぶつかるなど極端な外力が加わらない限り、あまり急激な方向転換や停止はせずに滑らかな軌道を描くはずです。また、ジャンプ中などは原則滑らかな放物線を描くはずです。

重心の速度は『この先どっちに向かうと自然か』の指標になります。前述の通り、強い外力が加わらない限り突然方向転換は出来ませんので、次フレーム以降もある程度この矢印の方向に進んだ方が無理のない動きにはなります。

水色のラインが重心の軌跡/緑の矢印が速度ベクトル
水色のラインが重心の軌跡/緑の矢印が速度ベクトル

最後のおまけ機能、軌道予測は『地面から離れた瞬間の位置と速度を元に将来の軌道と落下地点を予測する』機能です。これを正確に守ってアニメーションさせる必要はないですが、例えば“ジャンプの勢いが小さかったわりに長距離を飛びすぎている”などの不自然さを視覚化しやすくなります。

ピンクのラインは将来の予測軌道
ピンクのラインは将来の予測軌道

これらはあくまで可視化のみを行い、自動で姿勢を変更したりキーを改変するようなことはしないコンセプトで進めます。

注)各部位の質量や参考点がだいぶざっくりなので、そこから得られる指標はいずれも近似的なものになります。とはいえ、参考として使うには十分有用な範疇かと思います。

キャラクター全身の重心を求める

まずはキャラクターの重心(CoM)を求めるため、各部位に簡易的な質点を配置します。本来は長さや太さを考慮してできるだけ正確に設定すべきところかと思いますが、セットアップを簡単にするため各ジョイント位置をもとに以下のように配置する方法で進めます。

キャラクターの重心(CoM)を求めるため、各部位に簡易的な質点を配置

各部位の質量は体重から逆算して一括で設定したいので、割合を定義します。『人体 質量比』などでネット検索するといくつか文献が出てきますので参考にさせていただき、今回は以下のように比率を定義したいと思います。

各部位の質量は体重から逆算して一括で設定したいので、割合を定義する

全体の重心 R は、各質点の質量 m とその位置 r を用いて以下のように求められます。ようするに位置の加重平均です。

全体の重心 R は、各質点の質量 m とその位置 r を用いて求める数式

以上をBifrostグラフで組むと以下のようになります。

bifrostGraphShape
bifrostGraphShape
bifrostGraphShape > define_human_mass_point
bifrostGraphShape > define_human_mass_point
bifrostGraphShape > define_human_mass_point > mid_point
bifrostGraphShape > define_human_mass_point > mid_point
bifrostGraphShape > CoM
bifrostGraphShape > CoM
bifrostGraphShape > com_on_ground
bifrostGraphShape > com_on_ground
bifrostGraphShape > com_scope
bifrostGraphShape > com_scope

ではこれを人型のリグと接続してみたいと思いますが、せっかくなので前回登場した Bifrost Rigging のサンプルより「Biped Modules」を少し改変し、簡易的なモデルをスキンバインドしたもの使用してみます。各 joint の worldMatrix を、用意しておいた transform のポートに接続したら、あとは体重を設定するだけです。

Biped Modulesを少し改変し、簡易的なモデルをスキンバインドしたもの
サンプルデータ:step_01_center_of_mass.ma(記事の最後のダウンロードリンクからダウンロードできます。)

これで、キャラクターの全身の重心重心線を可視化することが出来ました!

支持基底面

支持基底面(BoS)とは、体を支えるため地面などに接している点を平面上で囲った領域です。今回は床を水平面に限定し、接地している代表点から凸包を得て近似します。この領域が広いほど、静止姿勢では安定が増します。

支持基底面

まずは地面に接する可能性のある部位に複数の代表点を配置します。地面(水平な平面)から一定距離以内に入った代表点を「接地している」とみなして、支持基底面の構成要素にしてみます

平面上の複数の点を全て囲む凸型の面(=凸包)を得るには、Andrew's Monotone Chain (*2) のアルゴリズムが使えそうです。リンク先に多数のサンプルコードが書いてありますので、Pythonコードを参考にしてBifrostグラフで実装します。while が無いので do_while で代用していますが、基本はそのままです。

*2)Andrew's monotone chain convex hull algorithm:複数の点 (x,y) を x 座標順にソートし、外積で折れ曲がりを判定しながら下側/上側の凸包を順に構成する手法。

bifrostGraphShape
bifrostGraphShape
bifrostGraphShape > random_points
bifrostGraphShape > random_points
bifrostGraphShape > monotone_chain_convex_hull
bifrostGraphShape > monotone_chain_convex_hull
bifrostGraphShape > monotone_chain_convex_hull > lower_iterate
bifrostGraphShape > monotone_chain_convex_hull > lower_iterate
bifrostGraphShape > monotone_chain_convex_hull > lower_iterate > do_while
bifrostGraphShape > monotone_chain_convex_hull > lower_iterate > do_while
bifrostGraphShape > monotone_chain_convex_hull > upper_iterate(※do_while は lower_iterate のものと同じ)
bifrostGraphShape > monotone_chain_convex_hull > upper_iterate(※do_while は lower_iterate のものと同じ)
サンプルデータ:sample/andrews_monotone_chain.ma(記事の最後のダウンロードリンクからダウンロードできます。)
サンプルデータ:sample/andrews_monotone_chain.ma(記事の最後のダウンロードリンクからダウンロードできます。)

さらに、重心の投影点が支持基底面に収まっているかどうかも知りたいので、判定用コンパウンドも用意しておきます。

ある点が凸包に収まっているかは『すべての辺において内側にいるか』を確認すれば判定できます。Convex Hullのコンパウンドから出てきた点の配列はすでにキレイに一周した並び順になっていますので、そのまま do_while で回して外積を確認していきます。

ある点が凸包に収まっているかは「すべての辺において内側にいるか」を確認すれば判定できる
ある点が凸包に収まっているかは「すべての辺において内側にいるか」を確認すれば判定できる
bifrostGraphShape
bifrostGraphShape
bifrostGraphShape > is_point_inside_convex_hull
bifrostGraphShape > is_point_inside_convex_hull
bifrostGraphShape > is_point_inside_convex_hull > do_while
bifrostGraphShape > is_point_inside_convex_hull > do_while
サンプルデータ:sample/is_inside_convex_hull.ma(記事の最後のダウンロードリンクからダウンロードできます。)
サンプルデータ:sample/is_inside_convex_hull.ma(記事の最後のダウンロードリンクからダウンロードできます。)

では、これらのコンパウンドを前項の重心可視化のグラフへ追加し、キャラクターの支持基底面を取得してみます。代表点はひとまず両足裏に4点ずつ、計8点ほど配置してみます。

bifrostGraphShape(黄色の枠線内が追加箇所)
bifrostGraphShape(黄色の枠線内が追加箇所)
bifrostGraphShape > filter_reference_points
bifrostGraphShape > filter_reference_points
bifrostGraphShape > bos_scope
bifrostGraphShape > bos_scope
支持基底面の計算結果
支持基底面の計算結果
サンプルデータ:step_02_base_of_support.ma(記事の最後のダウンロードリンクからダウンロードできます。)

これで、支持基底面(重心線の内外判定付き)が追加で得られました!

重心の軌跡と速度

次は重心の軌跡と速度を描画してみます。軌跡は過去数フレームの重心位置を配列で feedback ポートに保存しておき、 strands を描画しようと思います。重心の速度ベクトルは、表示目的であれば方向だけ分かれば十分なので前のフレームからの位置差分をそのまま使いますが、誤差をならすために過去2〜3フレーム分の平均を取ることにします。

bifrostGraphShape(黄色の枠線内が追加箇所)
bifrostGraphShape(黄色の枠線内が追加箇所)
bifrostGraphShape > trajectory
bifrostGraphShape > trajectory
bifrostGraphShape > trajectory_scope
bifrostGraphShape > trajectory_scope
bifrostGraphShape > vector_scope
bifrostGraphShape > vector_scope

Contents Browserより適当なモーションをインポートして試しにリグを動かしてみます。BifrostRigをHIKからリターゲットする機能は現状ありませんので、簡単に各部位をコンストレイントしている程度です。

サンプルデータ:step_03_trajectory_and_velocity.ma(記事の最後のダウンロードリンクからダウンロードできます。)

サンプルシーンにモーションは含まれておりませんが、BifrostRigをコンストレイントするだけの簡易スクリプト「constraint_hik_bifrostrig.py」を同梱しております。(実行するとcycleCheckの警告が出ますが一応動きます。)

これで、重心が『どのように移動してきたか』『この後どこへ移動しそうか』が可視化されるようになりました!

軌道予測

では最後におまけ要素として、ジャンプなどで打ち上がった際の重心の予測軌道を可視化してみたいと思います。軌道は接地状態から非接地状態へ移行した瞬間に計算し、次に再計算されるまで固定するものとします。

計算に必要な要素はすでにほぼ揃っています。まず、接地・非接地の判定は支持基底面の代表点がひとつでも地面に付いているか否かで判断し、非接地に移行した瞬間(打ち上がった瞬間)の重心位置と速度より、等加速度運動の公式を利用してt秒後の位置を求めます。なお、前項の速度ベクトルはフレーム間の位置差分(cm/frame)として得ているため、初速度 v0 に使う際は Δt で割って単位を cm/s に直します。

p(t) = p0 + v0 * t + 0.5 * g * t^2

・p0: 初期位置(非接地に移行した瞬間の位置ベクトル)
・v0: 初速度(非接地に移行した瞬間の速度ベクトル)
・t: 経過時間(秒)
・g: 重力加速度(Y-upで単位がcmの場合は[0, -980, 0])

また、打ち上がってから次に地面に到達するまでの時間は、上記の式をy成分に限定して地面の高さhを代入し、tについて二次方程式を解く事で得られます。

打ち上がってから次に地面に到達するまでの時間は、上記の式をy成分に限定して地面の高さhを代入し、tについて二次方程式を解く事で得られる
打ち上がってから次に地面に到達するまでの時間は、上記の式をy成分に限定して地面の高さhを代入し、tについて二次方程式を解く事で得られる

あとはt秒後までの各フレームにおける位置をすべて計算し strands を描画すれば未来の軌道が描けます。

以上をグラフに追加します。

bifrostGraphShape(黄色の枠線内が追加箇所)
bifrostGraphShape(黄色の枠線内が追加箇所)
bifrostGraphShape > is_grounded
bifrostGraphShape > is_grounded
bifrostGraphShape > trajectory_prediction
bifrostGraphShape > trajectory_prediction
bifrostGraphShape > trajectory_prediction > calc_ground_time
bifrostGraphShape > trajectory_prediction > calc_ground_time
bifrostGraphShape > trajectory_prediction > calc_trajectory
bifrostGraphShape > trajectory_prediction > calc_trajectory
bifrostGraphShape > trajectory_prediction > calc_trajectory > motion_with_constant_acceleration
bifrostGraphShape > trajectory_prediction > calc_trajectory > motion_with_constant_acceleration
サンプルデータ:step_04_prediction.ma(記事の最後のダウンロードリンクからダウンロードできます。)

空気抵抗などを全く考慮していないので正確さには欠けますが、目安としては十分な気がします!

以上です!

今回は少し趣向を変えて一切ジョイント操作などを行わないサポート特化ツールを作成してみました。ビューポートへの描画機能は仮に標準機能だけで作ろうとすると、メッシュやカーブを複数作成したりマテリアルを専用に持ったりと何かと余分なデータが増えやすいかと思いますし、処理負荷の面でも心配です。対して、Bifrostの描画機能はシーン内をキレイに保ったまま色々な情報を気軽に表示できるので、なかなか便利です。あまり詰め込みすぎると当然負荷はかかりますが、計算量の割には比較的高速なのは嬉しい点かと思います。

また次回をお楽しみに!

まとめ

・ターミナルを使用して様々なビューポートデバッグ描画が可能
・重心は自動ループとsum_arrayを使って重み付き平均として簡単に計算できる
・支持基底面は接地代表点の凸包で近似し、外積で重心投影点の内外を判定
・軌跡はフィードバックポートを活用


製品購入に関するお問い合わせ
オートデスク メディア&エンターテインメント 製品のご購入に関してご連絡を希望される場合は、こちらからお問い合わせください。