2025/05/29
ロボットのヒンジ関節をaimConstraintで再現する

こんにちは。
BACKBONEの谷です。
今回は、ロボットのヒンジ関節の挙動を再現する手法をご紹介します。
ヒンジ関節とは、開き戸や眼鏡のつるのように、特定の軸を中心に一方向にのみ回転する関節のことを指します。
ロボットの肩や肘など、特定の関節部分でこのような動きが必要とされる場面があります。
この記事では、aimConstraint を使用してロボットアームのリグを組む方法を解説します。
◆はじめに
ヒンジ関節の動きというのは、具体的には次のような挙動を指します。
※下記の動画では、「FKコントローラ」と「IKコントローラ」を設定しています。
肩周りに配置された3つのパーツ(赤パーツ、青パーツ、緑パーツ)の動きに注目してください。
これらのパーツは、それぞれ以下のような回転挙動を示しています。
※説明の都合上、オイラー角を用いて記述しています。
- 赤パーツ : RotateYの1軸で回転
- 青パーツ : RotateY、RotateZの2軸で回転
- 緑パーツ : RotateX、RotateY、RotateZの3軸で回転
さらに、コントローラに3軸すべての回転値を入力して動かしてみた場合でも、それぞれのパーツがヒンジ関節としての挙動を保っていることが確認できます。
このような動きを再現するには、各回転を1軸ずつに分解して制御する必要があります。
思考プロセス
今回用意したモデルに対して、人型と同様の骨階層を作成していきます。
作成するのは、次の4つのジョイントです。
※ジョイントの用途を明確にするために、名前に「jt」を付けて表記します(以下、「jt階層」と呼びます)。
- shoulder_jt_L
- upArm_jt_L
- foreArm_jt_L
- wrist_jt_L
次に、上腕から手首にかけて、FKとIKのコントローラを設定します。
※FK/IK のコントローラの具体的な設定方法については、ここでは割愛します。
全体の情報の流れは、下図のようになります。
jt階層を使ってモデルをバインドし、上腕を動かしてみると、以下のような挙動になります。
赤・青・緑の各パーツがすべて3軸で自由に回転しており、本来それぞれのパーツに必要なヒンジ回転の挙動が再現されていません。
ヒンジ回転を正しく再現するためには、各パーツの位置に対応する骨を追加する必要があります。
ただし、jt階層に直接骨を追加してしまうと、後のコントローラ設定時に支障が出るため、バインド専用の階層を新たに作成し、そこにヒンジ用の骨を追加します。
モデルのスキニング(バインド)は、このバインド用階層を使って行うように変更します。
まず、jt階層の各ジョイントを複製し、「jt」を「if」に置き換えてリネームします。
※骨の用途を明確に区別するために、この新しい階層を「if階層」と呼ぶことにします。
- shoulder_jt_L → shoulder_if_L
- upArm_jt_L → upArm_if_L
- foreArm_jt_L → foreArm_if_L
- wrist_jt_L → wrist_if_L
さらに、ヒンジ回転を表現するために、以下の2つのジョイントを追加で作成します。
- shoulder_if_L → shoulderA_if_Lに変更。
- upArm_if_L → upArmA_if_Lに変更。
- shoulderB_if_L → 赤パーツの起点に配置し、shoulderA_if_Lと同じ軸方向で作成。
- upArmB_if_L → 緑パーツの起点に配置し、upArmA_if_Lと同じ軸方向で作成。
jt階層とif階層では骨の数が異なりますが、異なる骨の情報の受け渡し方法については後述します。
現時点での全体の情報の流れは、以下の図の通りです。
この状態で、if階層を使ってモデルをバインドします。
まだjt階層とif階層は接続していないため、まずはif階層の骨を直接動かして挙動を確認します。
各パーツごとに設定した骨を、該当するヒンジ回転軸に沿って動かすよう調整すれば、ヒンジ回転の挙動が再現できそうです。それぞれのパーツが持つべきヒンジ回転の軸は以下の通りです。
- 赤パーツ : 上腕のRotateY
- 青パーツ : 上腕のRotateZ
- 緑パーツ : 上腕のRotateX
これら3つのパーツに対して、それぞれ必要な1軸のヒンジ回転のみを抽出して動かす仕組みが、ヒンジ回転の再現には欠かせません。本記事では、このヒンジ回転の再現手法について詳しくご紹介します。
◆aimConstraintのupVector設定による挙動
赤パーツの動きを例に、ヒンジ回転の仕組みを解説します。
赤パーツに必要な回転は、上腕の前後方向の回転(上腕の RotateY)のみです。
この特定軸の回転を抽出するために、aimConstraint の upVector を活用します。
まずは動作確認のために、簡易的なセットアップで解説を進めます。
以下のようなジョイントを用意します。
- src_jt
→ 上腕の基点となるジョイント(upArmA_if_Lに該当します )。 - src_jtEnd
→ 上腕の末端ジョイント。 - trg_jt
→ 赤パーツに対応するジョイント(shoulderB_if_Lに該当します)。
→ src_jtの位置からtranslateX = -5の位置に配置します。 - aim_loc
→ trg_jtがエイムするターゲット。
→ src_jtと同じ位置に配置します。 - upVec_loc
→ upVectorの方向を決めるターゲット。
→ src_jtEndの位置に配置し、src_jtにペアレントします。
このセットアップにより、ヒンジ的にtrg_jtを回転させる準備が整います。
aim_locをターゲット、upVec_locをupVectorに指定して、trg_jtにaimConstraintを設定します。
src_jtを回転してみると、以下のような挙動になります。
src_jtを回転させた際に、trg_jtが前後方向の回転(RotateY)のみに反応し、横方向やひねり方向の回転には反応しないことが確認できます。これは、回転の影響が以下のように分解されて伝わる構造になっているためです。
- src_jtを前後方向に回転
→ upVec_locも前後方向に移動する
→ trg_jtは前後方向に回転する - src_jtを横方向に回転
→ upVec_locも横方向に移動する
→ trg_jtは回転しない - src_jtをひねり方向に回転
→ upVec_locもひねり回転する
→ trg_jtは回転しない
このように、特定軸の回転のみを抽出して伝えることができるため、ヒンジ回転の再現が可能になります。
この仕組みを利用して、今後は実際のヒンジ関節部分に設定を追加していきましょう。
◆aimConstraintのupVectorの設定方法
角度を分解するための骨階層を作成する
前述のヒンジ回転の仕組みは、直接if階層に設定するのではなく、別途用意した骨階層であるdrv階層に設定を行います。そして、drv階層の回転情報をif階層へ渡すという構造を構築します。
※骨の用途を明確にするため、本記事ではこの階層を「drv階層」と呼ぶことにします。
まず、if階層を複製し、角度の分解が必要なジョイントのみを残します。
今回の設定で必要なジョイントは以下の3つです。
・upArmA_if_L
・upArmB_if_L
これらのジョイントを複製し、名前の「if」を「drv」に置き換えてリネームします。
・upArmA_if_L → upArmA_drv_L
・upArmB_if_L → upArmB_drv_L
階層構造はif階層と同様に構成します。
また、shoulderB_drv_Lの親ノードとして、shoulderA_if_Lと同じ空間情報(ワールド空間の位置・回転)を持つshoulderB_drvGrp_Lを作成します。
aimConstraintのupVectorについて
次に、aimConstraintのオプション設定について確認します。
Mayaのメニューから Constrain > Aim を選択し、オプションボックスを開きます。
この中のWorld Up Typeを“Object Up”に設定することで、World Up Objectの項目が有効になります。
また、ここに任意のオブジェクトを指定することで、Up Vectorの方向をそのオブジェクトに向けて制御することができます。この設定により、回転軸の安定性が向上し、特定方向へのヒンジ回転をより正確に抽出できるようになります。
ここまでの内容を踏まえて、drv階層にaimConstraintを設定していきます。
aimConstraintの設定
赤パーツの骨(shoulderB_drv_L)にaimConstraintを設定します。
【①:ターゲット用Locatorの設定】
赤パーツの骨のAim vectorとして固定する軸は+X軸、Up vectorとして固定する軸は-Y軸になります。
Aim vector用のLocator(shoulderB_trg_L)と、upVector用のLocator(shoulderB_upVector_L)を作成します。
→ upArmA_drv_Lと同じ位置に作成します。
→ shoulderB_drvGrp_Lにペアレントします。
・shoulderB_upVector_L
→ foreArm_if_Lと同じ位置に作成します。
→ upArm_jt_Lにペアレントします。※注意 if階層ではなくjt階層です。
【②:aimConstraintの設定】
shoulderB_drv_LにaimConstraintを作成する前に、あらかじめオプション設定を確認・調整しておきます。
- Aim Vector:(1.0, 0.0, 0.0)
→ ジョイントのローカル +X 軸をターゲット方向に向けます。 - Up Vector:(0.0, -1.0, 0.0)
→ ローカル -Y 軸を基準として回転方向の安定を確保します。 - World Up Type:Object up
- World Up Object:shoulderB_upVector_L
→ このオブジェクトの方向を Up Vector の参照に使用します。
設定が完了したら、コンストレイン対象のジョイントであるshoulderB_drv_Lを選択し、続けてターゲットのshoulderB_trg_Lを選択して、aimConstraintを実行します。upArmA_drv_LとupArmB_drv_Lに関しても、同様の考え方で設定してみてください。
必要な要素を接続する
ヒンジ挙動の再現が確認できたので、ここからはjt階層・drv階層・if階層の各階層同士の接続をおこなっていきます。接続のルールは以下の通りです。
- drv階層のジョイントが存在する場合
→ drv階層のジョイントと、対応するif階層のジョイントのRotateを接続します。
→ または、orientConstraintを使用しても問題ありません。 - drv階層のジョイントが存在しない場合
→ jt階層のジョイントと、対応するif階層のジョイントのRotateを接続します。
→ こちらも、必要に応じて orientConstraintの使用で構いません。
このように各階層の役割を明確に分けて接続することで、jt階層からの入力を、drv階層で必要な回転成分だけを抽出・調整し、if階層を経由してモデルに正しく反映させることができます。
◆まとめ
今回は、aimConstraintを用いて回転を1軸ずつ分解する手法をご紹介しました。
この方法以外にも、工夫次第で同様のヒンジ挙動を再現することは可能です。
ご興味があれば、ぜひ他の手法にもチャレンジしてみてください。
ではまた。
※免責事項※
本記事内で公開している全ての情報について、その完全性、正確性、適用性、有用性等いかなる保証も行っておりません。
これらの情報のご利用により、何らかの不都合や損害が発生したとしても、当社は何らの責任を負うものではありません。
自己責任でご使用ください。