チュートリアル / Bifrost for Maya Rigging Challenge~一歩先のリグ・アニメーションに挑戦~
第9回:Bifrost Rigging でカスタムモジュールを作る

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

みなさん、こんにちは。

本コラムではMayaのプラグイン"Bifrost"を使って、リグ、アニメーション、物理シミュレーションなどの観点から作例を紹介していきます。今回は「Bifrost Rigging」で自作のモジュールを作ってみたいと思います。

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

今回の成果物

【環境】
・Windows 11
・Maya 2026.2
・Bifrost 2.15.0.0

※Maya 2026.2 にバンドルされているBifrostのバージョンは2.14.1.0になります。2.15.0.0を使うには下記リンクよりBifrost単体のインストーラーを取得して更新する必要があります。
https://manage.autodesk.com/products/updates

Bifrostリギングモジュールフレームワークとは

Bifrostリギングモジュールフレームワークとは、バージョン2.14より新たに追加されたBifrost駆動のモジュラーリギングシステムです。プロシージャルかつモジュールが特徴で拡張性、再利用性の高いシステムとなっているとのことです。Maya Learning Channelにて非常に分かりやすい動画が全7本公開されていますので、まずはこちらに目を通しておいていただけるとよりスムーズに進められるかと思います。特にPart3はカスタムモジュールを作成する手順が1本にまとまっており非常に重要です。本記事はこの動画シリーズと公式ヘルプをベースにしている部分が多々あります。

Featured - Bifrost Rigging - YouTube
Maya ヘルプ | Bifrost リギング モジュール フレームワーク

リギングモジュールフレームワークの概要

リギングモジュールフレームワークの概要

まずはBifrostのリギングモジュールが従来のMaya標準ノードのみを使ったリグとどのように置き換わるのか各工程で比較してみます。以下の図は『骨を配置してメッシュをバインドし、コントローラを作成したら何らかのギミックを介して骨を制御』という工程を簡単に示したものです。

従来のMayaリグとBifrostリグの比較図

赤線で囲ったバインド以外の部分がBifrostグラフのモジュールでプロシージャル(非破壊的)に構築されることになります。スキンバインドはBifrostの外側にあるため破壊的ですが、skinClusterのbindPreMatrixというアトリビュートを利用することで初期ポーズが変更可能な状態にできます。これについては後半で詳しく触れていきます。

第1回『両端を固定し長さが保てるベルトのリグ』おさらい

今回はリギングモジュールのお試しということで、第1回で作成した「両端を固定し長さが保てるリグ」をモジュールに転用してみたいと思います。

まずは第1回の要素をおさらいします。

・複数の点(第1回の時は7点)に距離の制約をかける
・両端の2点は固定、中間の点はフリーに
・複数の制約を満たすよう反復計算を行う
・各点の位置を元に回転値を計算

最終的なグラフは以下のようになっています。これは第1回の配布データdistance_constraint_rig.ma」のグラフです。

第1回の配布データのbifrostGraphShape
bifrostGraphShape(第1回の配布データより)

グラフの入力は、各コントローラのworldMatrix、各ジョイントの初期位置、反復回数。出力は、各ジョイントの位置と回転になっています。点の数は7点固定です。まずはリギングモジュールに入る前に、このグラフ全体を、"ジョイント数が可変"かつ"入出力がMatrix配列(array<Math::double4x4>)"となるよう改変していきます。double型にする理由はリギングモジュールの設計に適合しやすく都合が良いからです。

まず元のグラフのiterate内部を見てみます。7つの位置とその間の距離を受け取り、距離制約6つの計算を終えた後、両端を除く5点について平均位置を計算しています。同じ計算を複数並べていて少々無駄なので、配列で可変長にできるよう組みなおします。

第1回の配布データのbifrostGraphShape内のiterateコンパウンド
bifrostGraphShape > iterate(第1回の配布データより)

ここから先は組み直したグラフです。姿勢を収束させるための全体の反復計算(calc_position_iterate)の中にさらに位置配列を端から順に処理するiterateを作ります。各点は2つの距離制約により一度2つの位置データに分かれるので、保管用の変数(position_buffer_1, position_buffer_2)に格納しておき、その後まとめてaverage_positionコンパウンドを通して平均位置をとることにします。

改変後のbifrostGraphShape
bifrostGraphShape(改変後)
bifrostGraphShape内のcalc_position_iterateコンパウンド
bifrostGraphShape > calc_position_iterate
calc_position_iterate内のiterateコンパウンド
bifrostGraphShape > calc_position_iterate > iterate
iterate内のdistance_constraintコンパウンド
bifrostGraphShape > calc_position_iterate > iterate > distance_constraint
distance_constraint内のdistance_constraint_one_sideコンパウンド
bifrostGraphShape > calc_position_iterate > iterate > distance_constraint_one_side
calc_position_iterate内のaverage_positionコンパウンド
bifrostGraphShape > calc_position_iterate > average_position

位置の計算が終わった後、点の位置とコントローラを入力としてエイムによって回転値を求める部分についても同様に、配列で対応できるように組み直します。

bifrostGraphShape内のcalc_rotationsコンパウンド
bifrostGraphShape > calc_rotations
calc_rotations内のaimコンパウンド
bifrostGraphShape > calc_rotations > aim

最後に、全体を「strap」という名前のコンパウンドでまとめます。入出力が配列になり、スッキリまとまりました!

strapコンパウンドを含むbifrostGraphShape
bifrostGraphShape(※strapの入力ポートの型はdouble4x4やdouble3にしてあります)
bifrostGraphShape内のstrapコンパウンド
bifrostGraphShape > strap

動作結果も問題なく第1回と同じになっていそうです!

距離制約リグの動作デモアニメーション
サンプルデータ:distance_constraint_rig_v2.ma(記事の最後のダウンロードリンクからダウンロードできます。)

ここまではまだグラフを整理しただけで、リギングモジュールは一切関係のない状態です。次項よりカスタムモジュール化していこうと思います。

カスタムモジュールを組んでみる

前項と同じシーン(distance_constraint_rig_v2.ma)のまま作業を続行します。まずは新しいBifrostGraphにて「template_module」を作成し、右クリック > Make Editable で編集可能な状態にします。複数用意されているモジュールのうち template_module はグラフを改変してカスタムモジュールを自作するための雛形になっています。

template_moduleの作成画面
新しいbifrostGraphShapeにて、template_moduleを作成

template_module の入出力ポートをどこかへ接続する前に、デフォルトのPin(*1)を設定しておきます。制御点の数は可変にする予定ですが、ひとまず初期値として7点(point0~6)のPinと、反復回数などを操作するオプションコントローラ(ui)用のPinを用意しておきます。Parameter EditorよりInputs > Setup > Pins の [+] ボタンを押して、Name や Pivot Matrix を入力していきます。

*1) Pin:コントローラやジョイントの初期姿勢を定義するためのガイドトランスフォームです。Pinを始点にリグの生成からアニメーションまでがプロシージャルに構築されることになります。

Pin追加前のParameter Editor画面
Pin追加前
PinにNameとPivot Matrixを入力した状態のParameter Editor
Pinを3つ追加しNameとPivot Matrixを入力したところ

Pinは下記のようにvnnコマンドを使って効率よく設定することもできます。

# bifrostGraphShape2 の template_module へ pinを追加するサンプル
from maya import cmds

pin_mtx = []

# ui
pin_mtx.append(f'ui, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1')

# point x 7
for i in range(7):
    t = [0, (i+1)*5, 0]
    pin_mtx.append(f'point{i}, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, {t[0]}, {t[1]}, {t[2]}, 1')

inputs_value = '{{' + ', '.join(pin_mtx) + '}, , {}, {}, {}, {}, {}, {}, , 0, 0}'
cmds.vnnNode(
    'bifrostGraphShape2',
    '/template_module',
    setPortDefaultValues=["inputs", inputs_value]
)
サンプルデータ:scripts\set_pins.py(記事の最後のダウンロードリンクからダウンロードできます。)

Pinsの初期値入力ができたら、root_moduleを追加作成して下記のように繋ぎます。これでinputsとoutputsがMaya側に公開され、BifrostRigをビルドする準備が整いました。

template_moduleとroot_moduleを接続した状態のbifrostGraphShape

一度Mayaビューポートに戻り、RiggingメニューバーのBifrost Rigging > Create Rig From Modulesオプションを開いたら、以下のように Synced Container にチェックを入れ、Setup Methodは native でリグを作成してみます。

Create Rig From Modulesのオプション設定画面
Create Rig From Modules オプション

うまくいけばbifrostRigというノードが作られ、その子階層にpinsやcontrolsなどの構成要素が生成されると思います。ただし、コントローラやジョイントはrootモジュールのぶんしか作られていません。今はまだtemplate_moduleの中身が空っぽだからです。これから、template_moduleのグラフ内にコントローラなどの定義を追加していきます。

モジュールから生成されたbifrostRigの階層構造
bifrostGraphのモジュールより生成されたリグ

template_moduleの内部を見るとすでに多くのグラフが組まれていますが、編集すべきところは下記の2箇所の赤い部分だけです。左側のUser Setupはコントローラやジョイントの階層を作成し初期状態を定義する領域、右側のUser Animationはリグのギミックを作成しトランスフォームを更新する領域になります。これ以外のコンパウンドは特に見る必要はありません。

template_module内部のUser SetupとUser Animationの領域

コントローラとジョイントの定義

ではまずは左側の user_setup コンパウンドの内部で、コントローラとジョイントを定義していきます。いったん最小構成として、グラフは以下のようになりました。ここでやっていることは、『PinのMatrixと親のコントローラやジョイントを取得し、それらの情報を使ってこのモジュールに必要なコントローラとジョイントを複数作成する』ところまでです。uiコントローラには “iteration” アトリビュートも追加してあります。

template_module内のuser_setupコンパウンド
bifrostGraphShape > template_module > user_setup
user_setup内のfor_eachコンパウンド
bifrostGraphShape > template_module > user_setup > for_each
user_setup内のiterateコンパウンド
bifrostGraphShape > template_module > user_setup > iterate

ここまで組めたところで一度ビューポートへ戻ってみると、グラフ内で定義したコントローラとジョイント階層がすでにMayaのノードとして作られていることがわかります。これは先ほどリグを作成する際に Synced Container オプションによりルートノードがbifrostRiggingContainerになるよう設定していたためです。このコンテナのAuto Update(*2) が有効になっているとモジュール内の変更が自動的に反映され、リグが再構築されるようになります。

*2) Auto Update:グラフ内でモジュールを改変する時にのみ有効にすべきオプションです。コントローラを操作する際には無効にする必要があります。

生成されたコントローラとジョイントの階層構造

一度 Auto Update をオフにし、pins階層下のロケーターを動かすと、各コントローラやジョイントの初期位置を変更できます。コントローラも操作可能な状態になっていますが、現状はuser_setupにてコントローラとジョイントをそれぞれ作成しただけですので、操作したところでジョイントはまだ動きません。

pinとコントローラを操作している様子のアニメーション
pinとコントローラの操作(※Auto Updateはオフ)

リグのギミックを定義

ではここから、右側の赤色領域にある user_animation コンパウンドの内部でリグのギミック本体を定義していきます。グラフは以下のようになりました。こちらでやっていることは、『コントローラやジョイントのtransformやアトリビュートを取得し、strapコンパウンドによりジョイントの姿勢を更新する』ところまでです。前項で第1回のグラフを改造して作った“strapコンパウンド”がここで登場しています。

template_module内のuser_animationコンパウンド
bifrostGraphShape > template_module > user_animation

再度Mayaのビューポートへ戻ってみます。bifrostRigのAuto Updateを有効にしてリグの再構築を促し、その後すぐ無効にしてコントローラを動かしてみます。今度はジョイントが動くはずです。

コントローラ操作でジョイントが動く様子のアニメーション
user_animationによりコントローラの操作でジョイントが動く

この時点で動作的な問題はないのですが、strapコンパウンド内のエイムによってジョイントの初期回転値を変えてしまっているので、これが後々問題になります。user_animation内で以下のように2箇所にtransform_scopeを接続してみると、ジョイントの初期位置であるpivot_matrixと、strapコンパウンドを出た直後のトランスフォームがズレていることがわかります。

transform_scopeを追加したuser_animation
user_animation内でtransform_scopeを追加
pivot_matrixとstrap出力matrixのズレを示す図
ワイヤー型の軸がpivot_matrix、矢印型の軸がstrapの出力matrix。ズレが出ている。

この対策として、一度user_setupに戻りコントローラやジョイントを定義するMatrix配列に手を加えます。PinのMatrix配列をそのまま使うのではなく、strap内部のエイム処理と同じものを一度適用して回転を補正した後のMatrix配列を使うよう変更します。

adjust_rotationを追加したuser_setup
bifrostGraphShape > template_module > user_setup(※adjust_rotationが追加分)
user_setup内のadjust_rotationコンパウンド
bifrostGraphShape > template_module > user_setup > adjust_rotation

これでジョイントの初期姿勢(pivot_matrix)がブレなくなりました!

pivot_matrixとstrap出力matrixが一致している状態

さて、ここまででモジュールの機能としては概ね完成となります。次は生成されたBifrostRigでメッシュをスキンバインドしてみます。

スキンバインド

第1回のベルトのリグをBifrostRigに置き換えてみます。元のリグデータでは下記のように、メッシュ階層、ジョイント階層、リグ階層、そしてbifrostGraph1という構成でした。これらのうちメッシュ階層以外の部分を丸ごとBifrostRigに置き換えていきます。

元のリグデータの階層構造

ジョイント階層を削除するとskinClusterが消えてウェイト情報を失ってしまいますので、事前にエクスポートをしておきます。既存のバインドジョイントの名前をBifrostRigのジョイント名 template_0_jnt ~ template_6_jnt に合わせてリネームした後、茶色いベルト部分に入っているスキンウェイトを Deform > Export Weights で出力します。両端の金具についてはインフルエンスが1つしかないのでウェイト出力は不要です。

次に、Auto Update がオフになっていることを確認し(*3)、templateモジュールの各pinを元リグのジョイントへひとつずつ Match Transform で位置合わせしていきます。

*3) モジュール内部を編集する際はオンにしておくと便利ですが、モジュールを“使う”フェーズでは必ずオフにしておく必要があります。自動的に再構築が走ると、位置がリセットされてしまったり、せっかく入れたskinClusterが消えたりするためです。

pinをMatch Transformで位置合わせしている様子

ここまで終えたらもう元のリグは必要ありません。ジョイント階層、リグ階層、bifrostGraph1を全て消してしまいます。改めて、BifrostRigのジョイントで3つのメッシュをバインドし、茶色のベルトについては先ほどエクスポートしておいたウェイトを復元します。スキンを復元した結果以下のようになりました!BifrostRigで元のリグと同じものが再現できています!

いったんこれで動きはしますが、アニメーションが追加された後であっても何も壊さずにジョイントの初期ポーズを変更出来るよう、さらに手を加えたいと思います。

具体的には、BifrostRigにより生成されたジョイントのpivotInverseMatrix (*4) を各skinCluster のbindPreMatrixに接続します。pivotMatrix はコントローラで姿勢を更新する前のジョイントの初期トランスフォームが記録されています。pivotInverseMatrix はその逆行列です。skinCluster の bindPreMatrix は初期姿勢の逆行列を接続することでバインドポーズを可変にできます。ここでskinClusterにPivot Inverse Matrix を接続するために、前項で軸ズレを修正しておきました。

*4)Bifrost ヘルプ | トランスフォーム モデル | Autodesk:BifrostのTransformモデルについて詳しくはこちらをご確認ください。

pivotInverseMatrixをskinClusterのbindPreMatrixに接続している図
pivotInverseMatrix -> bindPreMatrix 接続後

接続は手作業で行っても良いですが、以下のスクリプトを使用するとskinClusterに繋がっているすべてのインフルエンスをbindPreMatrixに追加接続することができます。

from maya import cmds


def get_skin_cluster(shape: str, *args):
    his = cmds.listHistory(shape, pdo=True) or []
    skin_clusters = cmds.ls(his, type='skinCluster') or []
    if not skin_clusters:
        return
    return skin_clusters[0]


def connect_bind_pre_matrix(sc: str, mtx_attr: str='pivotInverseMatrix', *args):
    matrix_attr_list = cmds.listAttr(f'{sc}.matrix', m=True)
    for matrix_attr in matrix_attr_list:
        bind_pre_attr = matrix_attr.replace('matrix', 'bindPreMatrix')
        inf = cmds.listConnections(f'{sc}.{matrix_attr}')[0]
        cmds.connectAttr(f'{inf}.{mtx_attr}', f'{sc}.{bind_pre_attr}', f=True)
        print(f'Connect bindPreMatrix ({sc}) : {inf}.{mtx_attr} -> {sc}.{bind_pre_attr}')


# 選択したすべてのメッシュのskinClusterにおいて、bindPreMatrixの接続を行います。
if __name__ == '__main__':
    for o in cmds.ls(sl=True):
        shapes = cmds.listRelatives(o, s=True, f=True) or []
        sc = get_skin_cluster(shapes[0])
        connect_bind_pre_matrix(sc)
サンプルデータ:scripts\connect_bind_pre_matrix.py(記事の最後のダウンロードリンクからダウンロードできます。)

接続を終えたら、Pinを動かしてもメッシュが変形しなくなりました!コントローラにアニメーションを追加した後にPinを動かしても破損がないことが確認できます。

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

ちなみに、ジョイントの初期姿勢が可変になったらbindPoseノードは特に意味がありませんので削除してしまって問題ありません。(残しておいても動作上の問題はありません。)

Pinを動かしてもメッシュが変形しない様子

パブリッシュして他のモジュールと組み合わせてみる

では最後に、このカスタムモジュールをパブリッシュして再利用可能にしてみます。まずはモジュールを使う時に調整できるようにしておきたいポートを、モジュールの最上位に取り出します。どのポートを取り出すかは、既存のモジュール(arm、variable_fkなど)を参考にしつつ最低限に抑えてみます。グラフは以下のようになりました。黄色い枠線内が更新部分です。コントローラシェイプ、エイム軸、親の検索情報などを接続しています。

パブリッシュ前のbifrostGraphShape(黄色い枠線内が更新部分)
bifrostGraphShape(※Nameを"strap"に変えてあります)
パブリッシュ前のtemplate_module
bifrostGraphShape > template_module
パブリッシュ前のuser_setup(黄色い枠線内が更新部分)
bifrostGraphShape > template_module > user_setup
パブリッシュ前のfor_each(黄色い枠線内が更新部分)
bifrostGraphShape > template_module > user_setup > for_each
パブリッシュ前のuser_animation(黄色い枠線内が更新部分)
bifrostGraphShape > template_module > user_animation
パブリッシュ前のstrapコンパウンド(黄色い枠線内が更新部分)
bifrostGraphShape > template_module > user_animation > strap

パブリッシュ直前のデータはサンプルデータ『create_strap_module_02.ma』になります。記事の最後のダウンロードリンクからダウンロードできます。

ここまで出来たらtemplateモジュールのコンパウンドを右クリック > Publish "template_module" …より、外部ファイルに出力します。名前は「strap_module」にしておきます。

Publishダイアログ画面

これで、Node Library やTabキーからstrapモジュールが再利用できるようになりました!

Node Libraryにstrap_moduleが表示されている画面

最後に、strap_moduleを別のモジュールと組み合わせる例を簡単に紹介して終わりにしようと思います。2.15のBifrost Browserに「Biped Modules」という二足歩行型リグのサンプルグラフが公開されていますので、まずはこちらを新規シーンにインポートします。インポートされるのはグラフだけですので、BifrostRigをビルドします。

biped_modulesをインポートしリグを作成した状態
biped_modules をダブルクリックしてシーンにインポートし「Create Rig From Modules」を実行した状態

このリグの腰あたりにチェーンが繋がっているイメージで、strapモジュールを追加してみます。グラフは以下のようになりました。

spineのik_baseを親にstrapモジュールを追加したグラフ
spineのik_baseを親に、strapモジュールを追加
strapのpinを腰回りに配置した様子
strapのpinを腰回りに配置
サンプルデータ:add_strap_to_biped.ma(記事の最後のダウンロードリンクからダウンロードできます。)

サンプルデータadd_strap_to_biped.maを正常に開くには、同じくサンプルデータのCompounds\strap_module.jsonを C:\Users\<ユーザー名>\Autodesk\Bifrost\Compounds に配置しておく必要があります。

以上です!

今回はBifrostのあらたなフレームワーク「リギングモジュール」に触れてみました。Maya標準では今までモジュラーリグシステムは付属していなかったので、このシステムは大きな進歩に繋がる気がしています。まだリリース直後でモジュールの数は少ないですが、今後のバージョンアップで拡充されていけば様々なタイプのリグに対応できるようになるかと思います。仮にカスタムモジュールを共有するコミュニティが活発になれば、さらに加速的に広がるかもしれません。この辺は今後どうなるか分かりませんが期待したいところです。

モジュールをカスタムするにはまずモジュールの構造を把握する必要がありますが、すべてのグラフを隅々まで理解する必要は無いことが分かりました。また、リグのロジックそのものは今まで通りの組み方をほぼそのまま活かせることも分かりました。本記事は入門にしては少々重めの内容になってしまったかもしれませんが、既存モジュールのグラフをただただ眺めるより一度カスタムモジュールを作ってみたほうが理解が早く進むと思います!是非試してみてください。

また次回をお楽しみに!

まとめ

・Bifrost Riggingはプロシージャルなモジュラーリンギングシステム!
・モジュールの内部すべてを理解する必要は無し!赤いところだけ拡張すればOK
・リグのロジックそのものは今までの組み方を流用できる


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